跳转到主要内容
采样决定了有多少真实用户数据会被采集上报。采样率设置过高会带来不必要的数据量与费用,设置过低则可能漏掉关键问题。本文介绍 RUM 采样的工作机制,并给出选择和动态管理采样率的最佳实践。

采样是什么

RUM SDK 通过 sessionSampleRate 参数控制采样,取值 0 到 100,表示被采集的会话百分比:
被采样命中的会话会上报全部数据(页面浏览、资源、错误、用户行为等);未命中的会话不上报任何数据——包括错误。这是理解采样的第一个关键点:采样率 20% 意味着线上 80% 的用户出了错,您在平台上是看不到的。 sessionReplaySampleRate 是在已采集会话基础上的二次抽样:sessionSampleRate: 20 且 sessionReplaySampleRate: 10 时,实际有会话重放录制的会话占全部流量的 2%。

采样的工作规则

理解以下四条规则,可以避免绝大多数「为什么配了采样率但行为不符合预期」的困惑。

1. 以会话为单位,而不是用户或事件

采样判定发生在会话开始时:SDK 按 sessionSampleRate 的概率决定该会话是否采集:命中则整个会话完整上报,未命中则整个会话完全静默。不存在「一个会话里 20% 的事件被上报」这种情况——会话数据要么完整,要么没有。 同一个用户今天的会话可能中签、明天的会话可能不中签。默认的采样机制不锚定具体用户。

2. 判定结果在会话内粘滞

抽签结果会随会话状态持久化(Web 端存储在 Cookie 中)。会话在用户持续活跃时最长保持 4 小时,不活跃 15 分钟后过期;期间用户刷新页面、跳转页面都不会重新抽签。只有会话过期后产生新会话时,才会按当时的采样率重新判定。
这意味着修改采样率后,新会话立即按新采样率判定,存量会话维持原判定直到自然过期。这正是渐进放量的正确语义,但也意味着调整不是瞬时全量生效的。

3. 是概率,不是精确配额

每个会话的抽签相互独立,没有全局协调。采样率 20% 表示期望值是 20%:流量越大,实际采集比例越接近 20%(大数定律);流量较小时会有明显波动,100 个会话实际采到 13 个或 28 个都是正常的。

4. 采样率在会话抽签时确定

每个新会话抽签时,SDK 使用当时生效的采样率:开启远程配置后是控制台下发的值,否则是 init() 传入的 sessionSampleRate。页面或 App 运行期间不能二次 init();未开启远程配置时,改变采样率需要让下一次初始化(Web 端即下一次页面加载)拿到新的值。

如何选择采样率

错误是低频事件。如果您的核心诉求是错误监控而非性能统计,宁可选择更高的采样率——性能指标 20% 的样本足够代表整体,而某个只影响 1% 用户的错误在 20% 采样下可能很久才出现一次。

最佳实践一:用远程配置动态调整采样

采样率写死在代码里,每次调整都要发版。开启远程配置后,您可以在控制台 应用管理 → 远程配置 页签修改采样参数并发布,客户端无需改代码、发版即可生效。典型用法:
  • 新版本发布期临时调高会话采样率,稳定后降回常规值。
  • 线上故障排查时调到 100,尽可能多地捕捉现场。
  • 数据量异常上涨时调低,必要时调到 0 紧急关停采集。
  • 调低采样率的同时开启错误会话补充采集,未抽中的会话报错后仍会补报现场,见最佳实践三。

开启方式与各端支持

在 SDK 初始化时开启 remoteConfigurationEnabled: true(默认关闭)。Android 与 HarmonyOS 为 .setRemoteConfigurationEnabled(true),Electron 在主进程的 init() 中开启。初始化时传入的 sessionSampleRate 仍要保留:客户端首次拿到配置前、或控制台停用远程配置后,SDK 使用这个值。 各端读取的配置项不同,表中未列出的配置项在该端不生效: React Native SDK 不支持远程配置,采样率只能在 init() 中设置。

