news 2026/10/30 4:41:15

从40MB到几MB:rrweb增量快照机制与录制数据压缩实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从40MB到几MB:rrweb增量快照机制与录制数据压缩实战

从40MB到几MB:rrweb增量快照机制与录制数据压缩实战

【免费下载链接】rrwebrecord and replay the web项目地址: https://gitcode.com/gh_mirrors/rr/rrweb

第一次用 rrweb 录一段 3 分钟的操作会话,你拿到的可能是一个 40MB 的 JSON 文件。原因并不神秘:全量快照把整页序列化进了一帧、滚动事件每秒几十条、同一份样式表被一遍遍内联进数据里。增量快照机制要解决的正是这件事——全量快照只取一次初始状态,之后只记录差异,再叠加节流、压缩与屏蔽,把体积压到可接受的量级。

先摸清录制数据的体积来源:全量快照是固定成本,增量快照是浮动成本

全量快照:整棵树序列化一次,样式表尽量内联

录制开始时,rrweb 会把整棵 DOM 树序列化成树状结构:元素、文本节点、注释节点都有记录;script 标签被替换为 noscript,内部内容不再保留;相对路径在录制端就转成绝对路径;同源页面能读到的样式表则被解析成 CSS 规则后内联进数据,保证内网环境下回放也有完整外观。对一个中等规模的业务页来说,这笔"固定成本"可能就是几 MB。录长会话时 rrweb 还会用checkoutEveryNms定期再出一帧全量快照,这笔成本会沿时间线重复出现。

增量快照:随用户操作强度线性增长

全量快照之后,rrweb 持续发出增量快照事件,覆盖 DOM 节点增删、属性与文本变化、鼠标和触摸交互、页面或元素滚动、视窗尺寸变化、输入内容、canvas 调用等类型。这类事件的体积和操作强度成正比:用户 1 分钟不停拖滚动条,滚动事件最多 60 条/秒 × 60 秒 = 3600 条,每条几百字节。不做节流,单是滚动就能贡献几十 MB。

用 id 替代节点引用:增量快照如何定位回放端的同一个节点

mirror 是录制端与回放端同步维护的 id→Node 映射表

增量快照里只记一个数字。全量快照序列化时,rrweb 给每个节点分配自增的连续id,录制端和回放端各自维护一份 mirror(id→Node 映射表):节点创建时,录制端序列化并登记,回放端在同一时机重建对应节点并登记;节点销毁时,两端同步移除。这样一次点击只需记录id,回放时按表取节点派发事件,页面结构前后变化几十次也不会丢。序列化规则的细节见 docs/serialization.zh_CN.md。

批量异步回调:先收集去重新增节点,再对属性覆盖写

DOM 变动的监听基础是 MutationObserver——浏览器在"一连串变化发生后"把一批 mutation 记录打包回调,而不是一条一条实时推送。这对录制有两个直接影响:

  • 同一节点可能在不同记录里以不同顺序出现为"新增"(先挂父节点再挂子节点,与先拼好子树再整体挂载,产生的记录不同),所以 rrweb 遇到新增节点不立即序列化,而是先收集,等本批记录全部处理完再去重,然后统一序列化;
  • 同一次回调里创建又被移除的节点(dropped node)不写入数据,去重新增节点时也会跳过其父节点。

属性变化则用覆盖写:拖动 textarea 调整大小时会刷出大量 width、height 变更,同一次回调里只保留该节点该属性的最终值。更完整的处理逻辑见 docs/observer.zh_CN.md。

用 sampling 配置给高频事件设节留阈值

scroll 每 150ms 最多一条,输入只保留最终值

sampling是录制入口的节流开关,效果最直观的是滚动和输入:

import { record } from '@rrweb/record'; record({ emit(event) {}, sampling: { mousemove: false, scroll: 150, input: 'last', }, });

scroll: 150表示每 150ms 最多一条滚动快照,滚动事件从每秒 60 条降到约 7 条。input: 'last'在连续输入时只保留 change 事件里的最终值,打 20 个字只产生 1 条事件。mousemove: false则整体关掉鼠标移动录制——回放里没有鼠标轨迹,体积少一个量级。mousemove 默认带节流,坐标按阈值记录、按批次发送,需要更细的粒度时可把sampling.mousemove改成数字调整记录阈值,mousemoveCallback调整批次间隔。

