录一小时页面要多少数据?rrweb 增量快照的 3 个关键机制
【免费下载链接】rrwebrecord and replay the web项目地址: https://gitcode.com/gh_mirrors/rr/rrweb
录一个小时的用户操作,事件流常常超过 200MB,大头往往是鼠标移动和重复的样式文本。rrweb 的增量快照在全量快照之上只记「变了的部分」,能省多少取决于录制器内部的 3 个机制,本文按数据流向拆一遍,附配置对照和踩坑边界。
先弄懂它在做什么
一句话定义:第一次对整页做一次全量快照,之后只记录节点增删、属性变化、文本变化这类「差值」。类比搬进新房子:先做一次全屋盘点(全量快照),之后只记「桌子挪到了左边」,而不是反复给整个房间拍照。
上图来自仓库测试用例:回放一个视频页面。它不录视频流本身,只记录暂停、跳转这类媒体交互事件,回放器照样能精确 seek 到对应画面。你会发现,凡是能「记操作而不记内容」的媒体,都是增量快照省数据的主力。
拆开录制链路:3 个内部机制
id 是连接录制与回放的唯一坐标系
rrweb-snapshot里的 Mirror 给每个序列化过的节点分配一个自增 id,录制端和回放端共用这张表。「在 id=17 下加一个子节点」这类增量事件全靠 id 引用,回放端按 id 找到真实 DOM 节点。简单说就是:没有这张表,增量事件只是一串没有出处的数字。
缓冲层:攒批、去重,再统一序列化
浏览器的 MutationObserver 是攒一批变化再异步回调,rrweb 在其外面包了一层MutationBuffer(源码在packages/rrweb/src/record/mutation.ts)。回调不逐条落盘,而是先把变化收进缓冲再统一处理:新节点先进 Set 去重,父、子同批出现时只记一次;同一节点同一帧改了三次属性,只记最终值。小例子:一次循环往列表塞 10 行,朴素做法是 10 条 add 事件,缓冲层合并后通常更少。这一步是录制数据比「一变一条」实现小的主因。
交互事件在源头节流
DOM 变化有缓冲层,鼠标、滚动、输入则在源头节流:scroll走 throttle,默认 100ms 最多发一次;input: 'last'只监听change,不追每个按键。这两项直接决定事件流里高频事件的占比。
record({ emit(event) {}, sampling: { mousemove: false, scroll: 150, input: 'last', }, });降低数据量的配置项:何时开、何时别开
| 配置 | 作用 | 该开的时候 | 别开的时候 |
|---|---|---|---|
sampling.mousemove: false | 不录鼠标移动 | 只分析点击与页面流 | 需要展示光标轨迹 |
sampling.input: 'last' | 只记输入最终值 | 长表单、连续输入多 | 要复现逐字输入过程 |
blockClass: 'rr-block' | 跳过该子树内容 | 长列表、广告位、复杂 SVG | 子树里有关键操作 |
packFn: pack | 按事件 fflate 压缩 | 边录边传、单条落库 | 服务端会对 gzip 批量压缩 |
checkoutEveryNms | 周期性全量快照 | 长会话,防增量漂移 | 短时操作、数据量已高 |
pack来自@rrweb/packer,回放时把unpack传给unpackFn即可:
import { pack } from '@rrweb/packer'; record({ emit(e) {}, packFn: pack });docs/recipes/optimize-storage.zh_CN.md里还有一条建议:对 gzip 这类算法,在服务端把多个事件批量压一次,压缩比通常好于逐条压。
两个容易翻车的边界
- 全量快照丢了,整段事件流不可回放。增量事件里的 id 指向第一次全量快照建立的节点表,只存事件流中段的话 id 无所指,回放直接失败。分片存储时应以全量快照为分片边界。
- 屏蔽了滚动容器,回放页面「卡住不动」。
blockClass会跳过子树内的 DOM 变化,但滚动事件仍引用被屏蔽节点的 id;回放时该节点不存在,对应区域的滚动就丢失。屏蔽前先确认子树内是否有滚动或交互事件。
下一步:读一遍packages/rrweb/src/record/mutation.ts里的MutationBuffer,对照本文的「缓冲、去重、序列化」流程逐段看,存储调优策略汇总在docs/recipes/optimize-storage.zh_CN.md。
【免费下载链接】rrwebrecord and replay the web项目地址: https://gitcode.com/gh_mirrors/rr/rrweb
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考