生效时机

  • 下一个新会话生效:SDK 在启动时和每个新会话开始时请求配置,新配置用于下一次抽签,进行中的会话维持原判定(规则 2)。客户端通常在发布后约 4 小时内完成切换。
  • 本地缓存:配置保存在本地,下次启动(Web 端为下次页面加载)的第一个会话直接按它抽签。Web 端本地还没有配置的页面(如首次访问、隐私窗口)会在开始采集前等待配置,通常约 1 秒(后台标签页可能更久);配置未及时到达或请求失败时,首个会话按 init() 中的配置抽签。等待期间的未捕获错误与控制台错误不会被采集。
  • 请求失败不改值:请求失败、超时或响应无法识别时,SDK 沿用当前生效的配置。
以下变化不等会话自然过期,SDK 会立即结束当前会话,下一个会话按新配置抽签:
  • 会话采样率调为 0(紧急关停),或从 0 调回非 0(重新开启)。
  • Web 端把回放脱敏级别调得更严格。
其余变化需要等下一个新会话。确需立即生效时,可以调用 SDK 的 stopSession() 结束当前会话。
stopSession() 会把一个用户的连续行为切分成两个会话,导致会话数轻微膨胀、会话时长统计断开。只在确需立即生效时调用。

确认配置已生效

发布后,在 远程配置 页签的发布面板查看采用情况,它按最近到达的会话统计各配置版本的占比。状态长时间停在「未收到配置」,通常是 SDK 未开启远程配置,或版本低于上表要求。发布、回滚与采用情况的详细说明见 应用管理 - 远程配置。

最佳实践二:业务自定义采样

默认的随机抽签对所有用户一视同仁,但业务往往希望差异化:VIP 用户全量采集、灰度用户重点观察、正在排查的用户必采。SDK 提供以下接口,让业务代码决定每个会话的采样率: 把规则参数(名单、开关、分桶盐值)放进远程配置的自定义配置项,就能在控制台动态下发:改名单、开排查模式都无需发版,并按生效时机在下一个新会话生效。例如在控制台发布如下自定义配置项:
下面的示例按优先级依次判断:排查模式与重点用户全量采集,其余用户按用户 ID 哈希分桶,桶的大小直接取控制台下发的会话采样率。
Flutter、HarmonyOS 与微信小程序提供同样的 beforeSampling、getRemoteConfig() 与 setForcedSession(),用法见各端高级配置文档。Electron 与 React Native SDK 没有 beforeSampling,可以在 init() 前自行判定,再把 sessionSampleRate 设为 0 或 100。 客服或研发需要临时排查某个用户时,除了把用户加进 debugUsers,也可以在业务代码里直接调用 setForcedSession(),例如在用户提交反馈时:

为什么用哈希分桶代替随机数

底座规则用 hash(userId) % 100 而不是 Math.random(),带来两个默认抽签没有的性质:
  • 用户级稳定:同一个用户的判定结果永远一致,您可以回答「用户 A 有没有数据」——中签用户的所有会话都在,未中签用户则明确没有。
  • 放量单调:采样率从 20% 调到 100% 时,原本中签的用户全部继续中签,新增的是纯增量,前后数据连续可对比。换一个 salt 即可整体重新洗牌。

注意事项

  • 回调必须轻量、确定。beforeSampling 在会话创建过程中同步执行,不能发起网络请求或阻塞;同样的输入应返回同样的结果。用 Math.random() 现抽会让同一用户的判定忽上忽下,确定性哈希天然规避这个问题。返回 0–100 以外的值或抛出异常时,SDK 沿用传入的采样率。
  • 规则变化在下一个新会话生效。用户从「不采」桶进入「采」桶后,进行中的会话不会被重新判定;需要立即生效时调用 setForcedSession() 或 stopSession()。
  • 自定义配置项对外可见。它会下发到客户端,任何持有 Client Token 的人都能读到,请勿在其中存放密钥、访问令牌或个人敏感信息。debugUsers 这类名单只放不可反推身份的用户 ID。
  • 用 sessionSampleRate: 0 而不是跳过 init()。跳过初始化会让业务代码里的 addAction / addError 等调用失效,到处判空很繁琐;传 0 让 SDK 正常初始化为静默状态,代码路径统一。
  • 平台侧数据代表实际采集量。自定义采样时,平台无法感知您的真实采样比例,看到的会话量即实际采集量,无法按采样率反推全量流量。如需估算全量,请在业务侧基于自己的采样规则换算。

