一、判断核心现象
流式任务(Blink/Flink)持续向 ES 批量写入,重启任务 = 清空内存堆积、重置连接 / 批次,所以 CPU 短暂回落;运行一段时间后负载复现,基本锁定这几类问题:
- 写入压力不平稳、批次 / 并发不合理
- ES 分片 / 刷新 / 段合并压力大
- 文档结构、查询 / 聚合后台任务拖 CPU
- Blink 侧写入参数、反压、重试逻辑异常
- ES JVM / 线程池配置不合理
二、现场快速排查
1. 先看 ES 节点的热点指标
1.1 节点维度
# 查看各节点CPU、负载、线程池
GET _cat/nodes?v&h=name,cpu,load_1m,heapPercent,ramPercent
# 查看ES 写入线程池、队列、拒绝(关键!写入瓶颈第一看这个)
GET _cat/thread_pool/write?v&h=node,name,active,queue,rejected
GET _cat/thread_pool/bulk?v&h=node,name,active,queue,rejected
bulk/write队列堆积、rejected > 0:写入过载- active 长期打满:线程池不够或单请求太重
1.2 索引维度(写入目标索引)
# 索引写入TPS、段合并、刷新频率
GET _cat/indices?v&h=index,docs.count,docs.deleted,store,pri,rep,segments.count
# 实时索引统计(刷新、合并、bulk耗时)
GET _stats/indexing,merges,refresh
重点观察:
refresh频率极高(默认 1s):小刷新频繁触发 CPUmerges持续高:小分片 / 小文件太多,后台段合并吃满 CPUbulk 耗时持续走高:单批次数据过大 / 文档字段过多
1.3 查看慢日志 & 热点操作
开启 / 查看 slowlog,确认是bulk写入慢还是查询/聚合慢:
# 查看当前慢日志配置
GET _settings/index.slowlog
如果大量 bulk 慢日志 → 写入侧问题;大量search/agg → 业务查询拖 CPU。
2. Blink/Flink 任务侧排查
- 是否存在反压:Flink UI 看 Task 反压、SubTask 堆积,反压会导致批次累积、批量写入暴涨。
- 并发度:写入并发是否远大于 ES 承载能力。
- 批量大小:
bulk.flush.max.actions/bulk.flush.max.size配置是否不合理。 - 重试机制:ES 返回 429 / 超时后,Blink 无限重试 → 风暴式写入,CPU 持续拉高。
三、分场景解决
场景1:流式写入 + 频繁 Refresh + 段合并爆炸
【现象特征】
重启任务后短时平稳,运行几小时 CPU 逐步上涨;ES segments.count 持续变多,merges 线程繁忙。
【优化操作】
- 调大索引 refresh 间隔
# 流式数据实时性要求不极致的直接改:
PUT 你的索引/_settings
{
"index.refresh_interval": "30s" // 从1s改成10~30s,根据业务容忍度调整
}
作用:减少内存刷盘、段生成,大幅降低 CPU
2. 关闭索引自动刷新
# 纯离线 / 准时间流:
{
"index.refresh_interval": "-1"
}
可在凌晨低峰手动
POST 索引/_refresh
3. 限制段合并并发
# 防止合并打满 CPU:
PUT _cluster/settings
{
"persistent": {
"indices.store.throttle.max_bytes_per_sec": "100mb",
"indices.merge.scheduler.max_thread_count": 2
}
}
场景2:Blink/Flink 批量写入不合理,并发高,重试风暴
【现象特征】
bulk 队列经常堆积,有 rejected 拒绝;Flink 任务无反压,但写入 TPS 波动大。
Blink 侧参数优化(Flink ES Connector)
1、控制 Bulk 批次大小
推荐组合(通用稳妥值):
- bulkFlushMaxActions:1000~2000
- bulkFlushMaxSizeInBytes:5~10MB
- bulkFlushInterval:1000~3000 ms不要单批次过大(>20MB 极易 GC / 锁竞争拉高 CPU)
2、降低写入并发
Blink 写入 SubTask 并发 > ES 节点数 * 2 基本过载,逐步降并发观察 CPU。
3、优化重试和超时
关闭无限重试,增加退避策略:
- 重试次数:3~5 次
- 重试延迟:500ms~2s 指数退避
- 连接超时 / Socket 超时 适当调高,避免频繁断开重连
4、开启本地攒批,避免单条下发
禁止逐条写入 ES,流式必须走 Bulk。
场景3:索引分片不合理
【现象特征】
分片数过多,segments 暴增,段合并永不停歇。
- 单分片数据量建议:单分片 20~50GB 最优
- 分片数原则:
- 主分片数 不要超过 ES 数据节点数
- 写入流索引:主分片 = 数据节点数,副本 1(高峰可临时关副本降负载)
- 临时降负载(紧急):
PUT 索引/_settings
{
"index.number_of_replicas": 0
}
# 低峰再改回 1。
场景4:文档本身问题(字段多、大字段、动态映射)
1、禁用动态映射,提前建好 Mapping
自动创建字段会频繁更新元数据、刷新索引,持续吃 CPU。
2、剔除无用大字段(长文本、二进制、超大数组)
写入、解析、索引都会拉高 CPU。
3、关闭 _source 压缩 / 调整字段类型,减少解析开销。
场景5:ES JVM & 系统层配置
1、JVM 堆建议:不超过 31G,生产常用 16G/24G
堆过大 → GC 卡顿、CPU 毛刺。
2、系统层面:
- 打开 ES 内存锁定
bootstrap.memory_lock: true - 调大文件句柄、线程数(流式写入必备)
四、临时应急方案
如果现在 CPU 已经很高,先做这几步快速止血:
- 对应索引
index.refresh_interval改为30s - 临时把索引副本设为 0
- Blink 写入任务:降低 1/3 并发 + 调大 bulk 间隔
- 手动触发一次段合并整理(低峰操作):
POST 索引/_forcemerge?max_num_segments=1
五、长效运维建议
1、按天 / 按小时拆分索引(时序流式数据首选)
用 滚动索引/日期索引,旧索引只读,不再产生合并 / 刷新压力。
2、做流量削峰:Blink 侧加缓冲,平滑写入 TPS,避免突刺。
3、监控看板重点加:
ES CPU、bulk 队列、段数量、refresh 次数、Flink 写入并发 / 批次。
4、定时运维:凌晨低峰执行 forcemerge + refresh 整理碎片。
补充一:快速定位
- 队列堆积、rejected → 写入并发 / 批次太大,降并发、调 bulk
- segments 多、merges 忙 → 分片多、刷新太勤,改 refresh、合分片
- 重启就好、越跑越卡 → 内存 / 批次累积 + 后台合并持续运行
补充二:信息收集命令(先收集后分析)
1. 集群&节点基础信息
# 所有节点概览:CPU、负载、堆内存、物理内存
GET _cat/nodes?v&h=name,ip,cpu,load_1m,load_5m,heapPercent,ramPercent,diskUsedPercent,node.role
# 集群整体健康、分片分配状态
GET _cat/health?v
# 查看节点JVM配置、堆大小、GC情况
GET _nodes/jvm?pretty
2. 写入核心线程池
# bulk 线程池(流式写入最关键)
GET _cat/thread_pool/bulk?v&h=node,name,active,queue,queue_size,rejected,completed
# write 线程池
GET _cat/thread_pool/write?v&h=node,name,active,queue,queue_size,rejected,completed
# 全部线程池(兜底查看其他阻塞)
GET _cat/thread_pool?v
关注字段:
rejected > 0代表写入过载拒绝;queue持续上涨代表堆积。
3. 目标业务索引信息
# 索引基础:分片、文档数、存储、删除文档数
GET _cat/indices?index=你的索引名*&v&h=index,pri,rep,docs.count,docs.deleted,store,segments.count
# 索引全局统计:写入、刷新、段合并耗时/次数
GET 你的索引名*/_stats/indexing,refresh,merges,search?pretty
4. 段合并 & 刷新详情
# 查看正在执行的段合并任务
GET _cat/segments?index=你的索引名*&v
# 查看后台合并调度、限流配置
GET _cluster/settings?include_defaults=true&pretty
# 查看索引当前 refresh 间隔、副本数等设置
GET 你的索引名*/_settings?pretty
5. 慢查询 / 慢写入日志
# 查看当前慢日志阈值配置
GET 你的索引名*/_settings/index.slowlog?pretty
# 查看最近慢日志(ES7+/8+ 内置日志检索,也可直接看服务器日志文件)
GET _search
{
"query": {
"match_all": {}
},
"sort": [{"@timestamp": "desc"}],
"size": 100
}
若服务器有日志文件,额外收集:
elasticsearch/logs/下的*.log、sloglog日志
6. 分片&分片分配情况
# 查看每个分片分布、大小、状态
GET _cat/shards?index=你的索引名*&v&h=index,prirep,shard,pnode,store,docs
# 查看未分配分片(如有异常分片也会拉高负载)
GET _cat/shards?v&h=index,prirep,shard,state,node
7. 批量请求 & 队列堆积补充
# 查看当前活跃的批量请求
GET _cat/pending_tasks?v
# 集群pending任务(元数据、分片迁移、任务排队)
GET _cat/tasks?v&actions=*bulk*,*index*