大模型服务的流量特征很极端:平时闲、峰值猛,一次对话的链路又长(网关、鉴权、提示词组装、向量检索、推理、后处理),单个 Segment 的 Span 数量可能是普通接口的几十倍。如果 100% 全量采集,SkyWalking 的探针 CPU、网络带宽、OAP 计算力和后端存储都会被迅速吃满,账单也会非常可观。采样(Sampling)就是在这个矛盾里找平衡:用最小的代价保留足够的排障信息。本文讲清楚 SkyWalking 的采样机制与在大模型场景的落地策略。

  1. 为什么必须采样:开销与成本的真实来源
  2. SkyWalking 的采样机制全景
  3. 实战:探针与 OAP 双层采样配置
  4. 大模型场景的采样策略设计
  5. 存储与 TTL 成本优化

1. 为什么必须采样:开销与成本的真实来源

一条链路从产生到可查询,要经历四道成本关:

  • **探针开销**:每个 Span 的创建、上下文维护、序列化都需要 CPU;大模型链路 Span 多,单请求探针耗时可能从微秒级升到毫秒级,会直接抬升接口 P99。
  • **网络开销**:探针把 Segment 批量上报给 OAP,全量上报在高并发下会打满网卡。
  • **OAP 开销**:OAP 要做拓扑聚合、指标计算、Trace 解析,数据量线性放大。
  • **存储开销**:Trace 原始数据落在 Elasticsearch / BanyanDB / TiDB,按数据量计费,且需要磁盘容量与索引。

以一个日活推理峰值 5000 QPS、平均每个对话 60 个 Span 的服务估算:全量采集每天产生约 260 亿个 Span 的写入压力。即便按 10% 采样,也能砍掉 90% 的存储与计算成本,而排障所需的「慢调用」「错误调用」样本依然充足。

因此采样的目标不是「少采」,而是「聪明地采」:保住有排障价值的样本(错误、慢调用、特定模型),丢弃无差异的海量正常样本。

2. SkyWalking 的采样机制全景

SkyWalking 的采样分布在两层:

**第一层:探针端采样(agent.sample_rate)**。探针在创建 Segment 的第一个 Span 时,按概率决定这条链路是否采集。一旦决定采样,整条链路(包括后续异步、跨进程的所有 Span)都会被采集;决定不采,则整条丢弃。这是成本最低的一层,因为它在源头就拦掉了数据。

**第二层:OAP 端采样(receiver-trace)**。即使探针全量上报,OAP 在接收端仍可按 `sampleRate` 二次丢弃。这一层通常用于「探针全采、服务端按策略收口」的集中管控场景。

除此之外还有三个「强制采样」开关,保证关键样本不被采样率误杀:

  • `force_sample_error_segment`:错误链路强制采样(默认 true)。
  • `slow_trace_segment_threshold`:超过该耗时的慢链路强制采样(毫秒)。
  • 错误与慢调用是排障的核心,务必保持强制采样开启。

采样率单位的坑:探针端 `agent.sample_rate` 是 0~1 的小数(1 表示 100%);而 OAP 端 `sampleRate` 是以「万分之一」为单位的整数(10000 表示 100%)。两者容易混淆,配置时要特别注意。

3. 实战:探针与 OAP 双层采样配置

探针端配置写在 `agent.config`,推荐用环境变量注入,便于按环境区分:

agent.service_name=${SW_AGENT_NAME:llm-inference}
collector.backend_service=${SW_AGENT_BACKEND:oap:11800}
agent.sample_rate=${SW_AGENT_SAMPLE_RATE:0.1}    # 采样率:日常 10%,压测/灰度可调高
agent.force_sample_error_segment=${SW_FORCE_SAMPLE_ERROR:true}   # 错误链路强制采集,永远不要关

 

启动命令通过环境变量覆盖,做到「测试环境全采、生产环境抽样」:

java -javaagent:/opt/skywalking/agent/skywalking-agent.jar \
     -DSW_AGENT_NAME=llm-inference \
     -DSW_AGENT_SAMPLE_RATE=0.1 \
     -DSW_FORCE_SAMPLE_ERROR=true \
     -jar inference-service.jar

 

OAP 端在 `application.yml` 的 `receiver-trace` 中配置服务端采样与慢调用强制采样:

receiver-trace:
  default:
    # 服务端采样率,单位 1/10000,10000 = 100%
    sampleRate: ${SW_TRACE_SAMPLE_RATE:10000}
    # 错误段强制采样
    forceSampleErrorSegment: ${SW_FORCE_SAMPLE_ERROR:true}
    # 慢调用阈值(毫秒),超过则强制采样
    slowTraceSegmentThreshold: ${SW_SLOW_TRACE_THRESHOLD:2000}

 