最佳实践三:错误全量采集,其余数据按比例保留

从 Web SDK 0.3.0 起,可直接开启 sessionOnError(需要异常回放时同时开启 sessionReplayOnError)实现异常会话补采,无需自行编写 beforeSend;配置、计费和限制见异常会话补采。下文保留旧版或需要自定义事件过滤的方案;其中保留失败请求的逻辑与新版开关不同,单独的失败资源事件不会触发异常补采。
一个常见的诉求是「把数据量降到 20%,但异常一条都不能漏」。直接把 sessionSampleRate 设成 20 做不到:采样以会话为单位,未命中的会话连错误也不上报(规则 1),异常会同步丢掉八成。下面的自定义过滤方案通过会话全量采集保证错误不漏,再在 beforeSend 里按稳定 key 分桶,只让中签的那部分保留完整数据:
  • 错误事件:全部保留,异常 100%
  • 失败的请求:全部保留,接口报错 100%(HTTP 5xx 与请求失败是资源事件,不是错误事件)
  • 成功的请求、用户行为、长任务:只保留中签的 20%,数据量的大头按 20% 收敛
分桶方式二选一,下面两个 Tab 各自是完整可抄的方案,先对照下表选定一种: 另外,如果接入了会话重放,还需要一步对齐:原生语义下重放是已采集会话之上的二次抽样,而本方案把 sessionSampleRate 设成了 100,SDK 会以为每条会话都被完整采集,从而在全部会话上抽回放——其中一部分落在细节分桶之外,表现为「有回放,却没有行为数据」。两个 Tab 里各自给出了对应的对齐做法,不用重放可以跳过。
数据采样的完整配置:
重放对齐:会话 ID 在 init() 之前还不存在,而重放采样率在初始化时就固化了,所以要关掉自动抽签、改用手动录制,初始化完成后自行做第二层抽样。把下面两个选项并入上面的 init(),并在 init() 之后执行一次判定:
手动录制方案有一个已知边界:会话在页面存活期间过期续期后(不活跃 15 分钟或持续 4 小时),新会话是新的 ID、落进新的桶,需要重新判定一次,而 SDK 没有暴露会话续期事件。长时间停留的页面若要严格对齐,需自行轮询 getInternalContext().session_id 的变化。
两种做法下,回放集合都严格是细节分桶的子集,最终录制比例是 DETAIL_SAMPLE_RATE × REPLAY_SAMPLE_RATE——与原生的 sessionSampleRate: 20 + sessionReplaySampleRate: 10 得到 2% 完全一致。
务必保留 rum_sampling 这类标记。 未中签的会话时间线天生是残缺的——只有视图、错误与失败请求。没有标记时,您在查看器里看到一条会话「没有任何点击」,无法判断是采样丢了还是用户真的没点。盖上标记后,缺失就有了解释:errors_only 的会话本就不含行为数据,而 full 的会话缺什么就是真的没发生。排查时先按 rum_sampling:full 过滤,就能只看完整现场。context 是 beforeSend 允许修改的字段,标记与丢弃决策写在同一个函数里,两者不会漂移。
必须按稳定的 key 分桶(会话或用户),不能用 Math.random() 逐事件抽签。逐事件随机在统计上是无害的——抽出来的是一份无偏样本,错误率、P75 这些聚合指标照样准确。问题出在排查单条会话的时候。设想一条会话依次产生了这些事件:进入商品页 → 点击「立即购买」 → 三个接口请求(其中下单接口返回 500) → 页面抛出异常。逐事件随机抽签后,错误与失败请求因为在白名单里被保留,而那个点击事件恰好没中签被丢掉。于是您在会话里看到的是:用户进了页面、什么都没做,然后接口失败并报错。真正的麻烦不是缺了一条数据,而是缺失的位置每条会话都不一样,且无法分辨——您看到会话里没有点击,无法判断是采样丢了,还是用户真的没点。会话从证据变成了不可信的证词。按稳定 key 分桶后,每条会话只有两种状态:中签的那部分现场完整,其余的明确只有错误与失败请求。两种都不会误导您。理由与哈希分桶一节相同。

