mod_dptools:呼叫限制功能
概述
该功能用于限制与某一资源相关的呼入/呼出呼叫数量,可实现对任意资源的呼叫量管控。
当呼叫数量达到设定上限时,系统会自动将呼叫转接到当前拨号方案上下文内的limit_exceeded分机,或指定上下文的对应分机。
注意
- 呼叫限制的生效范围仅限于当前拨号方案上下文。若将一条呼入呼叫从
public拨号方案转接到default拨号方案的分机,此前在public拨号方案中设置的所有呼叫限制会被重置。- 若限制对象为被叫号码,即便在同一上下文内将呼叫转接到其他分机,该限制的计数也会相应减少。
- 若通过
REFER方法转接呼叫(例如按下话机上的转移按钮),限制的计数不会减少。
拨号方案应用
呼叫限制相关的拨号方案应用由mod_dptools模块实现。
1. limit(基础限制功能)
语法
limit <backend> <realm> <resource> <max[/interval]> [<transfer_destination_number> [<dialplan> [<context>]]参数说明
| 参数 | 描述 |
|---|---|
| backend | 指定使用的后端存储类型 |
| realm | 自定义的域名称(用于区分不同限制分组) |
| resource | 需要限制呼叫数量的目标资源 |
| max[/interval] | -max:允许的最大并发呼叫数,或呼叫速率(单位:次/秒)。若未设置或设为负值,该功能仅作为计数器使用,不限制呼叫- interval:时间间隔,仅支持hash和hiredis后端 |
| transfer_destination_number | (可选)呼叫超限后转接的目标分机号。若不指定,默认转接至当前拨号方案和上下文的limit_exceeded分机 |
| dialplan | (可选)目标分机所属的拨号方案 |
| context | (可选)目标分机所属的上下文 |
补充说明
- 通过
REFER方法转接呼叫时,限制计数不会减少;- 若限制对象为被叫号码,同一上下文内转接至其他分机时,限制计数会减少。
2. limit_execute(条件执行应用)
仅当目标资源未达到呼叫上限时,才执行指定的拨号方案应用。
语法
limit_execute <backend> <realm> <resource> <max[/interval]> <application> [application arguments]参数说明
| 参数 | 描述 |
|---|---|
| backend | 指定使用的后端存储类型 |
| realm | 自定义的域名称 |
| resource | 需要限制应用执行次数的目标资源 |
| max[/interval] | -max:允许的最大并发执行次数,或执行速率(单位:次/秒)。设为负值表示无限制(仅作计数);设为0表示禁止任何并发执行- interval:时间间隔 |
| application | 需要执行的拨号方案应用名称 |
| application arguments | (可选)待执行应用的参数 |
补充说明
- 通过
REFER方法转接呼叫时,限制计数不会减少;- 若限制对象为被叫号码,同一上下文内转接至其他分机时,限制计数会减少。
API接口
呼叫限制相关的API接口由mod_commands模块实现,也可在拨号方案中通过如下方式调用:
<action application="set" data="api_result=${limit_usage(<backend> <realm> <id>)}"/>1. limit_reset(重置限制计数)
重置指定后端的呼叫限制计数。
- DB后端:删除该主机名下的所有计数记录;
- Hiredis后端:暂未实现。如需重置资源计数,执行命令:
hiredis_raw set <resource_name> 0; - Hash后端:暂未实现。
语法
limit_reset <backend>2. limit_status(查询后端状态)
查询指定后端的当前状态,仅支持DB后端,不支持Hash和Hiredis后端。
语法
limit_status <backend>3. limit_usage(查询资源用量)
查询指定资源的当前呼叫用量,支持所有后端。
语法
limit_usage <backend> <realm> <id>补充说明
- 通过
REFER方法转接呼叫时,限制计数不会减少;- 若限制对象为被叫号码,同一上下文内转接至其他分机时,限制计数会减少。
4. uuid_limit_release(手动释放计数)
通过删除指定UUID对应的“用量”记录,手动将呼叫计数减1。
- 若指定了
realm和resource,仅释放该资源的对应计数; - 若未指定,释放该UUID占用的所有资源计数。
语法
uuid_limit_release <uuid> <backend> [realm] [resource]5. limit_interval_reset(手动重置间隔计数器)
在下一个时间间隔开始前,手动将间隔计数器重置为0,仅支持Hash后端,不支持DB和Hiredis后端。
语法
limit_interval_reset <backend> <realm> <resource>6. hash_remote(跨服务器Hash数据访问)
通过该API可访问其他FreeSWITCH服务器上的Hash数据,底层基于事件套接字(Event Socket)实现。需在配置文件conf/autoload_configs/hash.conf.xml中配置目标服务器的名称和认证信息。
该API会每隔5秒向所有远程Hash节点查询完整的Hash列表,并将查询结果合并到本地服务器的Hash计数中。
语法
hash_remote <list>|<kill> [name]|<rescan>通道变量
1. 由limit功能设置的变量
调用limit功能后,系统会自动设置以下通道变量,这些变量会在呼叫挂断时用于删除对应的计数记录(删除操作会根据UUID、主机名、域和资源ID进行限定):
limit_realm:当前限制的域名称limit_id:当前限制的资源IDlimit_max:当前设置的最大呼叫上限
2. 影响limit功能的变量
| 变量 | 取值 | 作用 |
|---|---|---|
| limit_ignore_transfer | true | 呼叫转接时,不重置当前呼叫计数。适用于网关呼入呼叫转接至分机,但需保留原呼叫计数的场景 |
| limit_ignore_transfer | false | (默认)呼叫转接时,对应域和资源ID的呼叫计数会自动减少 |
补充说明
- 通过
REFER方法转接呼叫时,无论该变量取值如何,限制计数都不会减少;- 若限制对象为被叫号码,同一上下文内转接至其他分机时,限制计数会减少。
后端存储类型
1. db(数据库后端)
基于mod_db模块实现,支持多服务器共享呼叫计数,可跨所有参与服务器统计某一资源的实时呼叫数。
2. hash(内存哈希表后端)
基于mod_hash模块实现,使用哈希表作为数据存储结构,速度更快,并支持额外的限流特性。
核心应用语法:
<action application="limit" data="hash <realm> <id> [<max>[/<interval>] [number [dialplan [context]]]" />- 速率限制:通过指定
interval参数实现,例如5/1表示限制该资源每秒最多处理5次呼叫; - 超限处理:若呼叫超限,可转接至指定分机;也可在分机号前加
!,表示直接以对应原因码挂断呼叫,例如:<action application="limit" data="hash inbound 15142223333 2 !USER_BUSY" /> - 仅计数不限制:若未指定
max参数,该功能仅统计活跃呼叫数,不限制呼叫上限。
3. hiredis(Redis后端)
基于mod_hiredis模块实现,使用Redis数据库作为后端存储。
4. 后端存储类型对比
| 后端类型 | 速度 | 数据持久化 | 集群支持 | 时间间隔支持 |
|---|---|---|---|---|
| Hash | 最快 | 否 | 需结合hash_remote | 是 |
| DB | 较慢 | 是 | 可实现 | 否 |
| Hiredis | 快 | 是(可配置) | 是 | 是 |
配置示例
1. 限制单个应用的访问次数
场景:限制向外部运营商发起呼叫的并发数,示例为最多同时向2个运营商各发起5路呼叫。
<extensionname="outbound"><conditionfield="destination_number"expression="^1?[2-9]\d{2}[2-9]\d{6}$"><actionapplication="limit_execute"data="hash outbound carrier1 5 bridge sofia/gateway/carrier1/${destination_number}"/><actionapplication="limit_execute"data="hash outbound carrier2 5 bridge sofia/gateway/carrier2/${destination_number}"/></condition></extension>2. 限制用户并发呼叫数
场景:限制域内单个用户同时只能发起1路呼叫,超限后播放提示音并挂断。
<extensionname="limit_exceeded"><conditionfield="destination_number"expression="^limit_exceeded$"><actionapplication="playback"data="/sounds/overthelimit.wav"/><actionapplication="hangup"/></condition></extension><extensionname="limit"continue="true"><condition><!-- 可在directory.conf中为每个用户单独配置max_calls变量,移除下方行 --><actionapplication="set"data="max_calls=1"inline="true"/><actionapplication="limit"data="db $${domain} ${sip_auth_username} ${max_calls}"/></condition></extension>注意:
limit_exceeded分机需配置在limit分机之前,因为limit()函数会调用transfer(),而转接操作会从拨号方案开头开始匹配分机,避免出现转接循环。
3. 呼叫速率限制(防垃圾呼叫)
- 按源IP+被叫号码限制每秒呼叫数:
<actionapplication="limit"data="hash ${sip_received_ip} ${destination_number} ${calls_per_second}/1"/> - 限制每10分钟最多5路呼叫:
<actionapplication="limit"data="hash ${sip_received_ip} ${destination_number} 5/600"/>
4. 基于计数器的用户忙状态判断
场景:根据外部计数器判断用户状态,若计数器值超过60则返回“用户忙”,否则正常呼叫。
<actionapplication="bridge"data="${cond(${limit_usage(db time_spent in_bed)} <= 60 ? error/user_busy : user/$1)}"/>注意
- 该操作不会增加限制计数器的数值;
- 在新版本中,需先调用
limit功能为该资源设置计数规则(即使设为-1表示无限制),才能让该函数返回非零值。
5. 网关/用户级别的B腿呼叫限制
场景:对呼出呼叫的B腿(网关侧)设置并发限制,需通过环回通道(loopback)实现。
主拨号方案配置:
<actionapplication="set"data="destnum=${destination_number}"/><actionapplication="bridge"data="loopback/context/gw1,loopback/context/gw2"/>对应上下文配置:
<extensionname="gw1"><conditionfield="destination_number"expression="gw1"><actionapplication="limit"data="db outgoing gw1 10"/><actionapplication="bridge"data="sofia/gateway/gw1/${destnum}"/></condition></extension><extensionname="gw2"><conditionfield="destination_number"expression="gw2"><actionapplication="limit"data="db outgoing gw2 5"/><actionapplication="bridge"data="sofia/gateway/gw2/${destnum}"/></condition></extension>原理:若第一个网关达到并发上限,系统会先清理该网关的计数记录,再尝试下一个网关。若直接在同一分机中连续配置
limit和bridge,计数记录需等到A腿回到CS_ROUTING状态才会清理,会导致已尝试的网关持续占用通道资源。
6. 呼出网关的故障转移与限制
场景:配置3个呼出网关,实现故障自动转移,并为每个网关设置并发上限(适配美国10位号码)。
<extensionname="Outbound calls"><conditionfield="destination_number"expression="^(\d{10})$"break="on-true"><actionapplication="set"data="continue_on_fail=true"/><actionapplication="set"data="hangup_after_bridge=true"/><actionapplication="enum"data="1$1 e164.arpa"/><actionapplication="bridge"data="${enum_auto_route}"/><actionapplication="enum"data="1$1 e164.org"/><actionapplication="bridge"data="${enum_auto_route}"/><actionapplication="enum"data="1$1 nrenum.net"/><actionapplication="bridge"data="${enum_auto_route}"/><actionapplication="set"data="auto_hunt=true"/><actionapplication="limit"data="$${domain} gw_PROVIDER1 PROVIDER1_CHANNEL_LIMIT usdirect2"/><actionapplication="bridge"data="sofia/gateway/PROVIDER1/1$1"/><actionapplication="transfer"data="usdirect2"/></condition></extension><extensionname="usdirect2"><conditionfield="destination_number"expression="^usdirect2$"/><conditionfield="rdnis"expression="^(\d{10}$)"><actionapplication="limit"data="db $${domain} gw_PROVIDER2 PROVIDER2_CHANNEL_LIMIT usdirect3"/><actionapplication="bridge"data="sofia/gateway/PROVIDER2/1$1"/><actionapplication="transfer"data="usdirect3"/></condition></extension><extensionname="usdirect3"><conditionfield="destination_number"expression="^usdirect3$"/><conditionfield="rdnis"expression="^(\d{10}$)"><actionapplication="limit"data="db $${domain} gw_PROVIDER3 PROVIDER3_CHANNEL_LIMIT"/><actionapplication="bridge"data="sofia/gateway/PROVIDER3/1$1"/></condition></extension><extensionname="limit_exceeded"><conditionfield="destination_number"expression="^limit_exceeded$"><actionapplication="playback"data="/sounds/overthelimit.wav"/><actionapplication="hangup"/></condition></extension>关键配置说明
auto_hunt=true:允许直接跳转到指定分机,无需遍历整个拨号方案;- 替换
PROVIDER1..3为实际网关名称,PROVIDER1..3_CHANNEL_LIMIT为网关并发上限;- 在
bridge后配置transfer,实现网关故障自动转移。
7. 监控网关IP的并发呼叫数
命令行查询方式
- 监控呼入网关(IP:1.2.3.4)的并发呼叫数:
fs_cli -x'limit_usage db inbound 1.2.3.4' - 监控呼出网关(IP:5.6.7.8)的并发呼叫数:
fs_cli -x'limit_usage db outbound 5.6.7.8'
拨号方案配置示例
<extensionname="customer_a"><conditionfield="network_addr"expression="^1\.2\.3\.4$"/><conditionfield="destination_number"expression="^(.*)$"><actionapplication="limit"data="db inbound 1.2.3.4 10000"/><actionapplication="limit_execute"data="db outbound 5.6.7.8 10000 bridge sofia/gateway/5.6.7.8/$1"/></condition></extension>8. 限制本地分机的呼出呼叫
步骤1:在conf/dialplan/default.xml的Local_Extension分机后添加以下配置:
<actionapplication="limit"data="hash ${domain} $1 1 handle_over_limit XML over_limit_actions"/>步骤2:在conf/dialplan/目录下新建limits.xml文件,添加超限处理逻辑:
<include><contextname="over_limit_actions"><extensionname="oops, too many calls for this one"><conditionfield="destination_number"expression="handle_over_limit"><actionapplication="answer"/><actionapplication="playback"data="ivr/ivr-no_no_no.wav"/><actionapplication="playback"data="ivr/ivr-no_no_no.wav"/><actionapplication="playback"data="ivr/ivr-no_no_no.wav"/><actionapplication="hangup"data="USER_BUSY"/></condition></extension></context></include>扩展配置:若需将单用户并发上限改为4路,修改
limit参数即可:<actionapplication="limit"data="hash ${domain} $1 4 handle_over_limit XML over_limit_actions"/>
进阶配置:仅限制用户拨打7位及以上号码的并发数,拨打4位内部分机不限制:
<extensionname="set outbound limit"continue="true"><conditionfield="destination_number"expression="^1?\d{7}"break="on-false"/><conditionfield="caller_id_number"expression="^(10[01][0-9])"><actionapplication="limit"data="hash ${domain} $1 4 handle_over_limit XML over_limit_actions"/><actionapplication="log"data="INFO Added limit for caller $1"/></condition></extension>9. 防资费欺诈配置
(1)限制国内呼叫
限制同时发起4路国内呼叫,且每日最多发起250路国内呼叫,超限后返回“临时故障”。
<extensionname="domestic.VoiceNetwork.ca"><conditionfield="${toll_allow}"expression="domestic"/><conditionfield="destination_number"expression="^(\d{11})$"><actionapplication="set"data="effective_caller_id_number=${outbound_caller_id_number}"/><actionapplication="set"data="effective_caller_id_name=${outbound_caller_id_name}"/><!-- 限制最大并发呼叫数:4路 --><actionapplication="limit"data="hash fraud_protection calls_max 4 !NORMAL_TEMPORARY_FAILURE"/><!-- 限制每日最大呼叫数:250路(86400秒=1天) --><actionapplication="limit"data="hash fraud_protection call_per_day 250/86400 !NORMAL_TEMPORARY_FAILURE"/><actionapplication="bridge"data="sofia/gateway/VoiceNetwork/$1"/></condition></extension>(2)限制国际呼叫
限制同时发起1路国际呼叫、每日最多10路国际呼叫,且单路呼叫最长时长为30分钟。
<extensionname="international.VoiceNetwork.ca"><conditionfield="${toll_allow}"expression="international"/><conditionfield="destination_number"expression="^(011\d+)$"><actionapplication="set"data="effective_caller_id_number=${outbound_caller_id_number}"/><actionapplication="set"data="effective_caller_id_name=${outbound_caller_id_name}"/><!-- 限制单路呼叫最长时长:30分钟(1800秒) --><actionapplication="sched_hangup"data="+1800 alloted_timeout"/><!-- 限制最大并发呼叫数:1路 --><actionapplication="limit"data="hash fraud_protection calls_max_intl 1 !NORMAL_TEMPORARY_FAILURE"/><!-- 限制每日最大呼叫数:10路 --><actionapplication="limit"data="hash fraud_protection call_per_day_intl 10/86400 !NORMAL_TEMPORARY_FAILURE"/><actionapplication="bridge"data="sofia/gateway/VoiceNetwork/$1"/></condition></extension>(3)基于用户配置的个性化限制
步骤1:在用户配置文件(如1001.xml)中添加国际呼叫限制变量:
<userid="1001"><params><paramname="password"value="$${default_password}"/><paramname="vm-password"value="1001"/></params><variables><variablename="toll_allow"value="domestic,international,local"/><!-- 国际呼叫限制:最大并发1路,每日最多3路 --><variablename="calls_max_intl"value="1"/><variablename="call_per_day_intl"value="3"/><variablename="accountcode"value="1001"/><variablename="user_context"value="default"/><variablename="effective_caller_id_name"value="Extension 1001"/><variablename="effective_caller_id_number"value="1001"/><variablename="outbound_caller_id_name"value="$${outbound_caller_name}"/><variablename="outbound_caller_id_number"value="$${outbound_caller_id}"/><variablename="callgroup"value="techsupport"/></variables></user>步骤2:修改国际呼叫拨号方案,使用用户自定义变量:
<extensionname="international.VoiceNetwork.ca"><conditionfield="${toll_allow}"expression="international"/><conditionfield="destination_number"expression="^(011\d+)$"><actionapplication="set"data="effective_caller_id_number=${outbound_caller_id_number}"/><actionapplication="set"data="effective_caller_id_name=${outbound_caller_id_name}"/><actionapplication="sched_hangup"data="+1800 alloted_timeout"/><!-- 使用用户配置的并发上限 --><actionapplication="limit"data="hash fraud_protection calls_max_intl ${calls_max_intl} !NORMAL_TEMPORARY_FAILURE"/><!-- 使用用户配置的每日呼叫上限 --><actionapplication="limit"data="hash fraud_protection call_per_day_intl ${call_per_day_intl}/86400 !NORMAL_TEMPORARY_FAILURE"/><actionapplication="bridge"data="sofia/gateway/VoiceNetwork/$1"/></condition></extension>