SkyWalking 第三次积压超 3 亿:分片又小又匀,却只有一台机在扛
SkyWalking 第三次积压超 3 亿分片又小又匀却只有一台机在扛 摘要SkyWalking 第三次积压超 3 亿条三台 ES 只有一台 CPU 98%、磁盘读 180MB/s。上次是单分片 20GB 段合并热点这次分片又小又匀36 片×2.2GB却照样单机爆。pidstat merge stats free 三连追到根因OAP 与 ES 同机部署挤干 page cache合并被迫读物理盘。OAP 迁走后 page cache 回归积压 7 分钟清空。本系列第三集。第一集我们把 Kafka 分区倾斜治好了key 改 null数据均匀落 12 分区。第二集分区均匀了还积压凶手是 ES 单分片 20GB 的段合并热点DAY_STEP5→1单片降到 4.6GB 收工。我以为「分片」这个坑已经填平了。结果这次监控又红了积压突破 3 亿而且这次分片又小又匀——每天 36 个分片、每片才 2.2GB教科书级别的健康。分区匀了、分片也匀了、还是只有一台机在冒烟——这一集凶手藏得比前两集都深。前置阅读本篇是「SkyWalking 积压」三部曲的第三集强烈建议先看第二集 《SkyWalking 日志又积压 1900 万Kafka 分区明明均匀了凶手却藏在 ES 段合并里》本篇很多排查手法hot_threads、_cat/shards、磁盘读定位和「热点轮动≠数据倾斜」的结论会直接复用。第一集是 《SkyWalking 消费积压 6 亿条Kafka 分区倾斜的深度复盘》。一、问题现象分片又小又匀却又积压了7 月 13 日下午给某高 QPS 业务服务放开了全量链路采样。第二天清晨 5 点 40 左右SkyWalking 的 Kafka 消费组开始积压核心 topic 是skywalking-segments积压一路涨到3.13 亿条生产 13.7k/s、消费只有 7.5k/s——产 消越堆越高。体感还是熟悉的配方链路查询延迟、查不到最新 trace。打开资源大盘第一直觉又是那个熟悉的画面——只有一台机sw2在忙sw2CPU 98%、负载 158 核、内存 84.7%sw3 / sw4CPU 10%闲得发慌。于是我几乎要条件反射地下结论「跟上次一样又是段合并热点卡在一台机上吧。」——但这次这个结论是错的。这一集最大的教训就是别让上次的经验直接给这次下结论。二、先证伪这次真不是「大分片段合并」上次的根因是单分片 20GB、合并一次就是巨型读。所以这次我先拉分片想复现「大分片」——结果GET /_cat/shards?v打脸了集群完全均衡而且分片又小又匀。# GET /_cat/shards?v | grep sw_segment-20260714 # 36 主分片 / 0 副本12/12/12 均分三节点每片 2.2GB / ~914 万 doc index shard prirep state docs store ip node sw_segment-20260714 5 p STARTED 9139059 2.2gb 172.31.18.52 es02 sw_segment-20260714 16 p STARTED 9136695 2.2gb 172.31.19.98 es03 sw_segment-20260714 3 p STARTED 9140112 2.2gb 172.31.20.45 es01 ...36 片全部 2.2GB / 913~914 万 doc完全一致维度实测三节点总容量es01 823.7G / es02 818.1G / es03 819.1G几乎相等分片数687 / 688 / 687均匀当日sw_segment-20260714索引36 主分片、0 副本每节点 12/12/12 均分单分片每片2.2GB、约 914 万 doc几乎一模一样全局最大分片仅 4.5GBsw_log根本没有大分片第二集的DAY_STEP治理是有效的——分片已经被拆得又小又匀了。这里要停下来做一次关键的逻辑推理分片、doc 完全均匀 → 三台 ES 的合并工作量是一样的。既然合并量一样「只有 sw2 忙、另两台 10%」就不可能是 ES 索引 / 合并本身造成的——否则三台该一起忙。真凶必然是某个「天生只在一台机上」的东西。三、排查现场时间线把「稳态」和「单机阻塞」区分开只看一个瞬间的快照容易被误导。我把两条曲线叠在一起看——ES 机器 CPU和Kafka 积压sw3 / sw4从早上 5 点多起 CPU 一直趴着直到下午 14 点才突然忙起来Kafkaskywalking-segments5 点 30 分开始积压14 点开始下降。两条曲线的拐点严丝合缝。这说明问题不是稳态的负载分布不均而是 5:30 ~ 14:00 这段时间内 sw2 上有东西把整条消费管道卡死了——下游的 sw3/sw4 被饿着根本没活干一旦这个阻塞解除两台立刻有活、积压掉头。这一步很重要单机热 时间窗口 单机阻塞而不是这台机天生就该更忙。方向一下子就聚焦了。四、定位真凶不是 CPU是「磁盘读」被单机打满既然是 sw2 上的阻塞就得看 sw2 到底卡在哪个资源。我差点又只盯着 CPU——幸好扫了一眼磁盘列答案在那里机器IOutil磁盘读取磁盘写入sw285.0%102.9 MiB/s27.3 MiB/ssw310.6%4.3 KiB/s10.3 MiB/ssw47.5%390.4 KiB/s11.0 MiB/ssw2 磁盘读 102.9 MiB/ssw3 只有 4.3 KiB/s——差了 2 万多倍。而且 sw2 是读 写。瓶颈不是 CPU是sw2 的磁盘被海量读打满。说明102.9 MiB/s是资源大盘的一次采样读带宽在整段时间里一直在75~180 MB/s之间跳下面pidstat抓到的180 MB/s就是同一现象的峰值时刻——不是两个矛盾的数是同一块盘不同瞬间的读速。那读盘的到底是谁sw2 上同时跑着 OAPSkyWalking 的后端分析进程从 Kafka 消费 segment、算指标再写 ES和 ES得抓现行。[rootsw2-172-31-18-52 ~]# pidstat -d 206:46:44UIDPID kB_rd/s kB_wr/s kB_ccwr/s iodelay Command 06:46:5410003514990180226.0065462.0014796.000java← es02读180MB/s峰值 06:46:54014307060.006.000.000java← OAP读0那个飙到180 MB/s 读的 javaPID 3514990uid 1000 es02才是罪魁。OAP 是从 Kafka 走网络读、不碰本地盘能对本地磁盘打出 100 MB/s 顺序读的只有ESes02在读它自己的段文件。再确认 es02 在干嘛 ——GET /_nodes/es02/stats/indices/mergemerges:{current:4,// 4 个活跃合并在跑current_docs:4163677,current_size_in_bytes:2694651739// 当前正在合并 2.7GB}读 ≫ 写 活跃 merge ——就是段合并在读旧段。到这儿你的直觉一半对了确实是合并在读盘、卡在一台机上。但问题来了——分片均匀意味着三台合并量一样凭什么只有 es02 读爆盘先看写入侧有没有线索。拉一下 write 线程池# GET /_cat/thread_pool/write?v node_name name active queue rejected es03 write 0 0 0 es02 write 8 245 0 ← es02 写入队列堆了 245 个请求 es01 write 0 0 0es02 的 write 线程池 active8、queue245其他两个节点全是 0。写入被堵在 es02 上了——磁盘读爆导致写入吞吐见顶请求在队列里排长队。五、根因合并量三台都一样凭什么只有 sw2 读爆盘写入队列堆了 245 个请求说明 es02 的写入吞吐被什么东西卡死了——而磁盘读 180 MB/s 就是那个什么。但还有一个更大的疑问没解分片均匀意味着三台合并量一样为什么偏偏是 sw2 在读盘读到爆先看这台机上跑了什么 ——docker stats --no-stream[rootsw2-172-31-18-52 ~]# docker stats --no-streamNAME CPU % MEM USAGE / LIMIT MEM % BLOCK I/O skywalking-oap-server400.24%2.649GiB /15.24GiB17.37%20.3GB / 497MB ← OAP 单实例只在 sw2 es02314.76%9.785GiB /15.24GiB64.19% 616TB / 126TB ← ES 数据节点同机sw2 上OAP es02 挤在一起内存吃到 84.7%另两台只有 66~68%因为它们没有 OAP。再看一下迁走前的free -g[rootsw2-172-31-18-52 ~]# free -g # OAP 迁走前total usedfreeshared buff/cache available Mem:15130021Swap:000buff/cache 只有 2Gavailable 只剩 1G——page cache 几乎被榨干。答案就藏在这 2.6GB 的 OAP 上差别不在「合并多少」在「合并时读内存还是读磁盘」。sw3 / sw4没有 OAP剩大把page cache。刚写下去的段还在内存里合并直接从 page cache 读 → 磁盘几乎不动KB/s。sw2OAP(2.6G) es02 堆(8G) 把 16G 内存挤干几乎不剩 page cache。同样的段合并时早被挤出内存了 → 只能从物理磁盘读→ 180 MB/s、IOutil 打满。同一份合并工作量sw3/sw4 命中内存、sw2 被迫读盘。这就是「一台爆、两台闲」的最终答案不是合并偏心 sw2是 OAP 偷走了 sw2 的 page cache让 sw2 独自把「本该在内存完成的合并」拖成了磁盘 IO 灾难。完整因果链放开某业务全量采样 → 段量 ×3日增 42G → 104~115G→ 三台 ES 合并压力同步 ×3均摊 │ ▼ sw2 OAP(2.6G) es02(8G 堆) 挤一台 16G 机 → page cache 被挤干 │ ▼ es02 合并只能读物理盘 75~180MB/s、IOutil 85%sw3/sw4 命中缓存读 KB/s │ ▼ es02 磁盘饱和 → 写入队列堆积write thread pool queue245其他节点 queue0 │ ▼ 同机 OAP 消费被拖住 → 全管道限速到 7.5k/s生产 13.7k/s→ Kafka 积压涨到 3.13 亿 │ ▼ 下游 sw3/sw4 拿不到活 → 闲置到 14:00六、解决方案与验证把 OAP 迁走page cache 一还就好根因既然是「OAP 抢了 ES 的 page cache」解法就非常直接——把 OAP 从 es02 那台机迁到独立机器让 page cache 还给 ES。下午 15:25 完成迁移效果立竿见影三台 ES 消费立即均衡sw3/sw4 的 CPU 提上来了Kafka 积压掉头下降。free -g直接实证 page cache 已经回来了[ec2-usersw2-172-31-18-52 ~]$ free -g total used free shared buff/cache available Mem: 15 9 0 0 5 4 Swap: 0 0 0迁走前 OAPes02 把 16G 吃到 84.7%、cache 几乎为 0迁走后buff/cache 回到 5G合并重新回到内存磁盘 IO 释放。OAP 迁走即恢复反过来钉死了「OAP 挤占 page cache」就是根因。这是复盘里最漂亮的一种收尾改一个变量现象消失因果闭环。七、一个必须说清楚的反问扩分片能不能降合并排查中有人问既然是合并压力把分片数扩大、每片更小不就合并轻了吗不能而且在这个场景里会更糟。原因值得记住合并的总工作量 ≈ 正比于「写入的数据量」跟分片数几乎无关。合并是 Lucene 在每个分片内部做的分层合并同样一天的数据切成 36 片还是 72 片全部分片加起来要合并的总字节数几乎不变。扩分片只是把「几个大合并」拆成「更多小合并并行跑」磁盘要读的总量一样。更要命分片越多越耗内存每个分片有固定的 Lucene 结构 / 段元数据 / FST 开销。sw2 本来就是内存不够才读盘再加分片只会让 page cache 更紧、读盘更多——方向反了。真正能减少合并的旋钮是refresh_interval默认 1s 会生成海量小段、逼着不停合并对链路/日志这种写多读少的数据调到 30s段更少更大、合并次数直接锐减。但这治标治本还是那句话——别让 OAP 和 ES 抢内存。八、举一反三三集下来SkyWalking 积压的「排查地图」三次积压凶手一次比一次深但排查套路是可以沉淀成地图的。下次再遇到积压按这个顺序往下捅层查什么对应集数 / 症状Kafka 生产各分区生产是否均匀第一集分区倾斜key 固定Kafka 消费各分区消费/位移是否均匀、consumer 够不够——ES 写入·分片_cat/shards看分片是否倾斜 / 过大第二集单分片 20GB 段合并热点DAY_STEPES 节点·资源单机 CPU /磁盘读/ IOutilhot_threads看是不是 merge第二、三集merge 读盘打满单机机器·内存docker stats/free有没有别的进程抢 page cache第三集OAP 与 ES 同机抢内存几个反复踩到、值得刻进脑子的经验别用上次的结论给这次下判断——三次都是只有一台机忙但根因分别是分区、分片、内存一次比一次隐蔽。单机热 时间窗口 单机阻塞不是这台天生该忙把资源曲线和积压曲线叠着看拐点会告诉你真相。别只盯 CPU——这次真凶写在磁盘读那一列差点被 CPU 带偏。热点轮动 / 单机热 ≠ 数据倾斜——数据可能是完全均匀的是某个不分摊的东西大 merge、单实例进程、被抢的 page cache造成了单机热。page cache 是隐形资源——ES 靠它吃饭谁跟 ES 抢内存谁就在悄悄削 ES 的性能。OAP 和 ES 数据节点不要同机部署。九、总结一句话收尾前两集的坑在 Kafka 和 ES 的配置里这一集的坑在部署拓扑里——把一个吃内存的 OAP 和一个靠 page cache 吃饭的 ES 塞进同一台机就是给自己埋了一颗只在高峰期引爆的雷。三集治理动作串起来第一集Kafka Agentkey固定 → 改null数据均匀分区第二集super dataset 单分片 20GB →DAY_STEP5→1单片降到 4.6GB合并轻 4~5 倍第三集OAP 与 es02 同机抢 page cache →OAP 迁到独立机器page cache 还给 ES。后续治理采样常态化全量成本极高用完即关、refresh_interval调 30s 减合并、补 Kafka lag 磁盘 IOutil 告警这次闷声跑了近 10 小时才发现。你的 SkyWalking / ES 集群有没有哪个邻居进程正在悄悄偷 page cache欢迎评论区交流。延伸阅读《SkyWalking 日志又积压 1900 万Kafka 分区明明均匀了凶手却藏在 ES 段合并里》 —— 本系列第二集段合并热点与DAY_STEP治理排查手法一脉相承《SkyWalking 消费积压 6 亿条一次 Kafka 分区倾斜的深度复盘》 —— 本系列第一集Kafka 分区倾斜Elasticsearch 官方Segment merging段合并机制Elasticsearch 官方Reduce disk usage / 依赖 page cache 的存储原理SkyWalking 官方Elasticsearch 存储配置superDatasetIndexShardsFactor/superDatasetDayStep️ 标签SkyWalkingElasticsearch消息积压page cache段合并线上排障

相关新闻