Featured image of post kamailio pipelimit模块

kamailio pipelimit模块

背景

pipelimit 用于限制sip请求, 定义了管道(pipe)概念,可用来表示来自用户的SIP请求流(INVITE or REGISTER)。

脱胎于ratelimit, 可以在数据库中自定义pipe限制,专注于流量整形,没有队列功能。依赖数据库, 官方文档:pipelimit

支持的算法有:

  • Tail Drop Algorithm(TAILDROP)

    这是一个简单的算法, 和定时器一起使用,但是和长时间间隔的定时器使用有风险。 当定时器开始之前,会清除计数。定时器开始后,每次请求计数增加,达到限制之后,pl_check()返回false

  • Random Early Detection Algorithm(RED)

    随机早期检测算法,这是默认算法. 通过测量平均负载并动态调整丢弃率来规避TAILDROP算法带来的同步问题。

    使用此算法时, kamailio会每第n个包向路由引擎返回错误, 试图把上一个时间间隔的负载均匀分布到当前时间间隔。 负面影响是:有可能会丢信息即便是未达到时间间隔. 出现这种现象请减少时间间隔。

  • Network Algorithm(NETWORK)

    依赖网口提供的信息,每时间间隔内检测网口上等待消耗的字节数,如果数据超过限制,pl_check()返回false

  • Feedback Algorithm(FEEDBACK)

    使用PID控制模式,根据cpu负载系数动态调整下降率, 以便负载系数保持在指定值附近。 由于读取cpu负载开销较大, 因此每隔定时时间才读一次,反馈值也会在这段时间间隔内重新计算。

本次测试的kamailio版本:

version: kamailio 5.8.5 (x86_64/linux)

参数解析

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# hash_table大小, slots:2^hash_size, hash_size最大10,默认为6
modparam("pipelimit", "hash_size", 10)
# 数据库连接
modparam("pipelimit", "db_url", "DBURL")
# pipe数据表名,默认:pl_pipes
modparam("pipelimit", "plp_table_name", "pl_pipes")
# 定时器时间,单位秒,默认10
modparam("pipelimit", "timer_interval", 5)
# 控制使用哪种定时器, 0:使用主程快速定时器, 1:使用辅助轮式定时器, 默认:0
modparam("pipelimit", "timer_mode", 1)
# 控制是否获取cpu和流量负载,0:不获取,1: 定时获取. 默认:1 
modparam("pipelimit", "load_fetch", 0)
# 当达到限制时,返回错误值,默认: 503
modparam("pipelimit", "reply_code", 505)
# 错误原因,默认: Server Unavailable
modparam("pipelimit", "reply_reason", "Limiting")
# 到达多长时间间,是否清除未使用的pipes, 默认:0(不清理)
modparam("pipelimit", "clean_unused", 10)

重要函数

pl_check(name [, algorithm, limit])

检查当前name的pipe请求,可以用在ANY_ROUTE,参数:

  • name: pipe名称
  • algorithm: 算法名称, 可以为: TAILDROP,RED,NETWORK,FEEDBACK
  • limit: 限制值,默认: 0(不限制)

返回值:

  • -2: pipe没找到
  • -1: pipe达到限制
  • 1: pipe有限制但是没达到
  • 2: pipe有NOP算法

pl_active(name)

检查name的pipe是否创建了, 1: pipe被发现; -1: pipe没发现;可以用在ANY_ROUTE

pl_drop([ [min ], max ])

对于当前的请求,达到限制后503- Server Unavailable已发送返回.

如果没设置参数, 这个reply不带Retry-After

如果设置max, 那么带Retry-After:max

如果设置了minmax, 那么带Retry-After:x, xminmax之间的随机值.

实战

pl_pipes数据表

pl_pipes的表结构为:

pl_pipes

  • pipeid: pipe的唯一id
  • algorithm: 算法可以为: NOP,RED, TAILDROP, FEEDBACK, NETWORK
  • plimit: 每秒限制数

配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
loadmodule "pipelimit.so"
modparam("pipelimit", "hash_size", 10)
modparam("pipelimit", "db_url", DBURL)
modparam("pipelimit", "timer_interval", 5)
modparam("pipelimit", "timer_mode", 0)
modparam("pipelimit", "reply_code", 505)
modparam("pipelimit", "reply_reason", "Limiting")


request_route {
    ...
    if (is_method("INVITE")) {
                $var(check_result) = pl_check("one");
                switch($var(check_result)) {
                case -2:
                        xlog("L_ALERT","pl_check(\"$var(p)\") drop -pipe NOT found\n");
                        pl_drop();
                        exit;
                        break;
                case -1:
                        xlog("L_ALERT","pl_check(\"$var(p)\") drop\n");
                        pl_drop("5");
                        exit;
                        break;
                case 1:
                        xlog("L_INFO", "pl_check(\"$var(p)\") pass\n");
                        break;
                case 2:
                        xlog("L_ALERT","pl_check(\"$var(p)\") pass -NOP algorithm\n");
                        break;
                default:
                        xlog("L_ERR","pl_check(\"$var(p)\") dropping with unexpected retcode=$var(check_result)\n");
                        pl_drop();
                        exit;
                }
        }
    ...
}

数据表pl_pipes新增数据: insert into pl_pipes(pipeid, algorithm, plimit) values('one', 'TAILDROP', 2);

pipeid即是pl_check的参数name

测试

使用sipp分别做uacuas, 并发请求,得到的日志为:

1
2
3
4
5
6
7
8
9(5257) INFO: <script>: ------172.16.4.113:5666|172.16.4.111:5461|udp|INVITE
 9(5257) INFO: <script>: pl_check("0") pass
10(5258) INFO: <script>: ------172.16.4.113:5666|172.16.4.111:5461|udp|INVITE
10(5258) INFO: <script>: pl_check("0") pass
14(5262) INFO: <script>: ------172.16.4.113:5666|172.16.4.111:5461|udp|INVITE
14(5262) ALERT: <script>: pl_check("0") drop
 9(5257) INFO: <script>: ------172.16.4.113:5666|172.16.4.111:5461|udp|INVITE
 9(5257) ALERT: <script>: pl_check("0") drop

我们配的是2个请求限制/5s,当请求大于2时, 可以看到日志有报错,并且剩下的请求返回505

sip

因为我们配了pl_drop("5"),所以头带了Retry-After:5

总结

pipelimit模块和上章介绍的pike功能大体相似,都能限制请求并发数, 但是pipelimit的功能相对较丰富。

pipelimit可设置算法,限制的pipe,可自定义返回的错误码和错误原因。

pike只能通过ip来限制,也没有算法选择,限制之后的返回需要用户自己设置。

本博客已稳定运行
发表了45篇文章 · 总计78.36k字
本站总访问量 次 · 您是本站第 位访问者
粤ICP备2025368587号-1| 使用 Hugo 构建
主题 StackJimmy 设计