为什么你的 Elasticsearch 集群触发了磁盘水位线:14 个真实世界原因解析

17 阅读25分钟

作者:来自 Elastic Stef Nestor

了解 Elasticsearch 磁盘水位线的工作原理、触发原因,以及如何诊断 Support 团队遇到的 14 种最常见场景,从索引膨胀到 ILM 停滞。

更多阅读:

了解将数据摄取到 Elasticsearch 的不同方式,并深入研究实际示例,尝试一些新的内容。

Elasticsearch 提供了大量新功能,帮助你针对自己的使用场景构建最佳搜索解决方案。立即开始免费的云试用,或在本地机器上体验 Elastic。


Elasticsearch磁盘水位线系统不仅仅是一个告警机制:它会主动代表你采取响应措施,在磁盘使用率达到 85% 时停止分配分片,在达到 90% 时将分片迁移出节点,在达到 95% 时阻止所有数据摄取。当它被触发时,根本原因通常并不明显。本文涵盖了 Support 团队最常遇到的 14 种场景,包括索引数据增长、缓存磁盘使用以及 ILM 停滞,并提供诊断每种情况所需的具体 API 调用和分析思路。

Elasticsearch 磁盘水位线分配机制如何工作

Elasticsearch 假设同一个数据层中的所有节点都具有相同的硬件配置。这使其分配功能能够在目标节点之间分布索引分片。分配过程会依次根据集群级设置和过滤器进行计算,然后检查单个节点的磁盘水位线,最后再考虑分片感知机制。

在这些逻辑前提下,分配过程会运行一个 desired balancer 组件,通过计算数据流写入负载、节点总分片数、节点磁盘使用量以及索引分片分布等权重来管理节点可用磁盘空间。分配机制及其 desired balancer 组件会根据当前集群状态计算下一步操作。随后,分片会被重新路由,并异步恢复到被认为能够改善整体集群均衡性的目标节点。

Elasticsearch 文档强调,节点暂时超过高水位线,以及节点之间(包括同一数据层内)磁盘使用量存在较大差异,都是正常现象。例如,这可能发生在摄取流量激增、force merge 操作期间,或者大型索引执行 ILM rollovershrinkmigrate 操作之间。也可能是由于分片大小差异过大造成的。

Elasticsearch 管理员可能需要检查集群节点的磁盘使用情况。最常见的表现形式是 Elasticsearch 的 health API 报告问题,通常显示为水位线错误,或者表现为 ILM 索引停滞等常见子问题。

`

1.  # GET _health_report?filter_path=indicators.disk.status,indicators.ilm.status
2.  {
3.    "indicators": {
4.      "disk": {
5.        "status": "yellow"
6.      },
7.      "ilm": {
8.        "status": "yellow"
9.      }
10.    }
11.  }

`AI写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

Elastic 建议启用监控功能,以便在主机磁盘被写满之前及时收到告警。

Elasticsearch 提供了磁盘水位线功能,以避免磁盘耗尽问题。该功能不仅仅是业界常见的磁盘告警机制,因为分配系统会自动代表管理员采取行动,避免可用磁盘空间被耗尽。默认的磁盘水位线阈值及其影响如下:

  • 85% 的低水位线:停止向该节点分配更多分片,但仍允许向该节点摄取数据。

  • 90% 的高水位线:将分片迁移出该节点,但仍允许向该节点摄取数据。

  • 95% 的 Flood Stage 水位线:通过将索引设置为只读模式,停止向该节点进行所有数据摄取。当节点恢复到低于高水位线后,只读写入阻塞会自动解除。

注意:Elastic Cloud Hosted(ECH)部署界面会在 75% 时显示红色警告横幅,但此时 Elasticsearch 不会采取任何行动。

磁盘水位线设置位于集群设置中:

