在 Kamailio 中缓存数据库查询结果

数据库查询是一项成本相对较高的操作。虽然在很多情况下绝对有必要这样做,但反复访问数据库以获取相同的信息却是一种糟糕的模式。在 Kamailio(至少对我来说)中,一个相当普遍的做法是将数据库结果存储到一个有效时间相当短(比如 15 至 30 秒)的 hashtable 中,以避免重复查询。我会使用 sqlops 模块的 sql_xquery 函数查询数据库,返回一个 XAVP,然后使用 pv 函数 xavp_params_implode 将 XAVP 序列化,再将其存储到 htable 中,最后使用 xavp_params_explode 将其分解为 XAVP 进行处理。通常看起来是这样的:

. . .
modparam("htable", "htable", "did=>size=6;autoexpire=15;")
. . .


request_route {
    . . .
    route(GET_DID_DATA);
    ## Check $xavp(did_data=>did). If it's an empty string, it's an unknown
    ## number 
    if ( $xavp(did_data=>did) == "" ) {
        xwarn("$rU is an unknown DID\n");
        . . . 
    }
    . . .
}


route[GET_DID_DATA] {
    ## Use of $vn not $var so the default value is $null. Also note that
    ## this is copied first so that the hash can't expire while working
    ## with the data.

    $vn(did_serial) = $sht(did=>$rU);

    if ( $vn(did_serial) != $null ) {
        xinfo("Cache hit for DID [$rU]: [$sht(did=>$rU)]\n");
        xavp_params_explode("$vn(did_serial)", "did_data");
        return;
    }

    xinfo("Cache miss for DID [$rU]\n");
    route(QUERY_DID_DB);
}


route[QUERY_DID_DB] {
    $var(query) = "SELECT * "
                + "FROM dids "
                + "WHERE did = " + $(rU{sql.val.str});

    xdbg("Excuting DB query [$var(query)]\n");
    $var(sql_rc) = sql_xquery("db", "$var(query)", "did_data");

    if ( $var(sql_rc) == -1 ) {
        ## -1 is an error with the query - not an empty row.
        xerr("Error in [$var(query)]. Reply '503 Server Error' and exit\n");
        send_reply("503", "Server Error");
        exit;
    }

    if ( $var(sql_rc) == 2 ) {
        ## 2 means no rows returned. Use an empty string to cache this.
        xinfo("No data found for query [$var(query)]\n");

        ## Lots of potential ways to handle this - we'll set the looked up
        ## column as an empty string in the xavp:
        $xavp(did_data=>did) = "";
    }

    xavp_params_implode("did_data", "$sht(did=>$rU)");
    xinfo("Serialized query result: [$sht(did=>$rU)]\n");
}

这种用例很常见,即如果我们发送失败,就会立即收到同一号码的另一个 INVITE,所以为什么要做两次相同的查找。另一方面,我们不需要为处理的每个不同 DID 号码长时间保留缓存结果。15 秒的 htable 配置将这一需求保持在较小范围内,而 6 的大小提供了 64 个用于存储号码的唯一插槽,以每秒约 20 次的速度看来是合理的–我们每个插槽会有一条以上的记录,但可能不会超过几条。

查询返回的列可以通过 $xavp(did_data=>column_name)访问。最常见的变化是如何处理空结果。不过,缓存总是很重要的,所以即使我们想在结果集为空时发送 404 Not Found 这样的信息,也最好在从 route[GET_DID_DATA] 返回结果后再发送。

我将在今后的文章中讨论最近遇到的一个问题,数据库中的数据类型是 BIGINT。

完整代码示例

github 上的完整代码示例:https://github.com/whosgonna/kamailio_db_caching

原文:https://kaufmania.wordpress.com/2023/12/03/caching-db-query-results-in-kamailio/

本文来自作者投稿,版权归原作者所有。如需转载,请注明出处:https://www.nxrte.com/jishu/38821.html

(0)

相关推荐

发表回复

登录后才能评论