人们通常会讨论 SIP 代理是 “有状态 “还是 “无状态 “运行,但这些概念之间的区别可能很难把握。RFC3261 中当然有详细说明,但那是一本相当枯燥和详细的读物。人们还经常注意到,这里指的是事务状态,而不是对话状态,但这同样不是一个容易理解的定义。这一点的目的是提供一些澄清和区别实例,说明无状态事务处理和有状态事务处理之间的区别。
事务与对话框
最简单的理解方式是,事务是一个 SIP 请求及其响应,而对话则由一系列请求和响应组成。一个过于简化的例子是,建立呼叫的一组消息是一个事务,结束呼叫的一组消息是一个单独的事务。
Kamailio中的无状态事务处理
在无状态事务处理中,Kamailio只对单个SIP消息采取行动。它不会试图在SIP请求和匹配的响应之间建立关联。在这种模式下,Kamailio的效率极高,但正如我们最终将看到的那样,它也有相当大的局限性。举例说明,我们的环境由 UAC(发送 INVITE)、Kamailio 代理(无状态转发 INVITE)和 UAS(不工作,不会响应,只是一个在 TTY 模式下运行 shell 的容器)组成。
这里的 kamailio 配置如下:
#!KAMAILIO
loadmodule "pv"
loadmodule "xlog"
loadmodule "sl"
modparam("xlog", "prefix", "[$ci $rm-$cs] ")
modparam("xlog", "prefix_mode", 1)
modparam("sl", "bind_tm", 0)
disable_sctp = yes
force_rport = yes
request_route {
xinfo("$rm Call-ID: $ci RURI: $ru\n");
$rd = "uas";
forward();
}
很简单吧?更新 RURI 域并转发。那么,流量是什么样的呢?调用梯形图是这样的:
UAC PROXY UAS
───┬─── ───┬─── ───┬───
│ INVITE │ │
│ ─────────────> │ │
│ │ INVITE │
│ │ ─────────────> │
│ INVITE │ │
│ ─────────────> │ │
│ │ INVITE │
│ │ ─────────────> │
│ INVITE │ │
│ ─────────────> │ │
│ │ INVITE │
│ │ ─────────────> │
│ INVITE │ │
│ ─────────────> │ │
│ │ INVITE │
│ │ ─────────────> │
│ INVITE │ │
│ ─────────────> │ │
│ │ INVITE │
│ │ ─────────────> │
UAC 向代理发送 INVITE,代理将其转发。由于 UAS 处于非活动状态,所以没有响应,代理对此并不关心。代理转发 INVTE 是它的职责所在,INVITE 的重新传输由 UAC 负责。
Kamailio 中的有状态消息
那么,如果我们在 Kamailio 中进行有状态操作,会发生什么情况呢?配置文件如下。除了加载 TM 模块和使用 t_relay()而非 forward()外,它与无状态配置几乎完全相同。请注意,现实世界中的配置需要做的远不止这些。但这给我们提供了一个清晰的例子,说明在 UAS 没有响应的简单场景中,行为的不同之处。
完整配置可在此处找到,但这是 Kamailio 配置文件:
#!KAMAILIO
loadmodule "pv"
loadmodule "xlog"
loadmodule "tm"
loadmodule "sl"
modparam("xlog", "prefix", "[$ci $rm-$cs] ")
modparam("xlog", "prefix_mode", 1)
modparam("sl", "bind_tm", 0)
disable_sctp = yes
force_rport = yes
request_route {
xinfo("$rm Call-ID: $ci RURI: $ru\n");
$rd = "uas";
t_relay();
}
由此产生的调用阶梯是如何工作的?
UAC PROXY UAS
───┬─── ───┬─── ───┬───
│ INVITE │ │
│ ─────────────> │ │
│ 100 Trying │ │
│ <───────────── │ │
│ │ INVITE │
│ │ ─────────────> │
│ │ INVITE │
│ │ ─────────────> │
│ │ INVITE │
│ │ ─────────────> │
│ │ INVITE │
│ │ ─────────────> │
│ │ INVITE │
│ │ ─────────────> │
│ │ INVITE │
│ │ ─────────────> │
│ │ INVITE │
│ │ ─────────────> │
│ │ INVITE │
│ │ ─────────────> │
│ │ INVITE │
│ │ ─────────────> │
│ │ INVITE │
│ │ ─────────────> │
│ 408 Timeout │ │
│ <───────────── │ │
│ ACK │ │
│ ─────────────> │ │
这明显不同。在这里,代理不仅仅充当消息的“哑管道”,它更是一个积极的参与者。100 Trying
是由TM
模块免费提供的(不过可以通过模块参数禁用它)。这告诉UAC请求已经收到,因此UAC停止重传。当没有收到响应时,代理负责重传 INVITE。代理确定超时并向 UAC 发送408 Request Timeout
。
从表面上看,这似乎没什么大不了的,但它显示了关键的区别。因为代理知道响应,所以它可以处理响应并决定正确的操作。例如,串行分叉(看起来像这样)就可以实现。
UAC PROXY UAS1 UAS2
───┬─── ───┬─── ───┬─── ───┬───
│ INVITE │ │ │
│ ─────────────> │ │ │
│ 100 Trying │ │ │
│ <───────────── │ │ │
│ │ INVITE │ │
│ │ ─────────────> │ │
│ │ 503 Error │ │
│ │ <───────────── │ │
│ │ INVITE │
│ │ ──────────────────────────────> │
│ │ 100 Trying │
│ │ <────────────────────────────── │
│ │ 180 Alerting │
│ │ <────────────────────────────── │
│ 180 Alerting │ │ │
│ <───────────── │ │ │
│ │ 200 OK │
│ │ <────────────────────────────── │
│ 200 OK │ │ │
│ <───────────── │ │ │
只有当代理知道事务状态时,才能实现上述逻辑。
总结
虽然在Kamailio中采用无状态配置以实现最高性能似乎很诱人,但Kamailio中大多数有意义的路由决策都会涉及事务路由。
内容编译自:https://kaufmania.wordpress.com/2023/10/07/kamailio-stateful-vs-stateless-mode/
本文来自作者投稿,版权归原作者所有。如需转载,请注明出处:https://www.nxrte.com/jishu/35078.html