`

1.  # GET _cluster/settings?include_defaults&filter_path=*.cluster.routing.allocation.disk.watermark
2.  {
3.    "defaults": {
4.      "cluster": {
5.        "routing": {
6.          "allocation": {
7.            "disk": {
8.              "watermark": {
9.                "flood_stage.frozen.max_headroom": "20GB",
10.                "flood_stage": "95%",
11.                "high": "90%",
12.                "low": "85%",
13.                "flood_stage.frozen": "95%",
14.                "flood_stage.max_headroom": "100GB",
15.                "low.max_headroom": "200GB",
16.                "high.max_headroom": "150GB"
17.              }
18.            }
19.          }
20.        }
21.      }
22.    }
23.  }

`AI写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

如何使用 CAT allocation 诊断 Elasticsearch 磁盘使用情况

Elasticsearch 开发团队创建了一个统一的 端点 CAT allocation,作为你排查问题时的单一入口,用于汇总磁盘信息。当前磁盘统计信息也可以在 node stats 中查看(或者通过映射方式转换为 CAT allocation 的形式)。

使用 CAT allocation 返回的列名,下面这张截图(来自一个相关的数据增强请求)展示了其含义解释:

对于这个输出,我们通过“问题框定(problem boxing) ”开始排查,检查以下几点:

  1. 同一数据层内,不同节点 roledisk.total 是否存在差异。如果存在,则说明该集群的 硬件配置不均衡

  2. 是否存在被标记为 UNASSIGNED 的分片。如果存在,请参考 红色或黄色健康状态

  3. 是否存在热点节点(hot-spotted node),或者整个数据层的 disk.percent 超过低水位线阈值。

  • 注意:冻结(frozen)层出现 disk.indices: 0gbdisk.percent: 95 是预期行为,因为其 部分可搜索快照 本身存放在磁盘缓存中,并会自行管理以避免磁盘被填满。这也是 Elasticsearch 推荐使用 专用冻结节点 的原因之一。
  1. 单个或多个节点的 disk.indicesdisk.used 之间存在较大差异。

磁盘水位线问题可能来源于以下情况:

  • 可用磁盘被以下因素消耗:

    • 操作系统(OS)上的其他服务。

    • Elasticsearch 服务未正确设置 日志保留策略

    • Elasticsearch 索引数据。

    • Elasticsearch 数据缓存。

  • 也可能出现误报或漏报:

    • 意外的 Elasticsearch 磁盘水位线设置。

    • 磁盘水位线设置未与 XFS 配额(磁盘使用限制工具)对齐,导致通过 disk.available 降低而不是 disk.used_percent 升高来体现。

不过,我们接下来将重点关注由 Elasticsearch 索引数据和数据缓存引起的 flood-stage 磁盘水位线错误,因为它们是过去一年中大多数高严重性 Support 案例的根本原因。ILM 会单独作为一个章节处理,因为它可能在两种场景中同时出现。示例按出现频率从高到低排列。

常见 Elasticsearch 磁盘水位线场景

由索引数据导致的磁盘水位线问题

CAT allocation 报告 disk.indices 接近水位线阈值时,就会出现这种情况。默认的 flood-stage 水位线为 95%。由于 ECH 不会将 XFS 配额暴露给 Elasticsearch,因此当 disk.indices 接近节点的 disk.total 时也会出现该问题。以下是在这些假设下的一些示例。

A. 索引使用情况

第一个例子,我们来看一个单节点集群:

`

1.  # GET _cat/allocation?v&s=node&h=node,disk.*,shards
2.  node             	disk.indices disk.used disk.total disk.percent shards
3.  UNASSIGNED                                                           2
4.  instance-0000000000    11.5gb    11.8gb       12gb           96     36

`AI写代码

这是行业中典型的 “数据库几乎满了” 磁盘场景。磁盘几乎被占满,因此它拒绝为新创建索引的两个分片分配节点。实际索引数据占用了 11.5GB,也就是该节点 11.8GB 磁盘空间的 95%。

为了避免磁盘达到 100%(这在不同操作系统上可能会在 Elasticsearch 日志中表现为 no space left on the device),应尽快进行干预。可考虑的缓解方案包括:

  • 纵向扩容(增加节点磁盘容量)

  • 横向扩容(增加节点数量)

  • 删除不需要的索引(可能在快照之后执行)

B. 索引分片与节点差异

第二个简单例子:现在有两个节点,它们只差一个分片,但其中一个节点的 disk.indices 比另一个高出 11GB:

