高并发下WebSocket消息积压的核心是前端接收与处理能力失配,需从接收端节流、处理线程解耦、发送端协同三方面治理:用bufferedAmount+drain实现背压控制,计算任务移至Web Worker,safeSend封装动态降频,并以环形缓冲区替代Promise队列。

用 getBufferedAmount + drain 做实时背压感知
WebSocket 的 bufferedAmount 是唯一原生水位计,但它容易误读:
- 别在
send()后立刻查——此时消息可能还在 JS 队列里,值还是 0 - 推荐每 100ms 轮询一次,连续 3 次 ≥ 800KB(按实际带宽设阈值)就暂停发送
- 更稳的方式是监听
ws.on('drain', ...):它表示底层缓冲真正清空,这时恢复发送最准 - Chrome 对二进制帧统计不准,日常调试优先用文本帧验证逻辑
主线程必须卸载解析与计算任务
每秒上百条消息直接进 onmessage,再同步 JSON.parse + setState,60fps 渲染立刻崩。这不是 WebSocket 的锅,是线程绑太死:
- 把 JSON 解析、数据过滤、聚合统计这类纯计算任务,全挪到 Web Worker 里做
- Worker 只用
MessageChannel和主线程通信,传 ArrayBuffer 等 Transferable 对象,避免序列化开销 - 主线程收到 Worker 处理后的精简数据,再用
requestAnimationFrame批量更新 DOM,一帧最多处理一次视图刷新 - Worker 不得持有 WebSocket 实例,也不许调 console 或操作 DOM——否则反而拖垮性能
封装 safeSend + 动态降频策略
节流逻辑不能散落在业务代码里,统一收口:
- 写一个
safeSend(msg)方法,内部自动检查bufferedAmount - 超阈值时进入节流模式:首次延迟 100ms,失败则指数退避(100 → 200 → 400ms)
- 心跳、告警等高优消息走白名单通道,绕过节流,保证关键路径畅通
- 配合后端设置
maxBackpressure(如 1MB),并关掉closeOnBackpressureLimit,让前端掌握主动权
接收侧用环形缓冲区替代 Promise 队列
Promise.all 这类 HTTP 并发模型完全不适用 WebSocket 流式消息:
立即学习“Java免费学习笔记(深入)”;
- 不要把
ws.send()包进 Promise 链——会拉长发送间隔,导致心跳超时、连接被踢 - 接收端可用固定长度(如 64)的环形数组暂存消息,满时自动覆盖最老消息,防止内存失控
- 对不同消息类型做差异化节流:告警类立即处理,行情 tick 类可按 50ms 时间窗口聚合后再更新
- 页面切后台时,主动通知服务端降频(监听
visibilitychange),省资源也保连接


















