磁盘水位与容量规划:三档水位、分片规划与扩容决策

系统讲解 Elasticsearch 的磁盘水位机制与容量规划方法:low/high/flood 三档水位的作用与默认值、只读索引块与写拒绝的触发条件、分片大小与数量的规划原则,以及基于增长趋势的扩容决策流程。

集群磁盘写满是 Elasticsearch 运维中最常见也最容易预防的事故。一旦触发 flood 水位,所有索引被强制设为只读,写入全线中断,恢复要靠手工清块并等待分片重新分配,代价极高。更隐蔽的是 low 与 high 水位之间的灰色地带:分片不再迁入、新索引无法分配,集群表面上还在跑,直到某个节点彻底撑不住。本文讲清三档水位的确切行为、分片大小与数量的规划原则,以及如何用数据而不是感觉来做扩容决策。

1. 磁盘水位的意义

一句话总结: 水位机制是 Elasticsearch 的自我保护,用三档阈值把「磁盘将满」这个致命状态拆成可干预的三个阶段。

1.1 为什么需要水位

Elasticsearch 的分片分配是自动的,如果没有磁盘约束,主节点会把分片分配到任意节点,直到某个节点磁盘写满。写满的后果不是「写入失败」这么简单:该节点上的分片无法写入、副本无法同步、集群状态可能变红。水位机制让集群在磁盘接近满时主动收缩写入与分配,把故障控制在可恢复的范围内。

1.2 检查的粒度

水位按节点上的每个数据路径独立计算,而不是整机磁盘总量。如果一台机器上挂了多个数据盘(path.data 配置多个目录),每个盘单独判定。这带来一个常见误解:机器上还有另一块空盘,但某个数据路径已经超过水位,节点照样进入只读。

1.3 检查频率

主节点定期(默认每 30 秒)收集各数据节点的磁盘使用情况并重新评估水位。也就是说,水位不是实时触发的,从磁盘超过阈值到集群做出反应,最多有几十秒延迟。这解释了为什么「刚刚还好好的」突然就只读了——水位评估在后台周期性跑,不是每次写入都检查。

2. 三档水位

一句话总结: low 禁止分片迁入、high 开始尝试迁出分片、flood 强制所有索引只读,三档逐级加码。

2.1 默认阈值

水位默认阈值触发后的行为
low85%新分片不再分配到该节点
high90%尝试把分片迁出该节点
flood95%该节点上所有索引设为只读

阈值基于磁盘使用率,不是剩余空间。对大容量磁盘(如 4TB),95% 意味着还剩 200GB,看似宽裕,但分片迁移、merge 和快照都需要临时空间,实际余量并不安全。

2.2 low 水位

达到 low 水位后,主节点不再把新分片分配到该节点,但已有分片继续正常工作,也不会主动迁出。这个阶段的典型症状是「新索引的副本一直处于 unassigned 状态」,因为找不到满足条件的节点。

2.3 high 水位

达到 high 后,主节点开始尝试把该节点上的分片迁移到其他节点。迁移是有条件的:目标节点必须低于 low 水位、满足分片分配过滤规则。如果所有节点都接近满,迁移会失败并反复重试,集群状态长时间处于 yellow 或 red。

2.4 flood 水位

这是最后一道防线。达到 flood 后,Elasticsearch 对该节点上所有索引执行只读设置,写入直接被拒绝:

{
  "error": {
    "type": "cluster_block_exception",
    "reason": "index [logs-2026.10.02] blocked by: [TOO_MANY_REQUESTS/12/disk usage exceeded flood-stage watermark, index has read-only-allow-delete block]"
  }
}

注意这个块是集群级下发的,不是索引自身的设置。恢复时必须显式解除。

2.5 阈值调整

阈值可以按集群动态调整:

PUT /_cluster/settings
{
  "persistent": {
    "cluster.routing.allocation.disk.watermark.low": "85%",
    "cluster.routing.allocation.disk.watermark.high": "90%",
    "cluster.routing.allocation.disk.watermark.flood_stage": "95%",
    "cluster.routing.allocation.disk.watermark.flood_stage.max_headroom": "20gb"
  }
}

也支持绝对值形式(如 50gb)。对大磁盘集群,绝对值的表达力更好:watermark.low: 200gb 表示剩余不足 200GB 就不再分配分片,比百分比更贴近真实需求。max_headroom 参数则给大磁盘兜底,避免 95% 在超大容量盘上留出过多无用空间。

3. 只读索引块与恢复

一句话总结: flood 触发的只读块必须手工解除,且清块前必须先腾出磁盘空间,否则会立刻再次触发。

3.1 只读块的类型

index.blocks.read_only 与 index.blocks.read_only_allow_delete 是两个不同的设置。flood 水位使用的是后者:索引不可写,但仍允许删除文档,这是为了让用户能通过删除数据自救。

