Wholesale 完整案例
本节通过一个完整案例,演示从零搭建 Wholesale 语音中转平台。
场景描述
公司:某语音运营商,向 3 个下游客户(租户)提供国内/国际语音落地。
上游运营商:
- 运营商 A:国内线路,SIP 中继
10.0.1.100:5060 - 运营商 B:国际线路,SIP 中继
10.0.2.50:5060
下游客户:
- 客户 X:日均 5 万通,主要呼国内
- 客户 Y:日均 2 万通,呼国内+国际
- 客户 Z:日均 1 万通,仅呼国际
Step 1:数据库准备
# MySQL
mysql -u root -p <<EOF
CREATE DATABASE rustpbx CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'rustpbx'@'%' IDENTIFIED BY 'StrongP@ssw0rd';
GRANT ALL PRIVILEGES ON rustpbx.* TO 'rustpbx'@'%';
FLUSH PRIVILEGES;
EOF
Step 2:config.toml
http_addr = "0.0.0.0:8080"
database_url = "mysql://rustpbx:StrongP@ssw0rd@10.0.0.100:3306/rustpbx"
external_ip = "203.0.113.10"
[proxy]
addr = "0.0.0.0"
udp_port = 5060
modules = ["acl", "auth", "registrar", "call"]
media_proxy = "auto"
addons = ["wholesale"]
[proxy.wholesale]
route_cache_capacity = 10000
route_cache_ttl_secs = 30
[proxy.wholesale.circuit_breaker]
failure_threshold = 5
open_duration_secs = 30
half_open_probes = 1
failure_codes = [503, 408, 504]
[console]
session_secret = "my-console-secret-2026"
Step 3:配置 SIP 中继
mkdir -p config/trunks
config/trunks/carrier_a.toml(国内运营商):
[[trunk]]
name = "carrier-a"
dest = "sip:10.0.1.100:5060"
backup_dest = "sip:10.0.1.101:5060"
direction = "outbound"
codec = ["pcmu", "pcma", "g729"]
max_calls = 300
max_cps = 50
weight = 100
[trunk.auth]
username = "myacct_a"
password = "pass_a"
config/trunks/carrier_b.toml(国际运营商):
[[trunk]]
name = "carrier-b"
dest = "sip:10.0.2.50:5060"
direction = "outbound"
codec = ["pcmu", "pcma", "g729", "g722"]
max_calls = 200
max_cps = 30
weight = 100
[trunk.auth]
username = "myacct_b"
password = "pass_b"
Step 4:启动服务
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
Step 5:Web 控制台配置
访问 http://203.0.113.10:8080,创建超级用户后进入控制台。
5.1 创建费率表
Wholesale → 费率表 → 新建:
| 名称 | 类型 |
|---|---|
| buy-carrier-a | 买 |
| buy-carrier-b | 买 |
| sell-domestic | 卖 |
| sell-international | 卖 |
添加费率条目:
buy-carrier-a(买-国内):
| 前缀 | 费率 | 最低时长 | 步长 |
|---|---|---|---|
| 8610 | 0.025 | 6 | 6 |
| 8621 | 0.025 | 6 | 6 |
| 86 | 0.035 | 6 | 6 |
buy-carrier-b(买-国际):
| 前缀 | 费率 | 最低时长 | 步长 |
|---|---|---|---|
| 1 | 0.06 | 6 | 6 |
| 44 | 0.05 | 6 | 6 |
| 81 | 0.07 | 6 | 6 |
sell-domestic(卖-国内):
| 前缀 | 费率 | 最低时长 | 步长 |
|---|---|---|---|
| 8610 | 0.04 | 6 | 6 |
| 8621 | 0.04 | 6 | 6 |
| 86 | 0.05 | 6 | 6 |
sell-international(卖-国际):
| 前缀 | 费率 | 最低时长 | 步长 |
|---|---|---|---|
| 1 | 0.10 | 6 | 6 |
| 44 | 0.08 | 6 | 6 |
| 81 | 0.12 | 6 | 6 |
5.2 配置中继 Wholesale 参数
Wholesale → 中继管理:
- carrier-a → 买费率表:
buy-carrier-a,启用熔断器 - carrier-b → 买费率表:
buy-carrier-b,启用熔断器
5.3 创建路由策略
Wholesale → 路由策略 → 新建:
策略 “profile-domestic”(国内路由):
| 优先级 | 中继 | 前缀 | 权重 |
|---|---|---|---|
| 10 | carrier-a | 86 | 100 |
策略 “profile-full”(国内+国际):
| 优先级 | 中继 | 前缀 | 权重 |
|---|---|---|---|
| 10 | carrier-a | 86 | 100 |
| 10 | carrier-b | 1 | 100 |
| 10 | carrier-b | 44 | 100 |
| 10 | carrier-b | 81 | 100 |
策略 “profile-international”(仅国际):
| 优先级 | 中继 | 前缀 | 权重 |
|---|---|---|---|
| 10 | carrier-b | 1 | 100 |
| 10 | carrier-b | 44 | 100 |
| 10 | carrier-b | 81 | 100 |
5.4 创建租户
| 字段 | 客户 X | 客户 Y | 客户 Z |
|---|---|---|---|
| 名称 | 客户X-国内 | 客户Y-全路由 | 客户Z-国际 |
| 余额 | 50000 | 30000 | 20000 |
| 信用额度 | 5000 | 3000 | 2000 |
| 卖费率表 | sell-domestic | sell-domestic + sell-international | sell-international |
| 路由策略 | profile-domestic | profile-full | profile-international |
| 最大并发 | 200 | 100 | 50 |
| 最大 CPS | 30 | 15 | 10 |
| LCR | 启用 | 启用 | 启用 |
5.5 绑定租户中继
为每个租户添加入向中继绑定,配置源 IP:
- 客户 X:来源 IP
198.51.100.10 - 客户 Y:来源 IP
198.51.100.20 - 客户 Z:来源 IP
198.51.100.30
5.6 热加载
点击费率表和路由策略的 “重新加载” 按钮。
Step 6:验证
6.1 测试呼叫
从客户 X 的软交换发起呼叫到 861012345678:
- 应匹配路由前缀
8610(优先级 10) - 选择 carrier-a
- 匹配卖费率
8610= 0.04 元/分钟 - 匹配买费率
8610= 0.025 元/分钟
6.2 检查 CDR
Wholesale → 话单管理:确认 CDR 已生成,字段正确。
6.3 检查余额
租户详情:确认余额已扣减。
6.4 价格计算器验证
租户详情 → 价格计算器:
- 输入
861012345678→ 显示前缀8610,卖 0.04,买 0.025,利润 0.015 - 输入
12125551234→ 客户 X 应显示“无路由“(仅有国内策略)
Step 7:日常运维
| 操作 | 频率 | 位置 |
|---|---|---|
| 查看监控大盘 | 每天 | Wholesale 控制台 |
| 检查熔断器状态 | 每天 | 监控限流 |
| 核对余额 | 每天 | 租户详情 |
| 导出 CDR | 每周 | 话单管理 → 导出 |
| 生成账单 | 每月 | 账单管理 |
| 费率调整 | 按需 | 费率表 → 重新加载 |
| 数据库备份 | 每天 | MySQLdump / pg_dump |