WebRTC大规模实践:Docker、GPU节点、Prometheus与基于延迟的GKE自动扩缩容
实时应用已成为日常生活的一部分。我们使用它们进行视频通话、在线课程、游戏和健康检查。这些应用需要快速响应,即使是声音或视频的微小延迟也会影响使用体验。
WebRTC是支持大多数此类应用的开源标准。它在浏览器和移动设备上运行,支持直接的音频、视频和数据连接。但在云中扩展WebRTC应用具有挑战性。
为什么CPU指标不够用
大多数Kubernetes设置使用水平Pod自动扩缩器(HPA)和CPU利用率作为指标。当使用率超过限制时,HPA会添加Pod。这对许多应用有效,但对WebRTC效果不佳。
在测试演示应用时,CPU使用率保持在正常水平。直到使用率达到70%时,HPA才添加更多Pod。但此时视频质量已经下降,延迟达到300-400毫秒,帧率下降,音频断断续续。
用户不关心CPU使用率,他们关心流畅的通话体验。系统指标与用户体验之间的差距是主要问题。
解决方案是监控延迟而非CPU使用率。延迟反映了应用的响应时间。延迟峰值告诉我们用户正在遭受不良体验,即使CPU状态良好。
系统架构
构建的系统包含以下组件:
- 集群:包含两个节点池的GKE集群,一个使用常规CPU机器,另一个使用NVIDIA T4 GPU
- NVIDIA设备插件:使GPU对Kubernetes可见,Pod可以请求GPU资源
- WebRTC应用:请求一个GPU的Docker化容器服务,暴露两个端点:
/healthz显示运行状态/metrics共享延迟数据
- Prometheus和Grafana:收集指标并在仪表板上显示,可以查看延迟、GPU使用率、每秒请求数和Pod数量
- 自动扩缩容:保留基于CPU的HPA进行基本扩缩,同时添加KEDA(Kubernetes事件驱动自动扩缩),基于Prometheus查询扩缩Pod
启动和清理
云资源需要成本,GPU节点即使在空闲时也很昂贵。编写了两个脚本:
startup.sh 设置所需的一切:
- 创建包含CPU和GPU节点池的集群
- 安装NVIDIA设备插件
- 安装Prometheus、Grafana和用于GPU指标的DCGM导出器
- 在rtc命名空间中部署WebRTC应用
teardown.sh 清理资源:
- 删除WebRTC应用和命名空间
- 移除Prometheus和Grafana
- 删除GPU池和集群
- 检查残留的负载均衡器、IP和磁盘
部署WebRTC应用
简化的部署配置如下:
|
|
监控延迟
CPU图表不够用,需要查看用户实际体验的指标——延迟。
使用Prometheus抓取应用的/metrics端点,使用NVIDIA DCGM导出器跟踪GPU使用率。Grafana仪表板可以一起查看所有信息。
仪表板包含四个关键面板:
- p95延迟——95%的请求比此值更快
- 每秒请求数——显示流量水平
- GPU使用率——检查GPU工作强度
- Pod副本数——确认扩缩操作
主要的PromQL查询p95延迟:
|
|
基于延迟的自动扩缩容
真正的能力来自基于延迟的自动扩缩容。
标准基于CPU的HPA:
|
|
使用KEDA,设置基于延迟的扩缩规则:
|
|
这意味着如果p95延迟超过200毫秒,就进行扩展。
CPU vs GPU vs 自动扩缩容:实时扩缩容的权衡
在测试中,比较了三种设置:
| 设置 | 描述 | 性能 | 成本 | 最佳使用场景 |
|---|---|---|---|---|
| 仅CPU | 标准GKE节点上的默认Pod | 中等延迟(负载下约400毫秒) | 低 | 小型群组或低并发 |
| GPU启用 | 使用NVIDIA T4 GPU节点池 | 稳定延迟(负载下约150毫秒) | 高 | 重视频工作负载(编码、过滤器、ML) |
| 自动扩缩容(KEDA) | 基于延迟或队列指标扩缩 | 动态——仅在需要时增长 | 中等 | 突发流量、可变负载 |
关键发现:
- 仅CPU可预测但有限
- GPU启用以更高成本提供流畅的实时视频
- 自动扩缩容在延迟上升时通过使用额外的Pod或GPU节点来平衡两者
经验教训
- 节点选择器问题:正确的标签是
cloud.google.com/gke-accelerator: nvidia-tesla-t4 - 插件URL:正确的NVIDIA插件链接是
https://raw.githubusercontent.com/NVIDIA/k8s-devule-plugin/main/deployments/static/nvidia-device-plugin.yml - GPU配额:项目最初没有GPU配额,需要按区域请求配额
- 成本:GPU节点昂贵,安全的启动默认值和清理脚本可防止意外运行
- 集群操作重叠:GKE可以在另一个操作运行时阻止新节点池创建
- 待处理Pod调试:如果Pod保持待处理状态,请检查Events部分
最佳实践
- 基于延迟SLO而非仅CPU进行扩缩
- 收集反映用户感受的指标:延迟、抖动、帧丢失
- 使用Prometheus和Grafana提高可见性
- 使用脚本自动化基础设施设置/清理
- 在构建前检查GPU配额
结论
扩展WebRTC不仅仅是添加Pod,而是为用户保持通话流畅。
通过Docker化工作负载、GKE、GPU节点、Prometheus监控和KEDA自动扩缩容,可以:
- 基于延迟而非仅CPU进行扩缩
- 在负载下保持用户通话稳定
- 使用启动和清理脚本控制成本
用户不关心系统图表,他们关心正常工作的视频和音频。通过此设置,扩缩容与最重要的因素保持一致——通话另一端的体验。