把 `slowTraceSegmentThreshold` 设成略高于你的大模型推理 P99(例如推理普遍 1.5s,可设 2000ms),这样凡是「比正常慢」的调用都会被保留,正好命中性能排查需求。

4. 大模型场景的采样策略设计

大模型链路不能简单「全局 10% 了事」,需要分层设计:

  • **错误全采**:`force_sample_error_segment=true`,推理失败、超时、降级都进链路,便于复盘。
  • **慢调用全采**:`slowTraceSegmentThreshold` 对齐业务 SLA,慢推理必留样。
  • **按端点区分**:健康检查、心跳类接口价值极低,可以单独调低甚至不采;核心对话接口保留更高比例。基础版的 `agent.sample_rate` 是全局的,要做到「按端点不同采样率」,需要自定义采样插件或借助 OAP 服务端按 endpoint 过滤(例如上游只把核心接口打到全采的探针分组)。
  • **按模型区分**:把 `modelName` 作为关联上下文(见第 06 篇),对昂贵的大模型(如 72B 推理)提高采样率,对轻量模型降低。
  • **压测期临时全采**:大促或压测前通过环境变量把 `SW_AGENT_SAMPLE_RATE` 调到 1,拿到完整链路做容量评估,结束再调回。

不同采样率下的成本与覆盖率直觉对比如下表:

采样率

存储/计算成本

错误捕获

慢调用捕获

适用阶段

---

---

---

---

---

100%

最高

全量

全量

测试、压测、灰度初期

50%

中高

全量(强制)

全量(强制)

上线观察期

10%

全量(强制)

全量(强制)

稳定生产环境

1%

极低

全量(强制)

全量(强制)

超大流量常态

注意表中「错误/慢调用」一列始终全量,正是因为强制采样开关的存在——这正是采样策略能「又省钱又不漏问题」的关键。

5. 存储与 TTL 成本优化

采样解决的是「写入量」,而 TTL(数据保留时长)解决的是「存量规模」。即便采了 10%,Trace 原始数据长期堆积仍会撑爆存储。SkyWalking 的存储 TTL 在 `application.yml` 的 `storage` 段配置:

storage:
  banyandb:
    # Trace 原始记录保留天数
    recordDataTTL: ${SW_RECORD_DATA_TTL:3}
    # 指标数据保留天数(拓扑/监控图表用)
    metricsDataTTL: ${SW_METRICS_DATA_TTL:15}

 

优化建议:

  • **Trace 原始数据 TTL 短(3~7 天)**:排障通常在发生后几天内完成,过长保留收益低。
  • **指标数据 TTL 长(15~30 天)**:趋势图、容量规划需要长期数据,且指标体积小。
  • **存储选型**:Elasticsearch 功能全但成本高;BanyanDB 是 SkyWalking 原生时序存储,针对 Trace 做了压缩,成本显著更低,大模型高吞吐场景首选。
  • **索引策略**:ES 下合理设置分片数与副本数,避免为历史索引长期占用资源。

不同存储的取舍如下表:

存储

成本

查询能力

适用

---

---

---

---

Elasticsearch

强,全文检索

已具备 ES 集群、需复杂查询

BanyanDB

中,原生优化 Trace

新部署、成本敏感、高吞吐

TiDB / MySQL

弱,适合小流量

小规模验证

6. OAP 采样内部原理与限流

理解采样在 OAP 内部怎么生效,有助于避免误配。OAP 的 `receiver-trace` 模块在收到 Segment 后,先判断是否命中采样:未命中的 Segment 直接丢弃,根本不会进入后续的拓扑聚合、指标计算与 Trace 存储流程。这意味着服务端采样不仅省存储,还省 OAP 的 CPU 与内存——这是它和「只删存储」最大的区别。

需要厘清一个常见误解:**错误强制采样发生在探针端,而不是 OAP 端**。当探针发现当前 Segment 包含错误 Span 或耗时超过 `slow_trace_segment_threshold` 时,会无视 `sample_rate` 强制标记为「采样」,并连带整条链路上报。因此即使你把 `SW_AGENT_SAMPLE_RATE` 设成 0.01,错误与慢调用依然 100% 进入 OAP。如果你发现错误链路也没了,第一反应应是检查 `force_sample_error_segment` 是否被误关,或探针与 OAP 版本不匹配导致字段解析失败。

此外,OAP 还有一层自我保护:当接收流量超过处理能力时,会通过内部缓冲与丢弃策略限流,避免被冲垮。这正是为什么生产环境更该在探针端就把采样率降下来——把压力挡在源头,比让 OAP 在入口限流更优雅。

7. 采样率选择的决策流程与成本估算

