SipFlow 集群部署
SipFlow 是 RustPBX 内置的 SIP+RTP 信令抓包和回放系统,支持本地模式和独立集群模式。
1. 功能概述
| 能力 | 说明 |
|---|---|
| SIP 信令抓包 | 完整的 SIP 请求/响应报文 |
| RTP 媒体抓包 | 可选,按录音策略触发 |
| WAV 回放 | 从 RTP 包生成通话录音 |
| 时间线浏览 | Web 控制台中按 call_id 查看完整信令流 |
| S3/HTTP 上传 | 通话结束后上传到对象存储 |
2. 本地模式(单节点)
2.1 配置
[sipflow]
[sipflow.local]
subdirs = "daily" # none / daily / hourly
flush_count = 100 # 每 100 包刷新到磁盘
flush_interval_secs = 5 # 最长 5 秒刷新
id_cache_size = 10000 # Call-ID 缓存大小
2.2 存储结构
sipflow/
├── 20260526/
│ ├── 20260526.sqlite # 元数据索引
│ └── 20260526.raw # 原始报文(zstd 压缩)
├── 20260527/
│ ├── 20260527.sqlite
│ └── 20260527.raw
*.sqlite:每条记录包含call_id、时间戳、源/目的 IP/端口、SIP 方法*.raw:二进制报文数据,zstd 压缩
2.3 RTP 录音生成
从抓包数据生成 WAV:
GET /api/sipflow/media?call_id=xxx&start=0&end=3600&format=wav
支持 PCMU、PCMA、G722、L16 编解码转 WAV。
2.4 上传配置
通话结束后自动上传:
[sipflow.upload]
type = "s3"
bucket = "sipflow-archives"
region = "us-east-1"
endpoint = "https://s3.amazonaws.com"
access_key = "AKIA..."
secret_key = "secret..."
# 或上传到 HTTP
# [sipflow.upload]
# type = "http"
# url = "https://api.example.com/sipflow/upload"
3. 独立集群模式
多节点部署时,SipFlow 可部署为独立服务,通过一致性哈希路由。
3.1 架构
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ RustPBX │ │ RustPBX │ │ RustPBX │
│ Node 1 │ │ Node 2 │ │ Node 3 │
└──────┬──────┘ └──────┬──────┘ └──────┬──────┘
│ │ │
│ UDP 报文 + HTTP 查询 │
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ SipFlow │ │ SipFlow │ │ SipFlow │
│ Server A │ │ Server B │ │ Server C │
│ :3000/3001 │ │ :3000/3001 │ │ :3000/3001 │
└─────────────┘ └─────────────┘ └─────────────┘
- RustPBX 节点通过
call_id一致性哈希选择 SipFlow Server - 每个 SipFlow Server 独立存储
- 查询时自动路由到正确的 Server
3.2 SipFlow Server 部署
SipFlow Server 是独立的二进制(sipflow),从 RustPBX 源码编译:
cargo build --release --bin sipflow
启动参数:
/static/docs-zh/addons/sipflow \
--addr 0.0.0.0 \
--port 3000 \ # UDP 接收端口
--http-port 3001 \ # HTTP API 端口
--root /data/sipflow \ # 存储目录
--flush-count 200 \ # 刷新包数
--flush-interval 5 \ # 刷新间隔秒
--buffer-size 65536 # UDP 接收缓冲区
Docker 部署:
docker run -d --name sipflow-a \
-v /data/sipflow:/data/sipflow \
-p 3000:3000/udp -p 3001:3001 \
docker.cnb.cool/miuda.ai/rustpbx:latest \
/app/sipflow --addr 0.0.0.0 --port 3000 --http-port 3001 --root /data/sipflow
3.3 SipFlow Server HTTP API
| 端点 | 方法 | 说明 |
|---|---|---|
/health | GET | 健康检查 |
/flow | GET | 查询 SIP 信令(callid, start, end 参数) |
/media | GET | 生成 WAV 录音(callid, start, end, format 参数) |
3.4 RustPBX 节点配置
每个 RustPBX 节点配置 SipFlow 远程后端:
[sipflow]
[sipflow.remote]
flush_interval_secs = 5
[[sipflow.remote.nodes]]
udp = "10.0.1.1:3000"
http = "http://10.0.1.1:3001"
[[sipflow.remote.nodes]]
udp = "10.0.1.2:3000"
http = "http://10.0.1.2:3001"
[[sipflow.remote.nodes]]
udp = "10.0.1.3:3000"
http = "http://10.0.1.3:3001"
路由规则:
- 写入:
hash(call_id) % node_count→ 选择目标 Server,UDP 发送 - 查询:同样哈希路由到正确的 Server,HTTP GET 请求
3.5 一致性哈希
SipFlow 使用简单取模哈希(非一致性哈希环):
- 增减节点时,约
1/N的 call_id 会路由变化 - 建议在规划时确定节点数,避免频繁变更
- 节点变更后,历史数据的查询可能需要逐节点遍历
4. Web 控制台查看
控制台 → 通话记录 → 点击通话 → SIP Flow:
在 CDR 列表中点击任意通话,查看完整的 SIP 信令时间线:
- 每条 SIP 消息的时序
- 请求/响应配对
- RTP 流信息
- 可播放通话录音
5. 存储规划
5.1 磁盘空间估算
| 数据类型 | 每通电话大小 | 1 万通/天/月 |
|---|---|---|
| SIP 信令 | ~5 KB | ~150 MB |
| RTP 媒体(可选) | ~50-200 KB | ~1.5-6 GB |
| SQLite 索引 | ~500 B | ~15 MB |
5.2 保留策略
建议通过定时任务清理过期数据:
# 删除 90 天前的数据
find /data/sipflow -maxdepth 1 -type d -name "20*" -mtime +90 -exec rm -rf {} \;
或配置上传到 S3 后本地自动清理。
6. 网络要求
| 端口 | 协议 | 用途 |
|---|---|---|
| 3000 | UDP | RustPBX → SipFlow 报文传输 |
| 3001 | HTTP | RustPBX → SipFlow 查询 API |
RustPBX 节点需要能访问所有 SipFlow Server 的 UDP 和 HTTP 端口。
7. 录音策略与 SipFlow 的关系
SipFlow 抓包与通话录音是独立的:
| 配置 | 说明 |
|---|---|
[recording] | 通话录音(WAV/MP3) |
[sipflow] | 信令抓包(SIP+RTP 包) |
- SipFlow RTP 抓包跟随录音策略(仅录音的通话才抓 RTP)
- SIP 信令始终抓取(无论是否录音)
- SipFlow 生成的 WAV 可作为录音备份