`

1.  # GET _cat/allocation?v&s=node&h=node,disk.*,shards
2.  node             	disk.indices disk.used disk.total disk.percent shards
3.  instance-0000000001    11.5gb    11.8gb       12gb           96     11
4.  instance-0000000000     0.5gb     0.8gb       12gb            0     10

`AI写代码

要排查这种情况,需要结合 CAT shards 一起分析。此例的根因是某个索引配置为 1 个主分片(number_of_shards)且副本数为 0(number_of_replicas)(也称 “1p0r”),该分片本身就有 11GB。由于这种情况,Elasticsearch 无法在节点之间均衡磁盘。

修复方式可以考虑更新索引设置增加副本来平衡磁盘;但这样会让另一节点进入 flood-stage 水位线,因此必须同时考虑扩容磁盘。

C. 大分片(Large shard)

在上一个例子的基础上,如果该单分片大小是 300GB,这种情况在 Support 中更常见,通常是由于分片大小超出 Elasticsearch 推荐的 10–50GB 范围。

在这种情况下,建议在确保有足够磁盘空间用于数据复制的前提下进行分片重构:

更多细节与注意事项见链接指南。理想情况下,这个索引应调整为在两个节点上分成 6 个主分片,以达到推荐的最大 50GB 分片大小。为了让主分片更均匀分布,可能需要设置 total_shards_per_node 相关配置

D. 已删除文档(Deleted docs)

再扩展这个例子,作为临时缓解,可以检查已删除文档。Elasticsearch 会定期清理索引中的 docs.deleted,可通过 CAT indices 查看:

`

1.  # GET _cat/indices?v&h=index,docs.*
2.  index         	docs.count docs.deleted
3.  my-index-000001       23791010      9192030
4.  my-index-000002      187391903           0

`AI写代码

docs.deleted > 0 时,这些也会计入 CAT allocationdisk.indices。由于分片是不可变的,因此为了提前清理,可以执行 forcemerge,并加上 only_expunge_deletes 参数,例如:

`POST my-index-000001/_forcemerge?only_expunge_deletes=true` AI写代码

E. 分片大小不均(Varied shard sizes)

这是一个历史案例,因为它在用户升级前仍然会带来较高 Support 负载。在 v8.6 之前,只要同一数据层内分片数量均衡,Elasticsearch 就认为集群是 balanced,而不考虑分片大小差异或写入负载分布。

因此可能出现“分片数量均衡,但磁盘差异极大”的情况:

`

1.  # GET _cat/allocation?v&s=node&h=node,disk.*,shards
2.  node             	disk.indices disk.used disk.total disk.percent shards
3.  instance-0000000002	     40.0gb    40.5gb     60.0gb         67      37
4.  instance-0000000001	     40.1gb    40.5gb     60.0gb         67      37
5.  instance-0000000000	      1.5gb     0.8gb     60.0gb          2      37

`AI写代码

这类情况虽然在旧的平衡机制下是 “均衡” 的,但会导致 ingest 热点问题(hot spotting)。因此 Elasticsearch 在 v8.6 引入了 desired balance扩展了分配策略,纳入数据流写入负载和节点磁盘使用情况,从而显著减少这类问题。

默认建议升级到 v8.6 或更高版本。Elastic 通常建议使用最新版本。

