Sip-Proxy

SIP Proxy 水平扩容方案

核心约束

SIP 事务(ServerTransaction)是 JAIN-SIP 的内存对象,绑定在单进程内,无法跨节点共享。 同一设备的所有 SIP 消息必须打到同一节点,这是 SIP 协议的有状态特性决定的,框架层面无法绕过。


推荐架构

设备 A ──┐
设备 B ──┤                          ┌─ Node-1 (10.0.0.1:5060)
设备 C ──┼──→ VIP 1.2.3.4:5060 ──→ │
设备 D ──┤    (keepalived + ipvs)   └─ Node-2 (10.0.0.2:5060)
设备 E ──┘    源IP哈希
                                         │
                                       Redis
                                    (共享业务状态)

关键点:


状态分层

第一层:进程内状态(不可跨节点)

组件 说明
ServerTransaction JAIN-SIP 事务对象
SipTransactionRegistry 事务上下文,含 ServerTransaction
SipTransactionContext ThreadLocal 事务传递

处理方式: 靠源 IP 哈希保证同一设备打同一节点,无需改造。

第二层:进程内但可外化(建议接 Redis)

组件 说明
SipSubscribe.okSubscribes/errorSubscribes 按 callId 存的响应回调

处理方式:ConcurrentHashMap 替换为 Redis 实现,节点故障后新节点能接管业务状态。

旧版本中的 SubscribeHolder.catalogMap/mobilePositionMap 已于 v1.3.0 移除,订阅状态下放业务方根据需要自行管理(Redis 或本地)。

第三层:已支持外化(接口化)

组件 说明
DeviceSessionCache 设备会话(ip/port/transport),业务方实现
DeviceSupplier 设备信息提供,业务方实现
ServerDeviceSupplier.authenticate(userId, SIPRequest) 注册鉴权,业务方实现(v1.3.0 替代旧 ServerRegisterProcessorHandler

NAT 穿透

设备侧 NAT(设备在内网)

设备发包经过 NAT,服务器收到的源地址是 NAT 出口地址。

服务器侧 NAT(节点在虚拟机/内网)

节点监听内网地址,但 Via/Contact 头需填对外可达地址,否则设备无法回包。

配置方式:

sip:
  server:
    ip: 0.0.0.0          # 监听地址(内网/所有网卡)
    port: 5060           # 监听端口
    external-ip: 1.2.3.4 # 对外可达地址(VIP 或公网 IP),填入 Via/Contact
    external-port: 5060  # 对外端口(端口映射时填映射后的端口)

external-ip 不配置时 fallback 到 ip,不影响现有部署。

多节点时 external-ip 填 VIP 地址,设备后续消息发到 VIP,ipvs 源 IP 哈希保证还是打到同一节点。


ipvs 配置示例

# 安装
apt install keepalived ipvsadm

# 添加虚拟服务(源IP哈希)
ipvsadm -A -u 1.2.3.4:5060 -s sh
ipvsadm -a -u 1.2.3.4:5060 -r 10.0.0.1:5060 -m
ipvsadm -a -u 1.2.3.4:5060 -r 10.0.0.2:5060 -m

# UDP 同样配置
ipvsadm -A -u 1.2.3.4:5060 -s sh
ipvsadm -a -u 1.2.3.4:5060 -r 10.0.0.1:5060 -m
ipvsadm -a -u 1.2.3.4:5060 -r 10.0.0.2:5060 -m

-s sh = source hash,-m = masquerade(NAT 模式)。


NAT IP 变化的处理

设备 NAT 出口 IP 变化(重拨、网络切换)时:

  1. 旧 NAT 映射失效,心跳超时
  2. 设备触发重新注册,新 REGISTER 打到 VIP
  3. ipvs 按新源 IP 哈希,可能分到不同节点
  4. 新节点处理注册,更新 DeviceSessionCache
  5. 进行中的会话丢失(网络切换本身导致,任何架构下相同)

扩容粒度

水平扩容的粒度是设备 NAT 出口,不是物理设备数。

⚠️ 共享 NAT 出口的聚集效应-s sh 按客户端源 IP 哈希分片,企业园区/家庭网络下多个 GB28181 设备共享同一 NAT 公网 IP 时会全部落到同一节点。规划容量时应按 NAT 出口数 而非设备数估算节点负载,必要时可在前置层做 deviceId 二次分片(但需确保同 deviceId 始终打同节点)。