去年我负责为一个交易平台做实时监控仪表盘。需求是:以百万事件/秒的速率可视化市场数据,从事件发生到用户屏幕的延迟要低于 100ms。
这把我们过去对数据可视化的认知全打破了。
「实时」的真相
没人会告诉你的是:「实时」往往并不是真正的实时。而且很多时候这没问题。
大多数标着「实时」的仪表盘其实是每 5–30 秒刷新一次。对多数场景这已经够用。但当你真的需要亚秒级更新时,规则就完全变了。
「实时」的三个层级
层级 1:近实时(5–60 秒刷新)
典型场景:业务仪表盘、营销分析、销售指标
架构:轮询 API、批量聚合
复杂度:中等
这是大多数人需要的:数据团队每分钟聚合一次,仪表盘轮询更新,简单有效。
层级 2:实时(1–5 秒刷新)
典型场景:运维监控、实时活动追踪、客服队列
架构:WebSocket、服务端推送、流式查询
复杂度:高
从轮询到推送,一切都不一样了:要维护长连接、处理重连、管理客户端/服务端状态。
层级 3:亚秒级(小于 1 秒)
典型场景:交易平台、实时游戏统计、工业监控
架构:流式管道、专用数据库、优化渲染
复杂度:很高
我们在这个层级待了 8 个月,每一处优化、每一毫秒都算数。
实时可视化难在哪
问题 1:数据量
每秒 100 万事件时,不可能逐条渲染——那是每秒 100 万个点,浏览器会崩。
做法:预聚合。不要把原始事件推到前端,在源头按时间桶做均值、计数、分位数等聚合。我们每秒只发 10 次聚合结果,而不是 100 万条原始事件。
问题 2:渲染性能
即使每秒只有 10 次更新,整图重绘也会拖垮性能。React 的调和、SVG 操作、Canvas 重画都会叠加。
做法:增量更新。不要重建整张图,只追加。我们对最高频的图用了基于 WebGL 的渲染,可以稳定跑 60fps 更新。
问题 3:人眼与认知
一个反直觉的结论:更新快于约 200ms 就会糊成一片。用户处理不了 10+ fps 的信息,只会觉得在闪。
做法:视觉平滑。即使数据是 10Hz 更新,我们把过渡动画拉长到 200ms,图表既「活」又不乱。
问题 4:网络不稳定
WebSocket 会断、包会延迟、移动端会切网。
做法:可靠重连、消息队列、优雅降级。断线时展示上次已知状态并显示「重连中」,而不是白屏。
我们用的架构
满足「百万事件/秒」的大致技术栈是:
数据层
- Apache Kafka 做事件接入
- Apache Flink 做实时聚合
- Redis 做最新状态缓存
- TimescaleDB 做历史查询
API 层
- Go 写 WebSocket 服务(高并发友好)
- gRPC 做内部服务通信
- 消息批量发送(每 100ms 发一批,而不是每个事件一发)
前端
- React 负责 UI 结构
- WebGL(通过 regl)做高频图
- 轻量 Canvas 做中频图
- SVG(通过 D3)只用于低频、强交互的图
关键决策
- 尽量早聚合:前端应拿到「可直接展示」的数据,而不是原始事件。
- 区分更新频率:不是每个元素都要 10fps,静态上下文可以 30 秒一更。
- 让用户选粒度:在「总览」(更新慢、信息多)和「明细」(更新快、视野集中)之间可选。
性能优化
服务端
- 预计算时间桶,别让客户端算「最近 5 分钟」
- 增量编码:只发变化量,不发全量
- 压缩:对 WebSocket 消息做 gzip,效果明显
- 连接复用:多订阅共享连接
客户端
- 对象池:复用图表元素,减少 GC
- 用 RequestAnimationFrame 把更新对齐到浏览器渲染
- Canvas 分层:静态一层、动态一层
- Web Worker:在主线外解析入站数据
不推荐
- 用 SVG 做高频更新(DOM 太慢)
- 用 Redux 管实时状态(更新太频繁时开销大)
- 用通用图表库做 >5fps(大多没为这类场景优化)
实时场景的 UX 教训
教训 1:把控制权交给用户
不是所有人都想要实时刷新,有人会觉得干扰。我们加了:暂停按钮、更新频率选择(1 秒 / 5 秒 / 30 秒)、历史模式(「显示 5 分钟前的状态」)。
教训 2:状态要一目了然
用户需要知道:当前是实时还是历史?上次更新是什么时候?连接是否正常?
我们加了一个随每次更新脉动的「心跳」指示,对安心感帮助很大。
教训 3:处理好「无聊」状态
大部分时间没有异常,图表只是用相近的值在更新。
这时要靠标注:「14:32 检测到尖峰」把注意力引到有意义的变动上,否则用户面对的是噪音。
教训 4:移动端要区别对待
屏幕小、网络差、要省电。移动端应:自动降低更新频率、简化图表、加强重连逻辑。
何时不必做「实时」
做完这套系统后,我对「实时」需求更谨慎了。要先问:
- 更快更新会改变用户行为吗?
- 用户真能在那幺快的节奏下行动吗?
- 工程成本值吗?
对多数仪表盘,答案是否定的。15 秒刷新往往就够了,把「实时」留给「秒级真的重要」的场景。
工具与资源
层级 1–2(近实时、实时):
像 ChartGen 这类工具可以生成能有效轮询 API 的图表,配合 WebSocket 接口就能做出不错的实时仪表盘,无需自建整套基础设施。
层级 3(亚秒级):
需要专门方案:D3 + Canvas、自研 WebGL、或 uPlot、Apache ECharts 的增量更新模式等。
流式基础设施可选:
- Apache Kafka + Flink(复杂但强大)
- AWS Kinesis + Lambda(托管但有限)
- Redis Streams + 自研聚合(简单但扩展性较弱)
如何监控实时系统
我们关注:端到端延迟(事件时间戳到像素上屏)、连接健康(每小时重连次数)、渲染性能(帧率)、用户参与(是否真的在看实时视图)。
一个发现:很多人打开仪表盘看两分钟就切到后台,「实时」数据大多没被看到。
最后一点
实时可视化既是工程挑战,也是 UX 挑战。最难的不是把数据尽快送到屏幕,而是以人类能理解和行动的方式呈现。
在做实时之前先问:用户有了更快的数据,到底会多做哪一步?
如果答案不清楚,可能根本不需要实时。


