Stats API 与监控体系:getStats 接口设计、关键指标解读、性能分析工具链

大家好,我是你们这堂课的讲师。今天我们来聊聊 WebRTC 里一个特别实在的话题——监控。

说实话,我做了这么多年 WebRTC 开发,最怕的不是功能实现不了,而是线上跑得好好的,突然用户反馈说“卡了”、“黑了”、“没声音了”。这时候你怎么办?没有监控数据,你就像瞎子摸象。所以,Stats API 和监控体系,说白了就是你的“眼睛”和“耳朵”。

getStats 接口设计:你的第一把扳手

WebRTC 的监控入口,就是 RTCPeerConnection.getStats()。这个接口设计得挺巧妙,它不直接给你一个固定的数据结构,而是返回一个 RTCStatsReport 的 Map。每个 key 是一个字符串 ID,value 是一个 stats 对象。

我个人习惯,在建立 PeerConnection 之后,立刻挂一个定时器去拉取 stats。比如这样:

const pc = new RTCPeerConnection(configuration);
setInterval(async () => {
  const report = await pc.getStats();
  report.forEach(stats => {
    if (stats.type === 'inbound-rtp') {
      console.log(`SSRC: ${stats.ssrc}, 丢包率: ${stats.packetsLost}/${stats.packetsReceived}`);
    }
  });
}, 2000);

嗯,这里要注意:getStats() 返回的是一个 Promise,所以记得 await。我在项目中遇到过有人忘了 await,结果拿到的是一堆 undefined,排查了半天才发现是异步没处理好。

关键指标解读:别被数字骗了

拿到 stats 之后,怎么解读?我把它分成三类:

1. 传输层指标

指标名 含义 正常范围
bytesSent 发送的总字节数 持续增长
bytesReceived 接收的总字节数 持续增长
packetsLost 丢包总数 相对值 < 5%
roundTripTime RTT,毫秒 < 300ms

你想想看,如果 packetsLost 在 2 秒内从 0 跳到 100,那说明网络已经出问题了。但别只看绝对值,要看比例。我曾经遇到一个案例,用户说“视频卡”,我看丢包率只有 2%,觉得还好。后来发现是因为带宽不足,导致视频编码器自动降分辨率了。所以,丢包率低不代表体验好,还得看码率和分辨率的变化。

2. 媒体流指标

对于 inbound-rtpoutbound-rtp 类型的 stats,有几个关键字段:

  • framesPerSecond:帧率。低于 15fps 就会感觉卡顿。
  • framesDecoded / framesDropped:解码帧数和丢弃帧数。如果 framesDropped 持续增长,说明解码器跟不上。
  • jitter:抖动,单位毫秒。超过 50ms 就需要关注。
  • totalAudioEnergy:音频能量。可以用来检测是否静音。

这里有个坑:jitter 是接收端计算的,它反映的是网络抖动的平滑值。但如果你看到 jitter 突然飙升,不一定就是网络问题,也可能是发送端码率突变。我建议把 jitter 和 RTT 放在一起看,如果 RTT 也同步升高,那基本可以确定是网络问题。

3. 编解码器指标

codec 类型的 stats 里,你可以看到当前使用的编码器、解码器,以及它们的配置。比如:

{
  "type": "codec",
  "mimeType": "video/VP8",
  "clockRate": 90000,
  "channels": null,
  "sdpFmtpLine": "max-fs=3600;max-fr=30"
}

这个信息有什么用?我举个例子。有一次线上反馈说部分用户视频花屏,排查后发现是 VP8 编码器的 max-fs 设置太小,导致大分辨率画面被截断了。通过 stats 确认了编码器配置后,我们调整了 SDP 协商参数才解决。

性能分析工具链:从数据到决策

光有数据还不够,你得有一套工具链来分析和展示。我个人习惯用这三层:

第一层:实时仪表盘

在 Web 端,我通常会写一个 overlay 层,把关键指标实时显示出来。比如:

  • 当前帧率、码率、丢包率
  • RTT 和 jitter 的折线图
  • 音频能量条

这样在调试时,一眼就能看出问题。我曾经在调试一个多人会议时,发现某个用户的音频能量一直为 0,结果发现是他的麦克风权限没给。这种问题,没有实时仪表盘根本发现不了。

第二层:日志采集与上报

生产环境不能一直开着仪表盘。我会把 stats 数据按一定频率(比如每 5 秒)采集一次,加上时间戳和用户 ID,上报到后端。格式可以简单点,比如 JSON 数组:

[
  {
    "timestamp": 1700000000000,
    "userId": "user_123",
    "stats": {
      "inbound-rtp": { ... },
      "outbound-rtp": { ... },
      "candidate-pair": { ... }
    }
  },
  ...
]

嗯,这里要注意:上报频率不要太高,否则后端扛不住。我建议在客户端做一次聚合,比如每 30 秒上报一次汇总数据。

第三层:离线分析平台

数据到了后端,就可以做离线分析了。比如:

  • 按时间段统计平均丢包率
  • 按地区统计 RTT 分布
  • 按版本统计崩溃率

这些分析能帮你发现一些隐藏问题。我记得有一次,我们发现某个地区的用户丢包率特别高,排查后发现是那个地区的 CDN 节点配置有问题。如果没有离线分析,这种问题可能要等用户投诉了才知道。

知识体系总览

下面这张图,是我梳理的 Stats API 与监控体系的核心逻辑。你可以看到,从 getStats 接口出发,数据流向三个方向:实时调试、日志采集、离线分析。每个方向都有对应的工具和指标。

Stats API 与监控体系核心逻辑 getStats() 接口 实时仪表盘 日志采集与上报 离线分析平台 帧率 / 码率 / 丢包率 RTT / Jitter 折线图 JSON 格式 + 时间戳 每 5 秒采集 / 30 秒上报 按地区 / 版本统计 平均丢包率 / RTT 分布 从数据采集到决策,三层工具链缺一不可

核心观点:监控不是事后诸葛亮,而是事前预防针。把 stats 数据用好,你能在用户投诉之前发现问题。

小技巧:在开发阶段,把 getStats 的结果打印到控制台,用 console.table() 格式化显示,比看 JSON 对象直观得多。

注意:getStats() 在频繁调用时会有性能开销。我建议在线上环境把采集间隔控制在 2 秒以上,不要低于 1 秒。

好了,这一章的内容就到这里。Stats API 是 WebRTC 监控的基石,掌握了它,你就能在复杂的网络环境中找到问题的根源。下一章我们会深入 PeerConnection 的状态机,看看连接建立和断开时到底发生了什么。


公众号:蓝海资料掘金营,微信deep3321