1. 背景与问题现象
最近我们的日志系统遇到了严重的写入瓶颈。架构链路为:应用系统 -> MQ -> Logstash -> Elasticsearch。
ES 集群配置如下:
- 节点规模:3 节点
- 存储架构:网络存储 (NAS)
- 索引策略:按天切分,默认 1 分片 1 副本
- 数据规模:单节点存量数据约 30TB+
问题现象:
随着业务量增长,我们发现 MQ 消息积压严重。通过监控发现一个诡异的现象:
- 应用端写日志的流量仅仅 10MB/s。
- ES 服务器端的网络流量却飙升到了 100MB/s。
- 写放大高达 10 倍!
在尝试扩容之前,我们决定先深入排查,看是否能通过配置优化解决。
2. 排查过程
2.1 检查节点负载
通过 _cat/nodes 查看集群状态,发现虽然 CPU 使用率没有打满(约 20%-50%),但 Load Average(负载)极高,部分节点甚至高达 45。
GET /_cat/nodes?v&h=name,cpu,load_1m,dt,du
name cpu load_1m dt du
node-3 18 45.84 40tb 33tb <-- 异常高负载
node-1 22 24.03 40tb 31.4tb
低 CPU 高 Load,通常意味着 IO 等待(IO Wait) 严重。
2.2 抓取热点线程
使用 _nodes/hot_threads 进一步定位 ES 在忙什么,发现了核心线索:
100.0% [cpu=38.1%, other=61.9%] (500ms out of 500ms) cpu usage by thread 'elasticsearch[...][Lucene Merge Thread]'
Lucene Merge Thread:ES 正在疯狂进行段合并(Segment Merge)。other=61.9%:线程有 62% 的时间处于非 CPU 计算状态。结合 NAS 存储环境,这意味着线程大部分时间都在等待网络存储的 IO 响应。
3. 根因分析:为什么 NAS 上流量会放大 10 倍?
经过分析,我们确认问题的根源在于 Elasticsearch 的默认配置与网络存储(NAS)特性不兼容。
-
频繁的 Segment Merge(段合并):
ES 默认refresh_interval为 1秒。这意味着每秒都会生成一个新的小文件(Segment)。在 NAS 环境下,ES 后台线程需要不断地通过网络把这些小文件读出来,合并成大文件,再通过网络写回去。这产生了巨大的双向网络流量。 -
同步刷盘(Translog Fsync):
ES 默认translog.durability为request。即每次写入请求都要强制刷盘(fsync)。在本地盘上这很快,但在网络存储上,网络延迟会导致严重的写入卡顿,并产生大量小包 IO。 -
分片分布不均:
原配置为 1 主分片 1 副本,导致 3 个节点的集群中,始终有一个节点在“围观”,没有分摊写入压力。
4. 优化方案
在不增加硬件投入的前提下,我们调整了索引模板(Index Template)和 ILM(生命周期管理)策略。
4.1 核心配置调整(针对 NAS 优化)
我们将默认配置修改为以下“写优化”模式:
{
"index": {
"lifecycle": {
"name": "LOG-POLICY-PROD"
},
// 1. 增加分片数:充分利用3个节点的并发写入能力
"number_of_shards": "3",
// 2. 延长刷新间隔:从 1s 改为 60s
// 减少 Segment 生成频率,大幅减少后台合并产生的网络流量
"refresh_interval": "60s",
// 3. 异步刷盘:这是在 NAS 上提升性能的关键
"translog": {
"durability": "async", // 改为异步,不再每次请求都强制刷盘
"sync_interval": "30s" // 每30秒批量刷盘一次,合并 IO
}
}
}
配置解读:
- 收益:将大量微小的随机 IO 合并为少量的大块顺序 IO,极大地降低了 NAS 的通信开销。
- 代价:
refresh_interval: 60s意味着日志写入后可能有 1 分钟延迟才能被搜到;async意味着极端宕机情况下可能丢失最近 30 秒数据。对于日志业务,这是完全可接受的权衡。
4.2 历史数据治理(ILM 策略)
针对 30TB 的存量数据,我们优化了 ILM 策略,开启 Warm Phase 并执行 Force Merge:
- 操作:将 2 天前的索引强制合并为 1 个 Segment(
max_num_segments: 1)。 - 目的:彻底停止对老索引的后台合并操作,将所有网络带宽留给当天的热点写入。
5. 实施与验证
由于修改模板只对新索引生效,为了解决当天的积压问题,我们手动对正在写入的索引应用了上述 Settings 更新。
优化后的效果立竿见影:
- 网络流量下降:ES 服务器网卡流量从 100MB/s 骤降至 30-40MB/s,写放大现象基本消除。
- 负载降低:节点的 Load Average 从 40+ 逐步回落到正常水平,IO Wait 消失。
- 积压清理:MQ 的积压消息在短时间内被消费殆尽,系统恢复实时写入。
6. 总结
在基于 网络存储(NAS/SAN) 部署 Elasticsearch 时,千万不能使用官方默认配置。
- 默认配置(1s 刷新、同步刷盘)是为 本地 SSD 设计的,追求极致的数据可靠性和实时性。
- NAS 场景下,必须通过 “空间换时间” 和 “批量换低频” 的策略(加大 buffer、延长 refresh、异步 translog)来规避网络 IO 的高延迟瓶颈。
这次优化证明,在达到硬件瓶颈之前,合理的参数调优往往能带来数倍的性能提升。