Elasticsearch 创建、删除索引慢:快速排查 Runbook
PUT /<index>、DELETE /<index>、ILM rollover 和 mapping 更新一起变慢时,我通常不会先看某个索引有多大。这几类操作都要修改 cluster state,也都要经过 master。先查它们共用的这段链路,往往比盯着单个索引更快。
下面是一套偏现场排障的检查顺序。先用只读命令判断问题大致落在哪一类,再继续深挖:
- cluster state 更新积压或 master 节点压力;
- index、shard 总量过高,也就是 oversharding;
- shard allocation 或 recovery 未完成;
- JVM、线程池、磁盘或网络资源拥塞;
- 删除请求已经完成,但底层文件和磁盘空间尚未回收。
为什么这些操作会一起慢
创建索引、删除索引、更新 mapping、创建别名和 ILM rollover 都会改集群元数据。当前 master 处理请求、生成新的 cluster state,再把它发布给其他节点。元数据变大、更新过密,或者 master 的 CPU、heap、GC 顶不住,最终看到的现象都差不多:几个管理接口一起慢下来。
创建索引还可能等待 primary shard 变为 active。创建索引响应中的两个字段含义不同:
acknowledged表示创建索引的 cluster-state 更新已在超时前得到确认;shards_acknowledged表示所需数量的 shard 已在超时前启动。
所以,看到 acknowledged: true、shards_acknowledged: false 时,先去查 shard allocation 和启动过程。cluster-state 更新本身已经得到确认。
删除索引也有两个时间点。DELETE API 返回成功,说明 cluster-state 里的删除变更已经得到确认;节点删文件、释放文件句柄,以及存储系统显示出新的可用空间,都可能更晚。现场先问清楚到底是哪一种慢:
- DELETE 请求本身很慢:查 master 和 cluster state。
- DELETE 很快返回,但磁盘空间迟迟不下降:查磁盘 I/O、文件句柄、节点状态和存储监控。
先拆开请求的等待阶段
如果客户端能记录请求耗时,最好同时记录响应体和请求参数。很多管理 API 都有 master_timeout 和 timeout:前者控制等待 master 响应的时间,后者通常控制等待 active shard 的时间;具体可用参数仍要以当前版本和具体 API 的文档为准。
这能提供一个很有用的线索:master_timeout 经常触发,先查 cluster-state 和 master;cluster-state 很快确认,但 timeout 或 shards_acknowledged 迟迟不满足,先查 allocation、recovery 和磁盘。客户端自己的 HTTP 超时只能说明调用方放弃等待,不能说明 Elasticsearch 已经停止处理请求。
排查前的采集原则
下面的命令都不会修改集群。_cluster/allocation/explain 虽然使用 POST,但只解释分配决策,不会执行 reroute。
最好趁慢请求还在发生时采一次,过 30~60 秒再采一遍。线程池 rejected、GC 次数、I/O 字节数有不少是累计值,一张快照看不出它们是否还在增长。顺手记下这些现场信息:
- 请求开始时间、结束时间和客户端超时时间;
- 请求响应体,尤其是
acknowledged、shards_acknowledged和错误信息; - Elasticsearch 版本、目标索引名和操作类型;
- 同时段是否发生部署、批量建索引、ILM rollover、恢复、快照或节点重启。
不同 Elasticsearch 版本支持的 CAT 列略有差异。遇到列名报错,直接用 ?help 查当前版本:
第一步:确认集群状态和 cluster-state 队列
先执行以下四条命令:
| 命令 | 重点字段 | 如何判断 |
|---|---|---|
_cluster/health | status、initializing_shards、relocating_shards、unassigned_shards、number_of_pending_tasks、task_max_waiting_in_queue_millis | shard 未稳定时进入 allocation/recovery 分支;pending task 数量和最长等待时间持续增加时进入 master 分支 |
_cluster/health?level=shards | 各 index、shard 的状态 | 用于定位异常 index 和 shard,之后执行 allocation explain |
_cluster/pending_tasks | source、priority、time_in_queue_millis | create/delete/mapping/shard-started 等任务长时间排队,说明 master 处理 cluster-state 更新跟不上 |
_cluster/stats | index 数、primary/total shard 数、节点数 | index、shard 总量持续增长,管理操作也越来越慢,继续查 oversharding |
_cluster/pending_tasks 只列出尚未执行的 cluster-state 更新任务,和 _tasks 不是一回事。空列表只代表采样那一刻没有任务排队。任务可能刚处理完,也可能慢在发布阶段,所以还得对照前后两次采样和请求时间。
第二步:检查 index、shard 规模与分布
_cat/indices:是否存在大量小索引、小 shard
先看 pri、rep 和 pri.store.size。单个索引的平均 primary shard 大小可以粗略算成:
| |
有些集群数据总量并不夸张,却堆了成千上万个几十 MB、几百 MB 的小索引,每个索引还带多个 primary 和 replica。元数据、segment、文件句柄以及每个 shard 的固定开销就这样累积起来了。这正是常见的 oversharding。
_cat/shards:是否有大量 shard 正在移动或等待
关注 state 和 node:
- 大量
INITIALIZING:shard 正在启动或恢复; - 大量
RELOCATING:集群正在搬迁数据; - 存在
UNASSIGNED:需要用 allocation explain 查明原因; - shard 明显集中在少数节点:检查节点角色、allocation filter 和磁盘水位。
_cat/allocation:节点是否接近磁盘水位线
对比各节点的 shard 数、disk.avail 和 disk.percent。磁盘接近 low、high 或 flood-stage watermark 时,Elasticsearch 会限制分配,严重时还可能对索引施加只读保护。磁盘使用不均也可能让少数节点先触发限制,从而拖慢整个集群的 shard 稳定过程。
“每个节点最多放多少 shard”没有一个放之四海皆准的数字。节点规格、heap、数据模型、segment 数、写入模式和 Elasticsearch 版本都会影响结果。下面这组现象同时出现时,判断才比较站得住:
第三步:检查 master、JVM 和运行中任务
| |
先找到当前 master
_cat/nodes 的 master 列里,* 通常就是当前 master。把它的 CPU、load 和 heap 与其他节点放在一起看。若只有 master 长时间高负载,pending tasks 又多是 create、delete、mapping、shard-started,基本可以沿 cluster coordination 这条线继续查。
某一刻的 heap.percent 很高,说明不了太多。把 _nodes/stats 里的 GC 次数和耗时做前后对比,再看下面几种情况是否出现:
- old GC 频繁且耗时明显增长;
- heap 回收后仍长期处于高位;
- master 的 CPU 与 pending task 等待时间同步上升;
- 版本支持时,cluster-state publish 相关统计出现明显延迟。
用 _tasks 补充 pending tasks
_tasks 能看到还在运行的快照、reindex 和管理任务,正好补上 _cluster/pending_tasks 看不到的部分。查询时限制 actions;大型集群上直接拉全部任务,响应本身就可能很大。
用 hot threads 看 CPU 花在哪里
如果 CPU 持续偏高,再采集 hot threads:
MasterService、cluster coordination 或 cluster-state publish 相关栈占比高,继续沿 master/元数据方向排查;- Lucene merge、
IndexWriter、refresh 或 flush 相关栈占比高,继续检查写入放大和磁盘; - GC 相关线程频繁出现,结合 GC 日志和 heap 使用确认是否存在内存压力。
完整的 GET /_cluster/state/metadata 不适合当常规排查命令。索引多、mapping 大时,响应会很重。确实要看元数据,就限定到一个索引,再用 filter_path 裁掉无关字段。
第四步:检查 shard allocation 与 recovery
| |
_cluster/allocation/explain 需要指定一个目标 shard。不要发送没有 index 和 shard 的裸请求。定位到异常 shard 后,显式指定目标:
_cat/recovery 会给出恢复阶段、传输字节、文件数、进度和耗时。大量 recovery 同时跑,或者进度长时间不动,就去看磁盘吞吐、网络、源节点负载和 shard 大小。
allocation explain 里每个 decider 都会写明同意或拒绝的原因。现场常见的是:
- 节点磁盘超过 watermark;
- index 或 cluster allocation filter 排除了可用节点;
- data tier、节点角色或 awareness 属性不匹配;
- 同一 shard 的副本不能与 primary 分配到同一节点;
- 可用节点或容量不足;
- allocation 被临时关闭或延迟。
看到 UNASSIGNED 先别急着 reroute。若 decider 拒绝分配的根因还在,强制操作只会盖住容量问题,有时还会把数据置于风险中。
第五步:检查线程池、磁盘和后台负载
| |
把两次采样放在一起比较:
queue长期不下降,表示任务进入速度超过处理速度;rejected持续增长,表示对应线程池已经无法接收更多任务;- merge 的累计时间、字节数快速增长,可能存在显著写入或 merge 压力;
- segment 数量异常多,可能放大 heap、文件句柄和 merge 开销;
- refresh、flush 或 indexing 指标短时间快速增加,需要与业务流量核对。
fs.io_stats 也是累计计数,不能拿它单独证明磁盘延迟高。主机或云盘监控至少还要看:
- CPU iowait;
- read/write latency;
- queue depth;
- disk utilization;
- 可用空间和 inode;
- 节点间网络延迟、丢包和吞吐。
如果 DELETE 已经 ack,空间却没回来,检查 Elasticsearch 进程是否还持有已删除文件、节点是否健康,以及底层存储或容器文件系统的统计有没有延迟。这个场景继续盯 pending tasks 通常收获不大。
快速决策树
| |
这棵树不是互斥选项。比如 recovery 产生的大量 shard-started 任务,既会让 pending tasks 增长,也会让 shard 长时间处于 INITIALIZING。两种信号同时出现时,先查能解释更多现象的那条线,同时保留另一条线的采样结果。
五条命令完成第一轮分流
时间紧张时,先采集下面五条:
| |
这五条跑完,第一轮方向通常就有了:
| 观察结果 | 优先方向 |
|---|---|
| pending tasks 等待长,index/shard 总量高 | cluster-state、master、oversharding |
| initializing、relocating、unassigned shard 多 | allocation、recovery |
| 少数节点磁盘高、shard 分布不均 | disk watermark、allocation rule、节点容量 |
| 上述基本正常 | JVM、线程池、hot threads、OS 与同期任务 |
几个容易走偏的地方
先入为主地怪罪大索引
新建空索引时还没有业务数据。多个管理操作一起慢,先看它们共用的 cluster-state 和 master 路径。大 shard 确实麻烦,但影响更常出现在 recovery、relocation、merge 和节点重启恢复时。
把一次空的 pending tasks 当作结论
pending tasks 是瞬时视图。任务可能刚处理完,也可能卡在 cluster-state 发布或节点确认阶段。要把前后两次采样与 master 资源、真实请求耗时对上,才能判断。
认为 DELETE 成功后磁盘必须立刻下降
API 确认和物理空间可见是两个时间点。文件句柄、底层文件系统、存储平台统计和节点 I/O 都可能影响空间回收的可见时间。
一看到 shard 多就改集群配置
删除索引、降低副本、关闭 allocation、强制 reroute 都会影响业务。先确认根因,再做容量评估、数据保留确认和变更审批。
查到原因之后
方向确认后,可以暂停非必要的批量建索引,把 rollover 或 recovery 错开,必要时压低同期写入峰值。这些动作能争取处理时间,不能代替后续治理。
后续可以从这些地方下手:
- 合并过细的时间索引,按真实数据量设计 rollover 条件;
- 用 index template 统一合理的 primary 和 replica 数;
- 定期统计 index、shard、segment 和 mapping 字段数量的增长趋势;
- 为 master-eligible 节点保留稳定的 CPU、heap 和网络资源;
- 为 cluster operation latency、pending task 最大等待时间、unassigned shard 和磁盘水位建立告警;
- 在扩容或版本升级前,用真实 mapping、shard 数和变更频率进行容量验证。
我实际使用的排查顺序
现场排查时,我会按这条顺序走:
- 用 cluster health 和 pending tasks 判断 cluster-state 是否积压;
- 用 cluster stats、indices 和 shards 判断是否 oversharding;
- 用 master JVM、tasks 和 hot threads 确认协调节点压力;
- 用 recovery 和 allocation explain 定位 shard 无法稳定的原因;
- 用双时点线程池、I/O 与主机监控判断底层资源瓶颈。
shard 数量、某一刻的 heap,或者单条 API 的 ack,都不能独立证明根因。先把前后两次采样对起来,确定问题落在 cluster-state/master、oversharding、allocation/recovery 还是 disk/OS,再动配置。