XCC API

XSwitch 集群

本章讨论 XSwitch 集群组网。


来话处理

来话处理如下图所示。假设中继侧来话可以以一定算法分配置到 3 个不同的 XSwitch Node 节点。XNode 收到呼叫后,向 NATS 广播来话消息(Event.Channel(state = START)),Ctrl 收到后进行处理。

所有 XNode 都订阅至少两个 Subject:

  • cn.xswitch.node:所有 XNode 都以同一个 Queue 订阅,发往该 Subject 的消息只有一个 Node 能收到,也就是说接收消息是互斥的。
  • cn.xswitch.node.n:其中n = 1,2,3 ...,每个 Node 独立订阅,发往该 Subject 的消息只有一个能收到,也就是说,可以通过它定向发消息。

同理,所有 Ctrl 都订阅两个 Subject:

  • cn.xswitch.ctrl:以同一个 Queue 订阅,互斥接收。
  • cn.xswitch.ctrl.n:其中n = 1,2,3 ...,每个 Ctrl 独立订阅。

当有来话时,不失一般性,假设该来话分发到了node.1,则它会构造一个消息,通过 NATS 发送到cn.xswitch.ctrl上,右侧两个 Ctrl 都有可能收到该消息,但只有一个收到。不失一般性,假设ctrl.1收到了这个消息,这时候,它从消息的内容中取出node_uuid,知道了该消息是来自node.1,因此,它往node.1上回复一个XNode.Accept指令,表示它想接管这一路呼叫。node.1收到后,向ctrl.1回复200 OK,表示指令执行成功。至此,Node 和 Ctrl 通过 NATS 建立了一个“虚连接”(一对一对应关系),在这路通话生存期间都是如此。

时序图如下所示:

去话处理

去话逻辑与来话差不多,区别只是控制首先从 Ctrl 发起。假设ctrl.1发起呼叫,它首先将XNode.Dial请求发到cn.xswitch.node这个 Subject 上,不失一般性,假设node.1收到了这个请求,在后续的返回结果中,它会告诉ctrl.1这个呼叫是在node.1上处理了,因而也可以建立虚连接。

如果 Ctrl 想将 Dial 请求发到指定的 Node 上,也可以直接指定 Node 对应的 Subject,如cn.xswitch.node.1。至于 Ctrl 如何知道有哪几个 Node,参见下一节节点管理。

节点管理

  • 每个 Node 在上线时都会主动发Event.NodeRegister消息,Ctrl 侧可以订阅该消息以便感知节点上线。
  • 每个 Node 在下线时会发Event.NodeUnregister消息,请求注销。
  • 为了防止 Node 崩溃时来不及发送注销消息,Node 每 20 秒发一个Event.NodeUpdate消息,该消息可以做为心跳保活消息使用。此外,该消息还携带节点当前的活动 Channel 数以及负载信息。Ctrl 可以根据该信息向“负载最轻”的 Node 发送新任务。

注意:防止优先级反转。分布式系统的一个难点或者说一个误区就是无条件地往“负载最轻”的节点上发消息。假设我们做了一个自动外呼系统,有三个 Ctrl 和三个 Node。在某一时间,三个 Ctrl 都发现node.1负载最轻,然后分别向它发送了10个外呼任务,node.1就会在同一时刻收到 30 个外呼任务,有可能立即成为“负载最重”的节点,甚至会过载。

总之,分布式系统从来都不是很简单就可以实现的,在实际使用时需要考虑各种边界情况。在实际使用时,简单的轮循算法基于就可以做到“足够好”,如果能配合一些反馈补偿机制,就能做到“更好”。

这些消息默认会发到cn.xswitch.ctrl上,但是在 ctrl 侧存在多个实例的情况下,由于cn.xswitch.ctrl一般是队列方式订阅的,会导致一个消息只有其中一个节点能收到。因此,在这种情况下应该开启status-ctrl-subject参数,它的默认值是cn.xswitch.node.status

双机热备

集群需要比较多的物理机或虚拟机。在规模不大的情况下,可以使用双机热备,只需要两台机器。

双机热备与集群不同,双机热备是两台当一台用,浮动 IP 绑在主用 XSwitch 节点上对外提供服务。如下图:

双机热备模式下,两个节点配置如下:

  • switch.conf.xml中配置的switch_name要一致。
  • XCC 节点名要一致,配置node-name参数(该参数如果不配则可选)。
  • cn.xswitch.node这个如果使用,则只能用普通订阅模式,而不能用队列订阅。
  • 如果不使用cn.xswitch.node这个通用主题,可以使用cn.xswitch.node.$node-name主题
  • 将备机配置为standby模式(目前仅支持命令切换xcc <active|standby>),在standby模式下,XCC 正常订阅消息,但不做处理。
  • 总之,主备两台机器都会订阅cn.xswitch.node.$node-name,但只有主机会处理。

上图中,node-name被配成了x,会影响事件消息中的node_uuid值(也等于x),时时 XCC Node 节点全名为cn.xswitch.node.x。在应用中可以直接对这个 Subject 发消息。

需要说明的是,双机热备也需要 Ctrl 侧的支持。下面是一些切换逻辑:

总体逻辑

当发生切换时,系统会向cn.xswitch.ctrlcn.xswitch.ctrl.status(可配置)上发送Event.Recover事件消息,消息中包含成功恢复的 Channel 数量。

当发生切换时,已经桥接的呼叫会继续通话。正在放音的呼叫会中断(业务侧应该重放),已进入会议的呼叫可以继续会议。

单腿通话

来话

当发生主备切换时,Ctrl 将重新收到START消息,里面有recovered: true参数;Ctrl 应先执行Accept,然后执行后面的动作。在 IVR 类应用中,为了避免重放以前的放音,Ctrl 侧应该是有状态的。

去话

当发生主备切换时,只能通过Event.Recover事件知道已发生了切换,这时,所有已发送的请求命令将会超时(因为 XNode 无法回应消息),在超时后,Ctrl 侧可以重试上一个命令(这时可能还没有收到Event.Recover消息),或全局等待收到Event.Recover消息后再重试。

会议

会议应该可以正常恢复。

桥接的通话

桥接的通话理论上不受影响,但是,主备切换后会丢失一些状态,桥接后的处理可能会不正常(如转 IVR、转评价等)。

主备切换后,如果是已桥接的通话,会重新收到BRIDGE消息,并带有recovered: true标志。如果 Ctrl 侧依赖于该事件处理逻辑,则应该检查recovered标志。

桥接的通话在解除桥接时(如一方挂机),也能收到UNBRIDGE消息,并带有recovered: true标志。

小结

总之,双机热备状态下可以恢复处于“稳定”状态的通话,如桥接的通话或会议,但正在接续的电话可能无法正常恢复(不过由于没有正常接通,应该也可以接受)。

另外,为了防止从头重复放音(playbackspeaksay等),放音会中断,这时,业务侧应该感知到主备切换并重新放音。如果应用希望恢复后重放所有声音,则可以设置通道变量recovery_skip_announcement_type_applications=false

配置文件