使用前必须知道的三件事

  • 数据量不会精确降到 20%:视图事件是会话骨架,无法丢弃,仍按 100% 上报。实际收敛比例取决于资源与行为事件在您数据中的占比。
  • 绝对量指标需要换算:平台上会话数仍是 100%,但只有约 20% 的会话带完整数据。错误率、P75 这类比率与分位数指标不受影响(随机样本仍代表整体),但「资源请求总数」「点击次数」这类绝对量需要按 1 / 20% 换算。
  • 会话重放要单独对齐一次:本方案把 sessionSampleRate 设成了 100,SDK 就以为每条会话都被完整采集,于是在全部会话里抽回放。少了对应 Tab 里的对齐那一步,回放会落到分桶之外的会话上——录像有了,可那条会话里根本没有行为数据。
和「只上报错误」那种配置的区别:那种做法是把非错误数据整体关掉,适合只关心错误、不做性能分析的场景;本方案保留两成完整现场,适合既要异常不漏、又要保留性能与行为分析能力的场景。

各端支持情况

各端最低版本与读取的配置项见开启方式与各端支持。各端都可以调用 stopSession() 结束当前会话,让新采样率立即生效。

常见问题

严格意义上的「只上报错误」做不到——视图(view)事件是会话的骨架,无法关闭。但可以做到非常接近,思路是两个相互独立的开关叠加使用:
  • 采样率控制「哪些会话被采集」:以会话为单位,未命中的会话连错误也不上报(规则 1)。所以不能靠调低采样率来省量,那会同步丢掉错误。
  • 事件开关控制「每个会话采集哪些事件」:trackResources、trackLongTasks、trackUserInteractions、trackWebVitals 与采样无关,对每一个被采集的会话都生效。
因此「尽量只看错误」的正确配置是:把 sessionSampleRate 开到 100 保证错误不漏,再用事件开关把非错误数据压下去。资源事件通常是数据量的大头,收敛它的收益最明显。
不要直接设置 trackResources: false。 浏览器端的 HTTP 5xx 和请求失败不是错误事件,而是带 status_code 的资源事件——RUM 的错误事件只来自 JS 运行时异常、console.error、浏览器 Report API 和手动 addError。关闭资源采集会让接口报错在平台上完全消失,而这往往正是您最想看的那类「错误」。
推荐的做法是保留资源采集,用 beforeSend 只丢弃成功的请求:
使用前请了解这套配置的三个代价:
  • 视图事件仍会上报:每个页面至少一条,指标或事件计数变化时会节流更新,会话活跃期间每 5 分钟还有一次保活更新。这是无法消除的底噪,beforeSend 也无法丢弃视图事件。
  • 错误现场只剩堆栈:关闭 trackUserInteractions 后,您无法知道用户点了什么才触发的错误,排查效率会明显下降。
  • 链路追踪请求不受资源开关影响:命中 allowedTracingUrls 的请求即使关闭资源采集也仍会上报(标记为不索引,不计入数据量),因此流量并不会归零。
如果您的目标是「错误优先,但仍要保留现场」,请改用最佳实践三:错误与失败请求全量保留,其余数据按比例收敛,既压住数据量又留得下排查现场。