mouseInteraction 按事件类型逐项开关

sampling.mouseInteraction可以传对象做细粒度控制,比如{ MouseUp: false, Click: false, Focus: false },只关掉不需要的那几类交互,其余照常录制,不用一刀切。

用 pack 压缩单条事件,把批量压缩留给服务端

pack:基于 fflate 的事件级 zlib 压缩

录制数据高度同质,天然适合压缩。@rrweb/packer提供的pack用 fflate 的 zlibSync 把每条事件压缩成 base64 字符串(事件上会追加v: MARK版本字段),回放时把unpack传给 Replayer 的unpackFn即可还原:

import { pack } from '@rrweb/packer'; record({ emit(event) {}, packFn: pack, });
import { unpack } from '@rrweb/packer'; import { Replayer } from '@rrweb/replay'; const replayer = new Replayer(events, { unpackFn: unpack, });

为什么服务端批量 gzip 更划算

单条事件逐个压缩,每条数据量太小,冗余发挥不出来。更推荐的做法是把多次事件的批量压缩放到服务端:例如把一次用户操作产生的所有事件打包,用 gzip 类算法对长文本压缩,比率更高,存储对象数量也更少。

从录制入口减大数据量:blockClass 与样式表去冗

长列表、canvas、复杂 SVG 加 rr-block 跳过

record的blockClass默认值是'rr-block':带这个类名的元素及其子树不会被录制。长列表、canvas 动画、复杂 SVG、JS 驱动的动画元素是数据量大户,回放里它们会呈现为空白容器——演示型录制中这笔取舍通常划算。不想改页面代码时,可以用blockSelector传 CSS 选择器达到同样效果。

把内联样式表抽出来,只存一份

为了 hover 等效果,rrweb 会把样式表尽量内联进录制数据。反面是:录同一站点多个用户的访问时,同一份规则会被存很多遍,叠加周期性全量快照后重复更明显。可以在服务端遍历数据,把样式表内容抽出单独存一份,原位改为引用。更多策略说明见 docs/recipes/optimize-storage.zh_CN.md。

下次录制前,先做这五件事

一份可直接照做的清单

  • 先录一段 3 分钟真实会话,统计各事件类型的条数与字节数,找出体积大头
  • 高频事件按sampling.scroll: 150、input: 'last'、mousemove: false节流
  • 录制端加packFn: pack,回放端配unpackFn: unpack
  • 长列表、canvas 等元素挂上rr-block类名
  • 服务端对内联样式表做提取去冗

【免费下载链接】rrwebrecord and replay the web项目地址: https://gitcode.com/gh_mirrors/rr/rrweb

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/30 4:29:58

AI智能体运行状态异常监控告警实现方案

AI智能体运行状态异常监控告警实现方案# AI智能体运行状态异常监控告警实现方案 一、文档概述 1.1 业务背景 随着大模型驱动的AI智能体在自动化任务调度、智能问答、数据处理、流程执行等场景规模化落地,智能体离线卡死、推理超时、接口调用失败、资源占用过载、任务…

作者头像 李华
网站建设 2026/10/30 4:29:41

CSV 游标流式导出

推荐:方案 A — CSV 游标流式导出核心思路:不一次性加载,MySQL 游标分批取 → 写一行 → flush → 释放 → 下一批。while (true) {SELECT ... WHERE id > $lastId LIMIT 5000; ← 只取 5000 行│foreach → fputcsv($fp) …

作者头像 李华
网站建设 2026/10/30 4:25:04

Unitto时区换算工具使用指南:跨时区开会再也不算错时间

【免费下载链接】unitto 😎 Superior Calculator and Converter 项目地址: https://gitcode.com/gh_mirrors/un/unitto 点击查看 免费下载 Unitto 是一款开源的计算器与单位换算应用,它内置的时区换算功能能实时对比全球任意时区的时间&…

作者头像 李华