SkyWalking 每日写入 ES 数据量过大排查与降采样

SkyWalking 每日写入 ES 数据量过大排查与降采样

记录时间:2026-08-14(2026-08-17 修订:补真实根因——采样 env 变量名错误)
环境:dyck 生产信创环境(RKE + ARM64)| SkyWalking 9.3.0 | Elasticsearch 7.17.28(3 节点)

一、问题现象

最近发现 dyck 生产的 SkyWalking 往 ES 写数据特别猛,sw_segment-* 索引三天的数据长这样:

索引 文档数 存储大小
sw_segment-20260812 6.63 亿 373.2 GB
sw_segment-20260813 6.37 亿 367.5 GB
sw_segment-20260814 4.09 亿 243.4 GB

按 ES _cat/indices 的列序看,这些索引 pri=5 主分片、rep=0 零副本,每天稳定灌进去 4~6.6 亿条 segment,三天加起来快 1TB 了,ES 压力不小。

2026-08-17 追记:8-14 下午就给 kjds 服务配了 sampleCount: 10/20/30/50/100 并滚动更新了 Pod,结果 8-15、8-16 两天数据量纹丝不动(6.16 亿 / 5.85 亿),坐实配置没生效,由此才有下面的二次排查。

二、排查过程

2.1 先看 OAP 有没有配数据保留

先翻 prod-xc 的 OAP 部署文件,发现 env 里只有存储地址和账号密码,一个 TTL 环境变量都没有。SkyWalking 9.3.0 默认 recordDataTTL=3 天、metricsDataTTL=7 天,所以 ES 里同时留着 3 天的 segment 索引。这不是「没清理」,而是每天真实写入就有 ~300GB,攒 3 天就堆到 1TB。

2.2 翻 chart 模板看采样(8-14 的误判)

yw-helm-charts/gzeport-jartemplates/deployment.yaml,找到采样那个环境变量:

- name: SW_AGENT_SAMPLE_N_PER_3_SECS
  value: {{ .Values.skywalking.sampleCount | default "500" | quote }}

当时(8-14)的误判:以为 chart 早就内置了采样,默认 500 生效中,kjds 只是没有显式配置。
实际情况:这个 env 变量名是错的,采样从未生效过——详见 2.5 节根因。

2.3 数据到底从哪来的

prod-xc 的 OAP 后端 ES 是 dyck-elasticsearch.tools.svc.cluster.local:9200,dyck 服务上报是集群内地址 dyck-skywalking-oap.tools:11800。结果翻 kjds 服务的 values 时发现,kjds 全部 15 个服务的 backendServices 都是 <VIP>:31800

把端口和 VIP 对一下就明白了:

  • <VIP> 是 dyck 生产信创环境的 VIP(prod.skywalking.example.comprod.kibana.example.com 都指向它)
  • 31800 是 dyck OAP gRPC 的 NodePort(prod-xc OAP 里 nodePort: 31800

2.4 看 UI 揪出热点服务

SkyWalking UI 的 Services 页面(kjds 服务组),调用量排前面的几个:

服务 Load (calls/min) ≈calls/s
export-service 148496 2475
savefile-service 53394 890
import-service 17806 297
httpsend-service 13407 223

再对下副本数:export-service14 副本savefile-service 6 副本,messageprocess-export-service 12 副本。

2.5 二次排查:为什么 8-14 改了采样没生效(8-17)

配置了 sampleCount、Pod 也滚动更新了(容器 env 里 SW_AGENT_SAMPLE_N_PER_3_SECS: '10' 明明白白),但 8-15/8-16 数据量纹丝不动。进容器看 agent 的配置文件才恍然大悟:

grep -nE 'sample_n_per_3_secs|span_limit' /AppHome/skywalking-agent/agent/config/agent.config
# 31:agent.sample_n_per_3_secs=${SW_AGENT_SAMPLE:-1}
#     agent.span_limit_per_segment=${SW_AGENT_SPAN_LIMIT:300}

SkyWalking agent 读环境变量的机制agent.config 里每个配置项写成 ${ENV_NAME:默认值} 占位符,agent 启动时用同名环境变量展开。占位符写的是什么名字,env 就必须叫什么名字——agent.sample_n_per_3_secs 认的是 SW_AGENT_SAMPLE,不是自作聪明按配置项全称拼出来的 SW_AGENT_SAMPLE_N_PER_3_SECS

于是 pod 里那个 SW_AGENT_SAMPLE_N_PER_3_SECS=10 从第一天起就是摆设:没有占位符引用它,agent 读都没读,采样走默认值 -1关闭采样 = 全量上报)。这也解释了为什么每天敢灌 6 亿——所谓”默认 500″从来没存在过。

