集群部署

RustPBX 支持多节点集群模式,实现注册状态同步、SipFlow 分布式采集和跨节点呼叫控制。

1. 架构概述

           ┌──────────────┐
           │  Load Balancer│
           │  (SIP/HTTP)  │
           └──────┬───────┘
      ┌───────────┼───────────┐
      ▼           ▼           ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Node 1   │ │ Node 2   │ │ Node 3   │
│ SIP+HTTP │◄─► SIP+HTTP│◄─► SIP+HTTP│
│ SipFlow  │ │ SipFlow  │ │ SipFlow  │
└──────────┘ └──────────┘ └──────────┘
      │           │           │
      └───────────┼───────────┘
                  ▼
         ┌──────────────┐
         │  MySQL/PgSQL │
         └──────────────┘

关键特性:

  • 节点间通过 SIP MESSAGE 同步注册/在线状态事件
  • SipFlow 支持一致性哈希,按 call_id 路由到指定采集节点
  • 共享数据库(MySQL/PostgreSQL)保证配置和 CDR 一致

2. 数据库要求

集群模式 不支持 SQLite,必须使用共享数据库:

数据库最低版本推荐说明
MySQL8.0+8.4 LTS字符集 utf8mb4,排序规则 utf8mb4_unicode_ci
PostgreSQL14+16建议启用 pg_stat_statements 监控

连接字符串示例:

# MySQL
database_url = "mysql://rustpbx:password@10.0.0.100:3306/rustpbx"

# PostgreSQL
database_url = "postgres://rustpbx:password@10.0.0.100:5432/rustpbx"

注意事项:

  • 所有节点必须连接同一个数据库实例
  • 首次启动时 SeaORM 会自动执行 migration,后续节点启动会检测并跳过已执行的 migration
  • 数据库 DDL 文件位于源码根目录(rustpbx_ddl_*.sql),可供手动建表参考

3. 集群配置

3.1 节点间事件同步

在 config.toml 的 [cluster] 段配置 peer 节点:

[cluster]
peers = [
  { addr = "10.0.0.2", sip_port = 5060, ami_port = 8080 },
  { addr = "10.0.0.3", sip_port = 5060, ami_port = 8080 },
]

每个节点只需配置其他节点,不需要包含自身。节点间通过 SIP MESSAGE(application/x-rustpbx-cluster-event)传输 JSON 事件。

同步的事件类型:

  • Locator 事件:用户注册/注销状态
  • Presence 事件:用户在线/离线/忙碌状态

3.2 SipFlow 集群模式

[sipflow]
[sipflow.remote]
flush_interval_secs = 5

[[sipflow.remote.nodes]]
udp = "10.0.0.2:6060"
http = "http://10.0.0.2:6060"

[[sipflow.remote.nodes]]
udp = "10.0.0.3:6060"
http = "http://10.0.0.3:6060"
  • 每个 proxy 节点可读可写,按 call_id 一致性哈希路由到正确的 SipFlow 采集节点
  • 独立部署 sipflow 二进制(在源码 src/bin/sipflow.rs)作为采集服务器

3.3 每个节点的核心配置

http_addr = "0.0.0.0:8080"
database_url = "mysql://rustpbx:password@dbhost:3306/rustpbx"
external_ip = "10.0.0.1"   # 本节点的公网/内网 IP

[proxy]
addr = "0.0.0.0"
udp_port = 5060
modules = ["acl", "auth", "registrar", "call", "presence"]
media_proxy = "auto"

[console]
session_secret = "your-secret-here"  # 所有节点必须相同

3.4 分布式会话注册表(0.5+)

在 locator/presence 同步之外,0.5 版本将集群级会话注册表端到端打通:

ClusterFlow
  • 按归属节点路由的操作:任意节点都可以对接管节点之外的通话执行应答、转接、挂断、设置变量——请求自动转发到持有该会话的节点。节点故障时,其会话会被标记为 offline,而不是变成幽灵会话。
  • 会话 user_data 复制:挂载在会话上的应用数据(CRM 工单号、营销活动标签、坐席上下文)会复制到对端节点。转接和子会话会继承这些数据,业务上下文不会因节点切换而丢失。
  • 心跳指标:每个节点上报其持有会话的存活状态;AMI 健康端点暴露这些 gauges 供监控使用,自清理的 locator 绑定会上报为 offline。

应用侧接入点:PUT /api/calls/active/{session_id}/userdata 与 GET /static/docs-zh/rustpbx/static/docs-zh/userdata 在任意节点均可调用——操作会透明路由到归属节点。

4. 负载均衡配置

4.1 SIP 流量

使用 SIP Load Balancer(如 OpenSIPS、Kamailio)或 DNS SRV:

  • 源 IP 哈希:保证同一用户的 REGISTER 消息路由到同一节点(减少跨节点同步)
  • Call-ID 哈希:保证同一通话的信令在同一节点处理

4.2 HTTP 流量

使用 Nginx/HAProxy 反向代理:

upstream rustpbx {
    ip_hash;  # Session 粘性
    server 10.0.0.1:8080;
    server 10.0.0.2:8080;
    server 10.0.0.3:8080;
}

5. 部署步骤

# 1. 准备共享数据库
mysql -u root -p -e "CREATE DATABASE rustpbx CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"

# 2. 在每个节点部署
docker pull docker.cnb.cool/miuda.ai/rustpbx:latest

# 3. Node 1 (10.0.0.1)
docker run -d --name rustpbx \
  -v $(pwd)/config.toml:/app/config.toml \
  -v $(pwd)/config:/app/config \
  -p 8080:8080 -p 5060:5060/udp \
  docker.cnb.cool/miuda.ai/rustpbx:latest

# 4. Node 2/3 同理,修改 external_ip 和 cluster.peers

6. 运维要点

  • 数据库连接池:每个节点默认连接池大小由 SeaORM 管理,节点数 × 连接数不要超过数据库 max_connections
  • 时间同步:所有节点必须 NTP 同步,CDR 时间戳依赖系统时钟
  • 配置一致性:config/trunks/、config/routes/ 等文件建议通过共享存储或 GitOps 同步到所有节点
  • 滚动重启:逐节点重启,确保至少一个节点在线处理通话
  • SipFlow 存储规划:每个采集节点的磁盘空间独立规划,按每天通话量估算(每通约 50-200KB 信令数据)

8. 集群 AMI 端点(商业版)

多节点部署在 {ami_path} 下暴露额外的集群管理端点:

方法路径说明
POST/cluster/ping对所有对等节点发起健康探活
GET/cluster/reload_config基于 SSE 的集群配置重载流
POST/cluster/reload_sync向特定对等节点同步 JSON 重载负载
POST/cluster/dispatch_command向对等节点分发呼叫控制命令
POST/cluster/session_op按归属节点路由的 RWI 命令信封(终端节点本地执行)
GET/cluster/show_session/{session_id}在对等节点上显示详细呼叫会话状态
GET/cluster/session_owner/{call_id}解析通话由哪个节点承载
GET/cluster/list_calls列出集群中所有活跃呼叫(集群感知的 GET /calls 查询)
POST/cluster/set_userdata / get_userdata按归属节点路由的会话 user_data 复制
POST/cluster/set_var / get_var按归属节点路由的呼叫变量
GET/cluster/logs/recent · /cluster/logs/follow对等节点的近期日志与流式日志
GET/cluster/evaluate_route基于集群路由栈的路由评估

这些端点支持集中式呼叫控制、跨节点会话检查、从任一节点下发协调配置,以及会话 user_data 的跨节点复制。