3.2 解除只读

清空磁盘空间后,逐个索引或全集群解除:

PUT /_all/_settings
{
  "index.blocks.read_only_allow_delete": null
}

null 表示移除该设置。注意必须确认磁盘确实降下来了,否则下一次水位评估会立刻重新加上块。

3.3 恢复顺序

正确的恢复顺序是:

  1. 定位写满的节点,确认是哪个数据路径。
  2. 删除或迁走数据——优先删旧索引、清临时文件、删过期快照。
  3. 等磁盘使用率降到 high 以下。
  4. 解除只读块。
  5. 观察水位评估是否再次触发。

跳过第 3 步直接解块,会在几十秒后再次只读,形成反复。

3.4 预防性只读

除了 flood,也可以主动给历史索引加只读块,防止误写入:

PUT /logs-2026.01/_settings
{
  "index.blocks.write": true
}

这与 ILM 的 cold/frozen 阶段做的事一致,属于主动治理而非被动保护。

4. 分片大小与数量规划

一句话总结: 单个分片控制在 10GB 到 50GB,分片总数与节点数保持合理比例,是避免水位频繁触发的前提。

4.1 分片大小的经验值

官方给出的推荐区间是单分片 10GB 到 50GB。小于 10GB 的分片数量过多,每个分片都有固定开销(段文件、集群状态条目、堆内存),管理成本上升;大于 50GB 的分片在恢复、迁移时耗时长,merge 压力大,且单个分片故障影响面大。

搜索密集型场景偏向小区间(10 到 30GB),日志与写入密集型偏向大区间(30 到 50GB)。

4.2 分片数量的规划

分片数量的经验公式是「每 GB 堆内存对应 20 个分片以内」。一个 30GB 堆的节点,分片数控制在 600 以内比较稳妥。分片过多会显著增加主节点的集群状态管理开销——每次集群状态变更都要广播给所有节点,分片元数据越大,恢复越慢。

总分片数 ≈ 数据总量 / 单分片目标大小
单节点分片数 ≤ 堆内存GB × 20

4.3 滚动索引控制分片数

对时序数据,用 ILM 按时间滚动产生新索引,每个索引的分片数固定,从而让分片总数随时间线性增长。此时的关键参数是滚动周期与分片数:

PUT /_ilm/policy/logs-policy
{
  "policy": {
    "phases": {
      "hot": {
        "actions": {
          "rollover": { "max_primary_shard_size": "30gb", "max_age": "1d" }
        }
      }
    }
  }
}

max_primary_shard_size 让滚动由「主分片大小」触发,比按文档数或天数更贴近磁盘实际占用。

4.4 避免过小分片

日索引如果每天只有几百 MB,却配了 5 个分片,一年下来就是上千个小分片。正确做法是降低分片数(甚至单分片),或者改用更大粒度的索引(周索引、月索引)。

5. 容量估算方法

一句话总结: 容量估算要覆盖原始数据、索引膨胀、副本、段合并余量与安全余量五个部分,最终得出所需磁盘总量。

5.1 五部分构成

组成典型倍数说明
原始数据1.0业务写入的文档体积
索引膨胀1.1 到 2.0倒排索引、doc values、存储字段
副本1 + 副本数每份副本占等量空间
merge 余量1.5段合并期间的临时双份占用
安全余量1.15留给水位与运维操作

举例:原始数据 1TB,膨胀系数取 1.3,1 个副本,merge 余量 1.5,安全余量 1.15,则所需磁盘为 1 × 1.3 × 2 × 1.5 × 1.15 ≈ 4.5TB。

5.2 膨胀系数的影响因素

  • 字段类型:text 建立倒排索引,膨胀明显;keyword 与数值字段的 doc values 相对紧凑。
  • 是否开启 _source:关闭 _source 能省空间,但会失去 reindex 与更新能力,慎用。
  • index: false 的字段:仅存储不索引,能显著降低膨胀。
  • 分词粒度:细粒度分词产生更多词项,倒排更大。

5.3 增长趋势外推

容量规划不是算一次就完事。要按周或按月统计实际磁盘增长速率,做线性或带季节性的外推:

预计耗尽时间 = (可用空间 × 0.85) / 日均增长量

以「距离 low 水位还有多少天」作为核心告警指标,而不是「当前用了百分之几」。剩余 30 天时开始规划扩容,剩余 14 天时必须执行。

5.4 快照仓库的空间

快照仓库通常与数据盘分开,但也要纳入规划。增量快照虽然只存变化部分,但首次全量快照的体积接近数据总量,且长期保留策略会累积。仓库写满会导致快照失败,SLM 策略静默失效。