顺带核对发现同病相怜的还有两个:

chart 下发的 env agent.config 占位符 后果
SW_AGENT_SAMPLE_N_PER_3_SECS(错) ${SW_AGENT_SAMPLE:-1} 采样从未生效,全量上报 ← 本案根因
SW_AGENT_SPAN_LIMIT_PER_SEGMENT(错) ${SW_AGENT_SPAN_LIMIT:300} 恰好值=默认值 300,无实际影响但同为摆设
SW_AGENT_SAMPLE_RATE(values-demo 遗留) 不存在此占位符 幽灵配置,从来无效

其他 env(SW_AGENT_NAME/SW_AGENT_NAMESPACE/SW_AGENT_COLLECTOR_BACKEND_SERVICES/SW_LOGGING_*/SW_JDBC_*/SW_AGENT_IGNORE_SUFFIX)与占位符一一对应,都是真实生效的——所以服务名、命名空间、上报地址一直好好的,唯独采样是哑的。

三、根因分析(8-17 修订)

直接根因(8-17 定案):chart 模板里的采样 env 变量名写错了。

  • agent.config 占位符是 ${SW_AGENT_SAMPLE:-1},而 chart 下发的是 SW_AGENT_SAMPLE_N_PER_3_SECS,名字对不上 → agent 读不到 → 采样走默认 -1(全量上报)。
  • SkyWalking agent 的 env 不是”按配置项名自动映射”的,agent.config 占位符里写什么 env 名就只认什么。想加自定义 env,先去 agent.config 里加占位符行,或者用 -javaagent:...jar=key=value 的 agent options 方式传。
  • 8-14 的”降采样”之所以无效,就是改的 values 和模板渲染出来的 env 名压根没被 agent 消费。

叠加因素(量为什么这么大):

  1. kjds 和 dyck 共用同一套 OAP/ES:kjds 全部服务把 trace 上报到 <VIP>:31800(dyck 生产 VIP + OAP NodePort),数据落 dyck-elasticsearch.tools。kjds 没有独立 OAP/ES,查 ES 数据量必须两边一起看。

  2. 高副本服务全量上报:采样失效意味着没有任何限流,export-service 14 副本、总 2475/s 的调用量一条不落全部进 ES,单服务一天就灌进约 2 亿条 segment。kjds 合计约 3.3 亿/天,占 6.6 亿的一半以上,剩下是 dyck 自己的服务。

四、解决方案

第一步(8-14,已做但无效):给 kjds 全部 15 个服务的 values.yamlskywalking.sampleCount 分档。配置本身没问题,败在 chart 模板的 env 名是错的。

第二步(8-17,真正的修复):修 yw-helm-charts 三个 chart 的模板,把 env 变量名改成与 agent.config 占位符一致:

# deployment.yaml 修改前后对比
- name: SW_AGENT_SAMPLE_N_PER_3_SECS    # ❌ 错:agent.config 无此占位符
  value: ...
- name: SW_AGENT_SAMPLE                  # ✅ 对:${SW_AGENT_SAMPLE:-1}
  value: ...
# span limit 同理:SW_AGENT_SPAN_LIMIT_PER_SEGMENT → SW_AGENT_SPAN_LIMIT

涉及 gzeport-jar(1.2.13→1.2.14)、gzeport-tomcat(1.0.2→1.0.3)、gzeport-tongweb(1.0.10→1.0.11)三个 chart。values 侧的 sampleCount key 不变,应用 values 无需跟着改。

kjds 的分档维持 8-14 的方案:

