All checks were successful
Build and Deploy Backend / build-and-deploy (push) Successful in 5m41s
3.9 KiB
3.9 KiB
hw_service_go 并发压力测试报告
测试时间:2026-03-03 测试目标:
wss://qiyuan-rtc-api.airlabs.art/xiaozhi/v1/Pod 配置:单 Pod,CPU 100m500m(limits),Memory 128Mi512Mi(limits),replicas: 1
一、测试环境
| 项目 | 配置 |
|---|---|
| 服务 | hw_service_go(WebSocket + Opus 音频推送) |
| 部署 | K8s 单 Pod,1 副本 |
| CPU limits | 500m(0.5 核) |
| Memory limits | 512Mi |
| 硬编码连接上限 | 500 |
| 测试工具 | Go 压测工具(test/stress/main.go) |
| 测试客户端 | macOS,从公网连接线上服务 |
二、测试结果
2.1 连接容量测试(空闲连接)
go run main.go -url wss://..../xiaozhi/v1/ -conns 200 -stories 0 -duration 30s
| 指标 | 结果 |
|---|---|
| 目标连接 | 200 |
| 成功连接 | 200 |
| 握手成功 | 200 |
| 错误 | 0 |
结论:200 个空闲连接毫无压力,内存不是瓶颈。
2.2 并发播放压力测试
每个"活跃故事"会触发:Django API 查询 → MP3 下载 → ffmpeg 转码 → Opus 编码 → WebSocket 推帧。
| 并发故事数 | 总连接 | 首帧延迟 | 帧数/故事 | 错误 | 状态 |
|---|---|---|---|---|---|
| 2 | 10 | 2.0s | 796 | 0 | 轻松 |
| 5 | 10 | 4.5s | 796 | 0 | 正常 |
| 10 | 20 | 8.7s | 796 | 0 | 吃力但稳 |
| 20 | 30 | 17.4s | 796 | 0 | 极限 |
2.3 关键发现
- 帧数始终稳定 796/故事 — 音频完整交付,零丢帧,服务可靠性极高
- 首帧延迟线性增长 — 约 0.85s/并发,纯 CPU 瓶颈(多个 ffmpeg 进程争抢 0.5 核)
- Pod 未触发 OOMKill — 512Mi 内存对 20 并发播放也够用
- 全程零错误 — 无连接断开、无握手失败、无帧丢失
三、瓶颈分析
单个故事播放的资源消耗链路:
Django API (GET) → MP3 下载 (OSS) → ffmpeg 转码 (CPU密集) → Opus 编码 → WebSocket 推帧
↑
主要瓶颈
每个并发故事启动一个 ffmpeg 子进程
多个 ffmpeg 共享 0.5 核 CPU
| 资源 | 是否瓶颈 | 说明 |
|---|---|---|
| CPU | 是 | ffmpeg 转码是 CPU 密集型,0.5 核被多个 ffmpeg 进程分时使用 |
| 内存 | 否 | 20 并发播放未触发 OOM,512Mi 充足 |
| 网络 | 否 | Opus 帧约 4-7 KB/s/连接,带宽远未饱和 |
| 连接数 | 否 | 空闲连接 200+ 无压力,硬上限 500 |
四、容量结论
当前单 Pod(0.5 核 CPU, 512Mi, 1 副本)
| 指标 | 数值 |
|---|---|
| 空闲连接上限 | 200+(轻松) |
| 并发播放(体验好,首帧 < 5s) | ~5 个 |
| 并发播放(可接受,首帧 < 10s) | ~10 个 |
| 并发播放(极限,首帧 ~17s) | ~20 个 |
| 瓶颈资源 | CPU(ffmpeg 转码) |
五、扩容建议
| 方案 | 变更 | 预估并发播放(首帧 < 10s) | 成本 |
|---|---|---|---|
| 提 CPU | limits 500m → 1000m | ~20 个 | 低 |
| 加副本 | replicas 1 → 2 | ~10 个(负载均衡) | 中 |
| 两者都做 | 1000m CPU + 2 副本 | ~40 个 | 中 |
| 垂直扩容 | 2000m CPU + 1Gi 内存 | ~40 个 | 中 |
推荐方案:replicas: 2 + CPU limits: 1000m,兼顾高可用与并发能力。
六、测试命令参考
cd hw_service_go/test/stress
# 空闲连接容量
go run main.go -url wss://TARGET/xiaozhi/v1/ -conns 200 -stories 0 -duration 30s
# 并发播放(逐步加压)
go run main.go -url wss://TARGET/xiaozhi/v1/ -conns 10 -stories 2 -duration 60s
go run main.go -url wss://TARGET/xiaozhi/v1/ -conns 10 -stories 5 -duration 60s
go run main.go -url wss://TARGET/xiaozhi/v1/ -conns 20 -stories 10 -duration 90s
go run main.go -url wss://TARGET/xiaozhi/v1/ -conns 30 -stories 20 -duration 120s