在无法升级的情况下,可以通过以下方式临时干预:

  • 使用 cluster reroute 将高写入索引分散到不同节点

  • 通过合理设计分片数量,并使用 [total_shards_per_node](https://www.elastic.co/guide/en/elasticsearch/reference/current/allocation-total-shards.html "total_shards_per_node") 进行控制

更多内容见 hot spotting 指南中的索引级分片分布章节。

由缓存数据导致的磁盘水位线问题

Elasticsearch 会在每个节点上保留数据缓存,这可以通过 CAT allocationdisk.used - disk.indices 的差值来观察。这个缓存是按索引进行跟踪的,并会在索引达到 health .status:green 且没有待处理迁移请求时被释放。因此我们来看一些常见场景。

F. 删除索引

删除索引 会将其占用空间从 disk.indices 转移到磁盘缓存中,然后由 Elasticsearch 异步清理。因此,对于一个 1p0r 索引(且该节点上只有这一个索引),删除索引时在连续 API 查询中会看到如下变化:

`

1.  # GET _cat/allocation?v&s=node&h=node,disk.*,shards
2.  node            	disk.indices disk.used disk.total disk.percent shards
3.  instance-0000000000	     40.0gb    40.5gb     60.0gb         67      1

5.  # DELETE my-index-000001

7.  # GET _cat/allocation?v&s=node&h=node,disk.*,shards
8.  node            	disk.indices disk.used disk.total disk.percent shards
9.  instance-0000000000	        0gb    40.5gb     60.0gb         67      0

11.  # GET _cat/allocation?v&s=node&h=node,disk.*,shards
12.  node            	disk.indices disk.used disk.total disk.percent shards
13.  instance-0000000000	        0gb     0.5gb     60.0gb         0      0

`AI写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

注意:异步清理过程可能存在轻微延迟,这是预期行为。

G. 分片复制

再来看分片复制的情况。在迁移或复制过程中(可通过 CAT recovery 查看),参与的每个节点都会保留一份副本,直到目标节点确认分片完整性为止。这与 CAT indices 显示索引 health:green 的时间点一致。

这意味着,如果节点 instance-0000000000 正在向 instance-0000000001 复制,但失败后改为向 instance-0000000002 复制,那么在 instance-0000000002 确认与 instance-0000000000 的分片完整性之前,这三个节点都会保留该分片的磁盘缓存。

为了说明方便,我们简化 CAT allocation 的输出:

`

1.  # GET _cat/allocation?v&s=node&h=node,disk.*,shards
2.  node            	disk.indices disk.used disk.total disk.percent shards
3.  instance-0000000000       10.0gb   10.5gb     100.0gb          10      1
4.  instance-0000000001        0.0gb    0.5gb     100.0gb           0      0
5.  instance-0000000002        0.0gb    0.5gb     100.0gb           0      0

7.  # GET _cat/indices?v&h=index,health,shards.*
8.  index            health  pri rep
9.  my-index-000001  yellow    1   1

11.  # (恢复到 instance-0000000001)

13.  # GET _cat/allocation?v&s=node&h=node,disk.*,shards
14.  node            	disk.indices disk.used disk.total disk.percent shards
15.  instance-0000000000       10.0gb   10.5gb     100.0gb          10      1
16.  instance-0000000001        5.0gb    5.5gb     100.0gb           5      1
17.  instance-0000000002        0.0gb    0.5gb     100.0gb           0      0

19.  # (分片复制失败)

21.  # GET _cat/allocation?v&s=node&h=node,disk.*,shards
22.  node            	disk.indices disk.used disk.total disk.percent shards
23.  instance-0000000000       10.0gb   10.5gb     100.0gb          10      1
24.  instance-0000000001        0.0gb    5.5gb     100.0gb           5      0
25.  instance-0000000002        0.0gb    0.5gb     100.0gb           0      0

27.  # (恢复到 instance-0000000002)

29.  # GET _cat/allocation?v&s=node&h=node,disk.*,shards
30.  node            	disk.indices disk.used disk.total disk.percent shards
31.  instance-0000000000       10.0gb   10.5gb     100.0gb          10      1
32.  instance-0000000001        0.0gb    5.5gb     100.0gb           5      0
33.  instance-0000000002       10.0gb   10.5gb     100.0gb          10      1

35.  # GET _cat/indices?v&h=index,health,shards.*
36.  index            health  pri rep
37.  my-index-000001  green     1   1

39.  # GET _cat/allocation?v&s=node&h=node,disk.*,shards
40.  node            	disk.indices disk.used disk.total disk.percent shards
41.  instance-0000000000       10.0gb   10.5gb     100.0gb          10      1
42.  instance-0000000001        0.0gb    0.5gb     100.0gb           0      0
43.  instance-0000000002       10.0gb   10.5gb     100.0gb          10      1

`AI写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

在这种情况下,Elasticsearch 行为是正常的。当 CAT allocation 显示 disk.indices << disk.used 时,首先应检查并确保 cluster healthstatus:green,并确认 CAT indices 也是 health:green

H. 分片迁移

即使索引或集群状态是 green,Elasticsearch 仍可能在有意保留缓存数据,这通常发生在分片迁移过程中。这在 ILM 执行时尤其常见,后面章节会详细介绍。

这里我们考虑 node attributesindex shard allocation filtering 中的影响,以及 allocation explain 返回 can_remain_on_current_node:no 的情况。

例如,当你更新索引设置,使副本不能留在当前节点,但节点在迁移过程中重启,分片开始迁移到其他节点,而原节点在迁移完成前重新加入集群。这种情况下,由于副本源未丢失,索引不会变成 status:yellow,但迁移未完成,因此会暂时出现相同的磁盘缓存占用,直到迁移完成后释放。

`

1.  # GET _cat/allocation?v&s=node&h=node,disk.*,shards
2.  node            	disk.indices disk.used disk.total disk.percent shards
3.  instance-0000000000       10.0gb   10.5gb     100.0gb          10      1
4.  instance-0000000001       10.0gb   10.5gb     100.0gb          10      1
5.  instance-0000000002        0.0gb    0.5gb     100.0gb           0      0
6.  instance-0000000003        0.0gb    0.5gb     100.0gb           0      0

8.  # GET _cat/indices?v&h=index,health,shards.*
9.  index            health  pri rep
10.  my-index-000001  green     1   1

12.  # GET _cat/shards/my-index-000001?v&h=sh prirep state node
13.  sh prirep   state     node
14.  0  p       STARTED instance-0000000000
15.  0  r       STARTED instance-0000000001

17.  # (更新索引设置,使 replica 需要迁移到 instance-0000000002)

19.  # GET _cat/recovery?v&h=idx,sh,snode,tnode
20.  idx             sh snode tnode
21.  my-index-000001 0 instance-0000000001 instance-0000000002

23.  # (instance-0000000002 丢失,迁移转向 instance-0000000003,随后 instance-0000000002 重新加入)

25.  # GET _cat/recovery?v&h=idx,sh,snode,tnode
26.  idx             sh snode tnode
27.  my-index-000001 0 instance-0000000001 instance-0000000003

29.  # GET _cat/allocation?v&s=node&h=node,disk.*,shards
30.  node            	disk.indices disk.used disk.total disk.percent shards
31.  instance-0000000000       10.0gb   10.5gb     100.0gb          10      1
32.  instance-0000000001       10.0gb   10.5gb     100.0gb          10      1
33.  instance-0000000002        5.0gb    5.5gb     100.0gb           5      0
34.  instance-0000000003        9.0gb    9.5gb     100.0gb           9      0

36.  # (迁移完成,分片完整性确认,缓存释放)

38.  # GET _cat/allocation?v&s=node&h=node,disk.*,shards
39.  node            	disk.indices disk.used disk.total disk.percent shards
40.  instance-0000000000       10.0gb   10.5gb     100.0gb          10      1
41.  instance-0000000001        0.0gb    0.5gb     100.0gb           0      0
42.  instance-0000000002        0.0gb    0.5gb     100.0gb           0      0
43.  instance-0000000003       10.0gb   10.5gb     100.0gb          10      1

`AI写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

在这种情况下,需要检查 shard 的 allocation explain 来判断迁移是否被阻塞或处于某个条件限制中。

I. 迁移停滞

前一个问题也可能发生在迁移停滞时,例如 ECH 计划更新了 cluster settings 将某个节点排除,但计划在迁移过程中被取消,就会出现类似现象:

`

1.  PUT _cluster/settings
2.  {"transient": {"cluster.routing.allocation.exclude._name": "instance-0000000000"}}

`AI写代码

此时应临时取消该设置,直到在 Deployment > Activity 中重新应用计划,或通过 allocation explain 检查被排除节点上的分片为何未迁移。

J. 版本问题

以下是一些边缘情况,通常通过升级可以避免:

  • 旧版本中可能存在 disk cache reaper 服务未重试的问题,已在 v8.13.0 通过 elasticsearch#106544 修复,目前没有已知替代方案。

  • 在 v9.4 中仍可能存在一种情况:节点重启进入 flood-stage 后,如果缓存导致 disk.indices 与磁盘占用关系发生变化,缓存可能不会按预期释放,该问题仍在 elasticsearch#104667 讨论中。当前唯一已知解决方法是临时扩容磁盘;如在 ECH 遇到该问题,请联系 Elastic Support。

由 ILM 相关导致的 Elasticsearch 磁盘水位线问题

前面的迁移示例展示了在 ILM(ILM migrateILM shrink)执行过程中可能出现的类似问题。这是因为 ILM 会基于时间或逻辑条件自动执行管理操作,并以异步方式替用户完成。因此,在正常管理操作中也可能出现类似的分配问题,并且 ILM 场景下往往需要与普通情况相同的手动干预方式。

Elasticsearch 的 health API 提供了 ILM 指标,用于判断是否需要干预,例如某个步骤停留时间过长或出现明确错误。

K. Step 错误

当使用 ILM rollover 的写入目标配置不正确时,hot 节点可能因为 ILM rollover 错误 而被填满。

由于 rollover 会通过 ILM explainis_auto_retryable_error:true 自动重试,并结合 ILM 的  indices.lifecycle.poll_interval 设置运行,因此这些错误可能表现为:

  • failed_step_retry_count: >0

  • step:ERROR,并带有最新失败信息

`

1.  # GET my-index-000001/_ilm/explain
2.  {
3.    "index" : "my-index-000001",
4.    "managed" : true,
5.    "policy" : "my_policy",
6.    "index_creation_date" : "2022-10-09T17:41:12.581Z",
7.    "index_creation_date_millis" : 1665337272581,
8.    "time_since_index_creation" : "631.68d",
9.    "lifecycle_date" : "2022-10-09T17:41:12.581Z",
10.    "lifecycle_date_millis" : 1665337272581,
11.    "age" : "631.68d",
12.    "phase" : "hot",
13.    "phase_time" : "2022-11-06T17:58:01.766Z",
14.    "phase_time_millis" : 1667757481766,
15.    "action" : "rollover",
16.    "action_time" : "2022-10-09T17:41:12.911Z",
17.    "action_time_millis" : 1665337272911,
18.    "step": "ERROR",
19.    "step_time" : "2022-11-06T17:58:01.766Z",
20.    "step_time_millis" : 1667757481766,
21.    "failed_step" : "check-rollover-ready",
22.    "is_auto_retryable_error" : true,
23.    "failed_step_retry_count" : 316,
24.    "step_info": {
25.      "type": "security_exception",
26.      "reason": "action [indices:admin/settings/update] is unauthorized for API key id [XXXXX] of user [test] on restricted indices [my-index-000001], this action is granted by the index privileges [manage,all]"
27.    },
28.    "phase_execution" : {
29.      "policy" : "my_policy",
30.      "phase_definition" : {
31.        "min_age" : "0ms",
32.        "actions" : {"rollover" : {"max_age" : "30d", "max_size" : "50gb" } }
33.      },
34.      "version" : 1,
35.      "modified_date" : "2021-12-13T16:25:49.356Z",
36.      "modified_date_in_millis" : 1639412749356
37.    }
38.  }

`AI写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

如果当前没有显示失败信息,但 failed_step_retry_count: >0,建议检查 ILM history index 并定位具体索引的错误原因。

在该示例中,问题是由于权限不足的用户修改了 ILM policy,解决方式是使用具备足够权限的用户重新保存 policy,或为用户赋予权限。

相关问题可参考 elasticsearch#72856,该讨论涉及未来可能让 ILM 执行用户变为无关用户(user-agnostic)。

L. 为什么即使有后续数据层,hot tier 仍然会被填满?

ILM 用于将数据从高温数据层迁移到低温数据层(data tiers)。如果后续数据层不存在或出现 watermark 问题,就会导致前面的数据层堆积。

例如,一个 ILM policy 设置为:

  • hot:1 小时 rollover

  • 立即移动到 frozen

  • 3 天后删除

但如果 frozen tier 不存在,那么 ILM 在执行 顺序执行 时就无法推进删除步骤,数据会持续堆积在 hot tier,并最终导致磁盘填满。

这种情况下的表现可能如下:

`

1.  # GET _cat/allocation?v&s=node&h=node,disk.*,shards,role
2.  node                disk.indices.forecast disk.indices disk.used disk.avail disk.total disk.percent shards role
3.  UNASSIGNED                                                                                             103 
4.  instance-0000000003                 189gb      161.4gb   161.6gb     18.3gb      180gb           89    120 himrst
5.  instance-0000000007               135.2gb      109.6gb   179.9gb      7.1mb      180gb           99     41 himrst

`AI写代码

health report 中 ILM 指标会提示多个迁移停滞索引:

`

1.  # GET _health_report?filter_path=indicators.ilm.status,indicators.ilm.symptom,indicators.ilm.details
2.  {
3.    "indicators": {
4.      "ilm": {
5.        "status": "yellow",
6.        "symptom": "65 indices have stayed on the same action longer than expected.",
7.        "details": {
8.          "stagnating_indices_per_action": {
9.            "allocate": 0,
10.            "shrink": 0,
11.            "searchable_snapshot": 0,
12.            "rollover": 0,
13.            "forcemerge": 0,
14.            "delete": 0,
15.            "migrate": 65
16.          },
17.          "policies": 61,
18.          "stagnating_indices": 4,
19.          "ilm_status": "RUNNING"
20.        }
21.      }
22.    }
23.  }

`AI写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

通过 jq 分析 ILM explain,可以验证状态:

`cat ilm_explain.json | jq -c '.indices[]|select(.managed==true)|.phase+"/"+.action+"/"+.step' | sort | uniq -c | sort -r` AI写代码

结果显示 frozen tier 没有可用节点:

`65 "frozen/searchable_snapshot/wait-for-data-tier"` AI写代码

同时也可以看到:

`65 "no nodes for tiers [data_frozen] available"` AI写代码

因此,要解决 hot 磁盘水位线问题,你需要添加 frozen 节点。如果这些索引在 frozen 步骤上等待了好几天,你也可以考虑手动 删除索引

在这个例子中,我们根据 min age 的计算方式 预计索引最多只会存在“一天加一小时”,但实际数据却显示已经存在七天。

`

1.  $ cat ilm_explain.json | jq -c '.indices[]|select(.managed==true)|.age' | sort | uniq -c | sort -r | head -4
2.    24 "7d"
3.    20 "4d"
4.    20 "5d"
5.    10 "6d"

`AI写代码

Elastic Cloud 可以代表你处理 autoscaling,以避免这些问题的发生。

M. 为什么 ILM 索引卡在 migrate 步骤?

接下来,我们来看一个更常见的历史案例。在 Elasticsearch 还没有正式引入 data tiers 之前,用户通常使用 自定义节点属性 来区分不同类型的机器。

这种方式在很大程度上已经被 迁移到 node roles 的方式 所取代,但仍然偶尔会遇到只完成部分迁移的集群。同样地,虽然 data tiers 假设同一 data tier 内节点具有相同硬件配置,但在一些特殊场景中,仍然有人将自定义节点属性与 ILM 一起使用。这里我们先讨论第一种情况,因为“自定义节点属性与 ILM 发生冲突”是更常见的问题来源。

这一次,我们假设有 hot 和 warm 两个数据层,而 hot 层几乎满了,warm 层是完全空的。ILM 本应在 rollover 一小时后立即将数据迁移过去。但与前面的例子一样,ILM health report 仍然会显示索引停滞,不过这次会是:

`

1.  # GET _all/_ilm/explain?human&expand_wildcards=all
2.  $ cat ilm_explain.json | jq -c '.indices[]|select(.managed==true)|.phase+"/"+.action+"/"+.step' | sort | uniq -c | sort -r
3.    30 "warm/migrate/check-migration"
4.    10 "hot/rollover/check-rollover-ready"

`AI写代码

有时 step_info.message 会直接给出具体的分配错误信息,但有时你需要运行 allocation explain(以及其 常见输出)来判断分片为什么无法迁移到 warm 节点。

`

1.  # GET _cluster/allocation/explain
2.  # {"index": "my-index-000001", "shard": 0, "primary": true}
3.  ... # 为简化仅截取当前分片所在 hot 节点的部分输出
4.  "deciders": [
5.    {
6.      "decider": "filter",
7.      "decision": "NO",
8.      "explanation": "node does not match index setting [index.routing.allocation.include] filters [box_type:\"hot\"]"
9.    },
10.    {
11.      "decider": "data_tier",
12.      "decision": "NO",
13.      "explanation": "index has a preference for tiers [data_warm] and node does not meet the required [data_warm] tier"
14.    }
15.  ]
16.  ...

`AI写代码![](https://csdnimg.cn/release/blogv2/dist/pc/img/runCode/icon-arrowwhite.png)

这个例子展示了一个冲突:同一个分片同时被要求留在 hot 节点,又被要求迁移到 warm 节点。

Elastic 建议用户使用默认开启的 ILM migrate 来在 data tiers 之间移动数据。也可以选择禁用它,改为使用 ILM allocate + 自定义属性的方式。理论上两者也可以同时使用,但如本例所示,如果同时启用,必须非常谨慎地避免冲突。

尤其要注意 ILM 的执行顺序是 allocate 在 migrate 之前,如果在第一步就设置了阻塞条件,即使第二步可以解决,也会导致整体流程卡住,因此所有设置必须在每个步骤中都保持自洽。

N. ILM 中 min_age 与 rollover 是如何交互的?

前面我们已经简单提到过 ILM rollover 与阶段 min_age 设置之间的关系,这里我们单独用一个例子来说明。

当用户在 Elasticsearch 中平衡 10–50GB 分片大小 的建议与索引生命周期策略时,通常会同时考虑多种 rollover 触发条件。在这个例子中,我们假设索引从创建开始,使用默认 rollover 策略:

`

1.  # GET _ilm/policy/ilm-history-ilm-policy?filter_path=*.policy.phases.hot.actions.rollover
2.  {"ilm-history-ilm-policy": {"policy": {"phases": {"hot": {
3.      "actions": {
4.        "rollover": {
5.          "max_age": "30d",
6.          "max_primary_shard_size": "50gb"
7.        }
8.      }
9.  } } } } }

`AI写代码

只要任何一个主分片没有达到 50GB,这个索引就会一直在 hot 节点上写入数据,直到达到 max_age:30d 时触发 rollover。

但关键问题是:rollover 之后会发生什么?这取决于下一个阶段的 min_age。在这个例子中,下一个阶段是 warm tier,而默认配置如下:

`

1.  # GET _ilm/policy/ilm-history-ilm-policy?filter_path=*.policy.phases.warm.min_age
2.  { "ilm-history-ilm-policy": {"policy": {"phases": {
3.      "warm": {
4.        "min_age": "0ms"
5.      }
6.  } } } }

`AI写代码

一个阶段的 min_age 是基于索引的 rollover 时间来计算的。但如果索引还没有发生 rollover,那么它的 age 就等于 creation_date

用户有时会错误地理min_ageage,把它当成 “数据应该在某个 tier 存放的总时间”,但他们往往忽略了 rollover 本身消耗的时间。

因为没有从总时间里扣除 rollover 所花费的时间,索引在 rollover 之后会“立即”进入 warm tier。这本身不会立刻报错,但会导致数据比预期更快进入 warm 层,从而逐渐增加磁盘压力,最终可能引发 watermark(磁盘水位线)问题。

获取 Elasticsearch 磁盘问题帮助

根据我在 Elastic Support 中看到的情况,这就是最常见的集群磁盘问题总结。希望你现在也已经理解了相关原理和对应的解决思路。

不过,如果你在解决问题时仍然卡住,也可以随时联系我们,我们很乐意提供帮助!你可以通过以下渠道联系:

本文中描述的任何功能或发布时间,均由 Elastic 单方面决定。任何当前不可用的功能或特性,可能不会按时交付,甚至可能不会交付。

原文:Elasticsearch disk watermark: 14 troubleshooting scenarios - Elasticsearch Labs