分档 服务 副本 sampleCount 说明
报文管道(压最低) export-service 14 10 全量上报的最大户
报文管道 savefile-service 6 20 次大户
报文管道 httpsend / import / messageprocess-export / systems 30 纯报文转发,trace 价值低
核心业务 base-service / bigdata-service 100 多留点链路方便排查
其余 gateway / web / httpquery / httpreceiver / messageprocess-import / mqsend / camel 50 通用默认

配置写法(在 skywalking: 块下,和 logging: 平级):

skywalking:
  enabled: true
  collector:
    backendServices: <VIP>:31800
  logging:
    level: ERROR
    dir: /AppHome/logs/skywalking-agent
  sampleCount: 50    # 每实例每 3 秒最多 50 条 trace(0/负数=全采,勿写 0 当不限流)

行为变更提示:env 名修好后,所有使用这三个 chart 的服务采样从”实际全采”跳到”显式配置值或默认 500″。dyck 侧 54 个未显式配置的服务将吃默认 500(≈166 条/s/实例)——低于该流量的服务无感,个别高流量服务等于开始限采,属于修复 bug 的必然副作用,发布时需知会。

五、验证

chart 修复发布后第二天,对比新 sw_segment-* 索引的文档数和存储大小:

curl -s -u elastic:'<密码>' \
  'http://dyck-elasticsearch.tools.svc.cluster.local:9200/_cat/indices/sw_segment-*?h=index,docs.count,store.size&s=index'

正确的预期基准(8-17 修正,原文写”降到 1 亿以内”算错了):kjds 侧从 ~3.3 亿压到 ~4000 万,但 dyck 侧 ~3.3 亿没动,总量应从 6 亿档降到 ~3.5 亿档,不是 1 亿。dyck 侧 54 个服务吃默认 500 也会贡献一部分降幅。

UI 侧的硬指标:export-service 的 Load 从 ~14.8 万 calls/min 掉到 3000 上下(14 副本 × 10 条/3s ≈ 2800/min)——采样生效后 UI 流量数字会跟着采样失真,这是预期副作用,不是业务流量真掉了。

发布前的快速自检(滚动完成后任挑一个 kjds pod):

# 确认新 env 名已下发
kubectl exec -n <ns> <pod> -- env | grep SW_AGENT_SAMPLE
# 应输出 SW_AGENT_SAMPLE=10,且不再有 SW_AGENT_SAMPLE_N_PER_3_SECS

六、注意事项

  • SkyWalking agent 的 env 映射规则是本文的核心教训agent.config 占位符 ${ENV_NAME:默认值} 决定一切,env 名必须与占位符严格一致。没有”按配置项名自动推导”的机制。排查此类问题的第一刀永远是进容器 grep agent.config,而不是盯着 deployment 的 env 猜。
  • 采样语义sample_n_per_3_secs0 和负数 = 关闭采样(全量上报),默认值就是 -1。想”不限流”应该给大数值,写 0 会得到反效果。
  • MQ 消费也会产生 segment:SkyWalking 的 MQ 插件会追踪每一次 produce/consume,其中 consume 是异步边界、每次消费新建一条 trace,直接堆 segment 数量。采样作用于所有新建 trace,MQ consume 走同一条采样逻辑,所以降采样对 MQ 一样有效。
  • UI 里的流量数字是 metrics,不是 ES 数据量:Virtual MQ / Services 页面上的 LoadProduce/Consume Traffic 是分钟级聚合指标,存 sw_metrics 类索引,数据量很小;真正撑大 ES 的是这些流量背后每一次调用产生的 segment 明细。
  • 还没做:dyck 侧 54 个服务的显式分档采样(当前吃默认 500);OAP 侧 TTL(SW_CORE_RECORD_DATA_TTL=1)也没加。kjds 生效后观察总量,若还是高就轮到这两项。
  • ES 排查字段备忘sw_segment-* 索引没有 service_name 字段(只有 service_id,服务名元数据在 sw_service_traffic 索引,但该索引按 TTL 可能只留最近窗口);time_bucket 在 segment 索引里是秒级 yyyyMMddHHmmss,不是整点小时桶,按小时聚合要用 range 聚合。

七、参考资料

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Image
Image
Image
Image
Image
Image
Image
Image
Image
Image
Image
Image
Image
Image
Image
Image
Image
Image
Image
Image
Image
Image
Image
Image
Image
Image
Image
Image
Image
Image
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