采样率不是拍脑袋定的,要基于流量与成本倒推。下面以一个典型大模型对话服务做估算(假设平均每次对话产生 60 个 Span,QPS 为对话请求数):

峰值 QPS

全量(100%)每日 Span 数

10% 采样每日 Span 数

1% 采样每日 Span 数

---

---

---

---

1000

约 52 亿

约 5.2 亿

约 5200 万

3000

约 155 亿

约 15.5 亿

约 1.55 亿

5000

约 260 亿

约 26 亿

约 2.6 亿

每个 Span 在 Elasticsearch 里索引后约占几百字节到 1KB(取决于 tag 数量与长度),26 亿 Span 就是 TB 级写入与存储。按 10% 采样,写入量与存储直接降到约十分之一,且错误与慢调用因为强制采样仍然 100% 保留——排障所需样本完全够用。

推荐的决策流程:

  1. **灰度/上线观察期**:`sample_rate=1`(100%),拿到完整链路做容量评估与基线建立。
  2. **稳定生产期**:降到 `0.1`(10%),配合 `force_sample_error=true` 与 `slow_trace_segment_threshold` 对齐 SLA。
  3. **超大流量常态**:可降到 `0.01`(1%),但必须监控错误/慢调用样本量是否足够定位。
  4. **压测/大促前**:临时调回 `1`,结束后调回。

核心原则:**正常流量可以少采,异常流量必须全采**。采样率只砍「无差异的正常样本」,不砍「有排障价值的异常样本」。

8. 监控采样效果与防错

采样配置一旦生效,要持续监控它「有没有在正常工作」,否则可能悄悄漏掉关键链路:

  • **监控采样后 Trace 数量**:若某服务的 Trace 列表突然为空,要么是 `sample_rate` 过低且恰好没有错误/慢调用,要么是探针没挂上。需结合指标(拓扑图 CPM)判断——拓扑有流量但 Trace 为空,就是采样或插桩异常。
  • **监控错误样本完整性**:定期检查错误链路是否仍 100% 出现。可以在测试环境主动制造一次错误请求,确认它一定出现在 Trace 列表里。
  • **告警联动**:把「错误 Span 数突增但 Trace 样本为 0」作为独立告警项,这比「接口变慢」更早暴露采样配置问题。
  • **版本一致性**:探针 `apm-toolkit-trace` 与 OAP 大版本必须一致。跨大版本升级 OAP 时,先升级 OAP 再升级探针,避免快照字段不兼容导致强制采样失效。

9. 多环境采样配置管理

采样率绝不能硬编码在 `agent.config` 里,否则测试环境全采、生产环境也全采,成本失控。正确做法是用环境变量或配置中心按环境注入,做到「一套探针包,多环境不同策略」。

在 Kubernetes 里,常见做法是用 ConfigMap + 环境变量:

env:    # deployment.yaml 片段
  - name: SW_AGENT_SAMPLE_RATE
    value: "0.1"        # 生产环境默认值
  - name: SW_FORCE_SAMPLE_ERROR
    value: "true"

 

当需要临时调高(如大促前全量观察),只需改这个环境变量并滚动重启,无需重新打镜像。更进一步的做法是接配置中心(如 Nacos / Apollo),运行中动态下发采样率,探针支持部分配置热更新,真正做到「不重启调采样」。

推荐的环境策略:

环境

sample_rate

说明

---

---

---

本地开发

1

全量,方便调试

测试 / 预发

1

全量,建立基线

灰度上线

0.5

观察真实流量

稳定生产

0.1

成本与覆盖平衡

超大流量

0.01

仅保留异常样本

10. 采样与可观测性权衡速查

把「采多少」和「能看见什么」直接对应起来,避免拍脑袋:

你的诉求

采样策略

还能看见什么

---

---

---

我要完整复现每一次请求

100%

全部 Trace,成本最高

我要抓性能瓶颈但不想太贵

10% + 强制错误/慢

正常样本抽样,异常全留

我只关心报错和大模型慢推理

1% + 强制错误/慢

仅异常样本,成本极低

我要长期趋势图

任意采样 + 长 TTL 指标

拓扑/指标不受影响

记住一个核心不等式:**采样率只影响「正常样本的留存比例」,不影响「错误与慢调用的留存」**。只要 `force_sample_error_segment` 和 `slow_trace_segment_threshold` 开着,你最该关心的异常链路永远不会丢。这是采样能「又省又准」的根本原因。

总结:采样是「前端节流」,TTL 与存储选型是「后端瘦身」。两者结合,才能在高并发大模型场景下既把成本压下来,又保证错误与慢调用万无一失。下一篇我们进入拓扑图,看看怎么用全局视角定位瓶颈节点。

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