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路呼叫。
xml
<extension name="outbound">
<condition field="destination_number" expression="^1?[2-9]\d{2}[2-9]\d{6}$">
<action application="limit_execute" data="hash outbound carrier1 5 bridge sofia/gateway/carrier1/${destination_number}" />
<action application="limit_execute" data="hash outbound carrier2 5 bridge sofia/gateway/carrier2/${destination_number}" />
</condition>
</extension>
2. 限制用户并发呼叫数
场景:限制域内单个用户同时只能发起1路呼叫,超限后播放提示音并挂断。
xml
<extension name="limit_exceeded">
<condition field="destination_number" expression="^limit_exceeded$">
<action application="playback" data="/sounds/overthelimit.wav"/>
<action application="hangup"/>
</condition>
</extension>
<extension name="limit" continue="true">
<condition>
<!-- 可在directory.conf中为每个用户单独配置max_calls变量,移除下方行 -->
<action application="set" data="max_calls=1" inline="true"/>
<action application="limit" data="db $${domain} ${sip_auth_username} ${max_calls}"/>
</condition>
</extension>
注意 :
limit_exceeded分机需配置在limit分机之前,因为limit()函数会调用transfer(),而转接操作会从拨号方案开头开始匹配分机,避免出现转接循环。
3. 呼叫速率限制(防垃圾呼叫)
-
按源IP+被叫号码 限制每秒呼叫数:
xml<action application="limit" data="hash ${sip_received_ip} ${destination_number} ${calls_per_second}/1" /> -
限制每10分钟最多5路呼叫:
xml<action application="limit" data="hash ${sip_received_ip} ${destination_number} 5/600" />
4. 基于计数器的用户忙状态判断
场景:根据外部计数器判断用户状态,若计数器值超过60则返回"用户忙",否则正常呼叫。
xml
<action application="bridge" data="${cond(${limit_usage(db time_spent in_bed)} <= 60 ? error/user_busy : user/$1)}" />
注意
- 该操作不会增加限制计数器的数值;
- 在新版本中,需先调用
limit功能为该资源设置计数规则(即使设为-1表示无限制),才能让该函数返回非零值。
5. 网关/用户级别的B腿呼叫限制
场景:对呼出呼叫的B腿(网关侧)设置并发限制,需通过环回通道(loopback)实现。
主拨号方案配置:
xml
<action application="set" data="destnum=${destination_number}" />
<action application="bridge" data="loopback/context/gw1,loopback/context/gw2" />
对应上下文配置:
xml
<extension name="gw1">
<condition field="destination_number" expression="gw1">
<action application="limit" data="db outgoing gw1 10" />
<action application="bridge" data="sofia/gateway/gw1/${destnum}" />
</condition>
</extension>
<extension name="gw2">
<condition field="destination_number" expression="gw2">
<action application="limit" data="db outgoing gw2 5" />
<action application="bridge" data="sofia/gateway/gw2/${destnum}" />
</condition>
</extension>
原理 :若第一个网关达到并发上限,系统会先清理该网关的计数记录,再尝试下一个网关。若直接在同一分机中连续配置
limit和bridge,计数记录需等到A腿回到CS_ROUTING状态才会清理,会导致已尝试的网关持续占用通道资源。
6. 呼出网关的故障转移与限制
场景:配置3个呼出网关,实现故障自动转移,并为每个网关设置并发上限(适配美国10位号码)。
xml
<extension name="Outbound calls">
<condition field="destination_number" expression="^(\d{10})$" break="on-true">
<action application="set" data="continue_on_fail=true"/>
<action application="set" data="hangup_after_bridge=true"/>
<action application="enum" data="1$1 e164.arpa"/>
<action application="bridge" data="${enum_auto_route}"/>
<action application="enum" data="1$1 e164.org"/>
<action application="bridge" data="${enum_auto_route}"/>
<action application="enum" data="1$1 nrenum.net"/>
<action application="bridge" data="${enum_auto_route}"/>
<action application="set" data="auto_hunt=true"/>
<action application="limit" data="$${domain} gw_PROVIDER1 PROVIDER1_CHANNEL_LIMIT usdirect2"/>
<action application="bridge" data="sofia/gateway/PROVIDER1/1$1"/>
<action application="transfer" data="usdirect2"/>
</condition>
</extension>
<extension name="usdirect2">
<condition field="destination_number" expression="^usdirect2$"/>
<condition field="rdnis" expression="^(\d{10}$)">
<action application="limit" data="db $${domain} gw_PROVIDER2 PROVIDER2_CHANNEL_LIMIT usdirect3"/>
<action application="bridge" data="sofia/gateway/PROVIDER2/1$1"/>
<action application="transfer" data="usdirect3"/>
</condition>
</extension>
<extension name="usdirect3">
<condition field="destination_number" expression="^usdirect3$"/>
<condition field="rdnis" expression="^(\d{10}$)">
<action application="limit" data="db $${domain} gw_PROVIDER3 PROVIDER3_CHANNEL_LIMIT"/>
<action application="bridge" data="sofia/gateway/PROVIDER3/1$1"/>
</condition>
</extension>
<extension name="limit_exceeded">
<condition field="destination_number" expression="^limit_exceeded$">
<action application="playback" data="/sounds/overthelimit.wav"/>
<action application="hangup"/>
</condition>
</extension>
关键配置说明
auto_hunt=true:允许直接跳转到指定分机,无需遍历整个拨号方案;- 替换
PROVIDER1..3为实际网关名称,PROVIDER1..3_CHANNEL_LIMIT为网关并发上限;- 在
bridge后配置transfer,实现网关故障自动转移。
7. 监控网关IP的并发呼叫数
命令行查询方式
-
监控呼入网关(IP:1.2.3.4)的并发呼叫数:
bashfs_cli -x 'limit_usage db inbound 1.2.3.4' -
监控呼出网关(IP:5.6.7.8)的并发呼叫数:
bashfs_cli -x 'limit_usage db outbound 5.6.7.8'
拨号方案配置示例
xml
<extension name="customer_a">
<condition field="network_addr" expression="^1\.2\.3\.4$"/>
<condition field="destination_number" expression="^(.*)$">
<action application="limit" data="db inbound 1.2.3.4 10000" />
<action application="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分机后添加以下配置:
xml
<action application="limit" data="hash ${domain} $1 1 handle_over_limit XML over_limit_actions"/>
步骤2 :在conf/dialplan/目录下新建limits.xml文件,添加超限处理逻辑:
xml
<include>
<context name="over_limit_actions">
<extension name="oops, too many calls for this one">
<condition field="destination_number" expression="handle_over_limit">
<action application="answer"/>
<action application="playback" data="ivr/ivr-no_no_no.wav"/>
<action application="playback" data="ivr/ivr-no_no_no.wav"/>
<action application="playback" data="ivr/ivr-no_no_no.wav"/>
<action application="hangup" data="USER_BUSY"/>
</condition>
</extension>
</context>
</include>
扩展配置 :若需将单用户并发上限改为4路,修改
limit参数即可:
xml<action application="limit" data="hash ${domain} $1 4 handle_over_limit XML over_limit_actions"/>
进阶配置:仅限制用户拨打7位及以上号码的并发数,拨打4位内部分机不限制:
xml
<extension name="set outbound limit" continue="true">
<condition field="destination_number" expression="^1?\d{7}" break="on-false"/>
<condition field="caller_id_number" expression="^(10[01][0-9])">
<action application="limit" data="hash ${domain} $1 4 handle_over_limit XML over_limit_actions"/>
<action application="log" data="INFO Added limit for caller $1"/>
</condition>
</extension>
9. 防资费欺诈配置
(1)限制国内呼叫
限制同时发起4路国内呼叫,且每日最多发起250路国内呼叫,超限后返回"临时故障"。
xml
<extension name="domestic.VoiceNetwork.ca">
<condition field="${toll_allow}" expression="domestic"/>
<condition field="destination_number" expression="^(\d{11})$">
<action application="set" data="effective_caller_id_number=${outbound_caller_id_number}"/>
<action application="set" data="effective_caller_id_name=${outbound_caller_id_name}"/>
<!-- 限制最大并发呼叫数:4路 -->
<action application="limit" data="hash fraud_protection calls_max 4 !NORMAL_TEMPORARY_FAILURE"/>
<!-- 限制每日最大呼叫数:250路(86400秒=1天) -->
<action application="limit" data="hash fraud_protection call_per_day 250/86400 !NORMAL_TEMPORARY_FAILURE"/>
<action application="bridge" data="sofia/gateway/VoiceNetwork/$1"/>
</condition>
</extension>
(2)限制国际呼叫
限制同时发起1路国际呼叫、每日最多10路国际呼叫,且单路呼叫最长时长为30分钟。
xml
<extension name="international.VoiceNetwork.ca">
<condition field="${toll_allow}" expression="international"/>
<condition field="destination_number" expression="^(011\d+)$">
<action application="set" data="effective_caller_id_number=${outbound_caller_id_number}"/>
<action application="set" data="effective_caller_id_name=${outbound_caller_id_name}"/>
<!-- 限制单路呼叫最长时长:30分钟(1800秒) -->
<action application="sched_hangup" data="+1800 alloted_timeout"/>
<!-- 限制最大并发呼叫数:1路 -->
<action application="limit" data="hash fraud_protection calls_max_intl 1 !NORMAL_TEMPORARY_FAILURE"/>
<!-- 限制每日最大呼叫数:10路 -->
<action application="limit" data="hash fraud_protection call_per_day_intl 10/86400 !NORMAL_TEMPORARY_FAILURE"/>
<action application="bridge" data="sofia/gateway/VoiceNetwork/$1"/>
</condition>
</extension>
(3)基于用户配置的个性化限制
步骤1 :在用户配置文件(如1001.xml)中添加国际呼叫限制变量:
xml
<user id="1001">
<params>
<param name="password" value="$${default_password}"/>
<param name="vm-password" value="1001"/>
</params>
<variables>
<variable name="toll_allow" value="domestic,international,local"/>
<!-- 国际呼叫限制:最大并发1路,每日最多3路 -->
<variable name="calls_max_intl" value="1"/>
<variable name="call_per_day_intl" value="3"/>
<variable name="accountcode" value="1001"/>
<variable name="user_context" value="default"/>
<variable name="effective_caller_id_name" value="Extension 1001"/>
<variable name="effective_caller_id_number" value="1001"/>
<variable name="outbound_caller_id_name" value="$${outbound_caller_name}"/>
<variable name="outbound_caller_id_number" value="$${outbound_caller_id}"/>
<variable name="callgroup" value="techsupport"/>
</variables>
</user>
步骤2:修改国际呼叫拨号方案,使用用户自定义变量:
xml
<extension name="international.VoiceNetwork.ca">
<condition field="${toll_allow}" expression="international"/>
<condition field="destination_number" expression="^(011\d+)$">
<action application="set" data="effective_caller_id_number=${outbound_caller_id_number}"/>
<action application="set" data="effective_caller_id_name=${outbound_caller_id_name}"/>
<action application="sched_hangup" data="+1800 alloted_timeout"/>
<!-- 使用用户配置的并发上限 -->
<action application="limit" data="hash fraud_protection calls_max_intl ${calls_max_intl} !NORMAL_TEMPORARY_FAILURE"/>
<!-- 使用用户配置的每日呼叫上限 -->
<action application="limit" data="hash fraud_protection call_per_day_intl ${call_per_day_intl}/86400 !NORMAL_TEMPORARY_FAILURE"/>
<action application="bridge" data="sofia/gateway/VoiceNetwork/$1"/>
</condition>
</extension>