19、统计与监控:getStats API详解、关键指标采集、WebRTC-internals工具使用
做WebRTC开发,最怕什么?
我最怕用户说「视频卡了」,然后我这边啥数据都没有。两眼一抹黑,根本不知道是网络抖了,还是编码器抽风了。
所以这一章,咱们聊聊怎么给WebRTC装上「仪表盘」。说白了,就是getStats API、关键指标采集,还有Chrome自带的那个神器——WebRTC-internals。
19.1 getStats API:WebRTC的OBD接口
getStats API 是浏览器暴露给我们的底层数据接口。你可以把它理解成汽车的OBD接口——插上去就能读到发动机转速、水温、油压。
在WebRTC里,这个接口能告诉你:
- 发了多少包、收了多少包
- 丢包率是多少
- 延迟有多高
- 码率稳不稳
- 甚至CPU占用情况
调用方式很简单,但很多人用不对。我见过不少新手直接写:
peerConnection.getStats().then(stats => {
stats.forEach(report => {
console.log(report.type, report);
});
});
嗯,这样能跑,但拿到的数据太原始了。你想想看,几十个report对象堆在一起,哪个是你要的?
19.2 关键指标:到底该盯哪些?
getStats 返回的数据少说几十项,但真正需要关注的,其实就这几个:
| 指标 | 类型 | 说明 | 健康阈值 |
|---|---|---|---|
| packetsLost | inbound-rtp / outbound-rtp | 丢包数 | < 总包数的2% |
| jitter | inbound-rtp | 抖动(毫秒) | < 30ms |
| roundTripTime | candidate-pair | RTT 往返时间 | < 200ms |
| framesPerSecond | inbound-rtp / outbound-rtp | 帧率 | ≥ 15fps(视频通话) |
| bitrate | (计算得出) | 实际码率 | 接近目标码率 |
这里有个坑——bitrate 不是直接拿到的。getStats 返回的是 bytesSent 和 timestamp,你得自己算差值。
我曾经在项目里直接用了 bytesSent 的绝对值,结果画出来的码率曲线像心电图一样乱跳。后来才反应过来:要算 delta。
// 计算码率的正确姿势
let lastBytes = 0;
let lastTime = 0;
function calcBitrate(statsReport) {
const now = statsReport.timestamp;
const bytes = statsReport.bytesSent;
if (lastTime === 0) {
lastBytes = bytes;
lastTime = now;
return 0;
}
const deltaBytes = bytes - lastBytes;
const deltaTime = (now - lastTime) / 1000; // 转成秒
lastBytes = bytes;
lastTime = now;
return (deltaBytes * 8) / deltaTime; // bps
}
19.3 采集策略:别太频繁,也别太懒
getStats 调用本身不重,但如果你每秒拉100次,浏览器也会累。我个人建议:
- 常规监控:每1秒拉一次
- 问题排查:遇到丢包或抖动时,临时提高到每200ms一次
- 不要:在 oniceconnectionstatechange 等回调里直接调 getStats,容易造成回调风暴
我习惯用一个定时器,配合一个「降频」逻辑:
let pollInterval = 1000;
let timer = null;
function startStatsPoll(pc) {
timer = setInterval(async () => {
const stats = await pc.getStats();
processStats(stats);
// 如果发现丢包严重,自动提高采集频率
if (isPacketLossHigh(stats)) {
pollInterval = 200;
resetTimer();
} else {
pollInterval = 1000;
}
}, pollInterval);
}
说白了,就是让采集频率跟着网络质量走。网络差的时候多看看,网络好的时候少折腾。
19.4 WebRTC-internals:Chrome自带的调试神器
你不需要写一行代码,就能看到所有WebRTC连接的内部状态。Chrome浏览器里输入:
chrome://webrtc-internals
打开之后,你会看到一个实时更新的仪表盘。这里面有:
- 所有 PeerConnection 的完整状态
- ICE 候选者列表和连接检查日志
- RTP 流的收发统计
- 甚至还有 SDP 的完整文本
我记得有一次线上反馈说「视频偶尔黑屏」,我本地死活复现不了。后来让用户打开 webrtc-internals,截图一看——inbound-rtp 的 framesDecoded 突然归零,但 packetsReceived 还在涨。这说明解码器崩了,跟网络没关系。直接定位到是 H.264 编码兼容性问题。
19.5 知识体系总览
下面这张图,是我自己梳理的统计监控知识结构。你可以把它当成一个检查清单:
19.6 避坑指南:我踩过的几个坑
做统计监控这几年,我踩过不少坑。挑几个典型的说说:
- 坑一:getStats 在旧浏览器里是 callback 风格。 我一开始全用 Promise,结果在某个 Chrome 72 上直接报错。后来加了兼容判断。
- 坑二:stats 对象的 id 不是固定的。 每次调用 getStats,某些对象的 id 会变。你不能用 id 做持久化缓存。
- 坑三:别在 worker 线程里调 getStats。 PeerConnection 必须在主线程创建,getStats 也一样。我试过用 OffscreenCanvas 绕,不行。
- 坑四:webrtc-internals 的数据是「最终一致性」的。 有时候你看到丢包率 50%,但过两秒就变成 5% 了。别慌,等几秒再看。
嗯,统计监控这块,说白了就是给WebRTC装上「黑匣子」。平时不显眼,但出了问题,它就是你的救命稻草。别等到用户投诉了才想起来加,那时候就晚了。