6. 扩容决策与实施

一句话总结: 扩容前先判断是「数据增长」还是「分片失衡」,前者加节点,后者先做分片重平衡。

6.1 先诊断再扩容

磁盘告警时先回答三个问题:

  • 是单节点异常还是全集群普遍偏高? 单节点高说明分片分配不均,应调 rebalance 或手动迁移。
  • 是主分片增长还是副本堆积? 副本过多可以降副本数,这是最快的止血手段。
  • 增长是趋势性的还是突发? 突发可能来自某次批量导入或日志暴涨,加节点是过度反应。

6.2 分片重平衡

如果只是分配不均,用分配过滤把分片从高水位节点迁走:

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

迁移完成后清空该设置。注意迁移本身会消耗网络与磁盘 IO,且目标节点必须有空间。

6.3 垂直与水平扩容

  • 垂直扩容:给节点加盘或换大盘。操作简单但受单机上限约束,且重启节点会触发分片重分配。
  • 水平扩容:加新节点,让分片自动均衡。更符合 Elasticsearch 的设计,但要注意新节点加入后的大量分片迁移会占用带宽。

水平扩容的节点配置应与现有节点一致,否则新节点会成为瓶颈。

6.4 扩容后的验证

加节点后要确认三件事:新节点是否被正确加入集群、分片是否开始迁移、迁移完成后各节点使用率是否均衡。分片迁移是 IO 密集操作,建议在低峰期执行,并临时降低 cluster.routing.allocation.node_concurrent_recoveries 避免打满带宽。

6.5 降副本作为应急手段

磁盘告急时,最快的腾挪方式是临时把副本数从 1 降到 0:

PUT /logs-*/_settings
{
  "index.number_of_replicas": 0
}

这能立刻释放一半空间,但集群进入无冗余状态,任何一个节点故障都会丢数据。仅作为应急,扩容完成后必须恢复副本并等待分片重新分配。

7. 生产实践与常见坑

一句话总结: 磁盘治理的重点是「提前告警、分层存储、定期清理」,而不是等到只读后再救火。

7.1 分层与冷热

用 ILM 把数据从热节点滚动到温节点,再到冷节点,最后删除或转为可搜索快照。热节点用 SSD、容量小;冷节点用大容量 HDD。分层能让昂贵的存储只承载热数据,是控制成本与水位最有效的手段。

7.2 告警指标设计

  • 节点磁盘使用率超过 75% 预警,超过 82% 严重告警。
  • 「距 low 水位剩余天数」低于 30 天告警。
  • 集群出现 unassigned 分片且原因是 disk 时立即告警。
  • 监控 cluster.routing.allocation.disk.threshold_enabled 是否被误关。

7.3 常见坑清单

  • 多数据路径误判:只看整机磁盘,忽略了单个 path.data 已超限。
  • 副本数过多:为了「高可用」把副本设成 2 或 3,磁盘成倍消耗。
  • merge 期间误判:大 merge 会临时占用双倍空间,触发水位后 merge 被阻塞,形成死锁。
  • 快照仓库与数据盘同盘:快照写入把数据盘写满,直接触发 flood。
  • _all/_settings 解块忘记确认空间:反复只读。
  • 磁盘满时删除文档:read_only_allow_delete 允许删除,但删除产生新段,短期内磁盘占用可能不降反升。

7.4 定期巡检

每月做一次容量巡检:核对增长趋势与外推结果、检查是否有超大分片或过小分片、确认 ILM 策略按预期执行、验证快照是否成功。把巡检结果记录下来,容量规划就从「拍脑袋」变成了「看数据」。

8. 总结

环节要点
水位机制low 85% 禁迁入、high 90% 迁出、flood 95% 只读
判定粒度按每个数据路径独立计算,非整机磁盘
恢复流程先腾空间再解块,顺序错误会反复只读
分片大小单分片 10GB 到 50GB,避免过小分片
分片数量每 GB 堆不超过 20 个分片
容量估算原始数据乘膨胀、副本、merge 与安全系数
扩容决策先诊断失衡与增长,再决定垂直或水平扩容
长期治理ILM 分层加定期巡检,把水位挡在触发之前

磁盘水位是一条不能靠运气跨越的红线:它平时不发声,一旦触发就是写入中断。把容量规划做成有数据支撑的常规流程,比任何应急手册都可靠。存储分层是控制水位的长期手段,而把冷数据搬到对象存储、仍保留查询能力,则是可搜索快照要解决的问题。

延伸阅读

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「elasticsearch」更多文章

  1. 可搜索快照与冻结层:把冷数据放进对象存储还能查
  2. 分页与深度分页:from/size、search_after、PIT 与 scroll
  3. 嵌套与父子关联查询:nested、join 字段与性能取舍