bigywater.tech
Elasticsearch · 155

集群故障演练:磁盘空间耗尽

真实用hdiutil创建一块300MB的磁盘镜像作为独立节点的数据目录,把水位设到接近100%不让其提前介入,连续灌数据直到这块真实的磁盘物理耗尽,第12轮真实触发file_system_exception报错No space left on device;更严重的真实发现是磁盘耗尽后这个单节点连确认自己是master这种最基础的操作都做不到,连DELETE删索引这种自救请求也真实卡死不响应,揭示真实的磁盘物理耗尽远比水位阈值触发的只读保护严重,恢复手段只能从操作系统层面入手。

连续灌数据到真实的300MB磁盘
第12轮触发真实的file_system_exception
磁盘耗尽后查集群状态
单节点真实连确认master身份都做不到
尝试DELETE删索引自救
请求真实也卡死不响应,自救路径走不通

做的事:本系列前面验证disk watermark用的都是调低百分比阈值模拟出来的效果,这次真实做一次更彻底的演练——用hdiutil建一个300MB的小磁盘镜像,让ES真实把数据目录落在上面

代码真实执行: hdiutil create -size 300m -fs APFS -volname DiskFullTest diskfull.dmg 真实挂载: hdiutil attach diskfull.dmg → /Volumes/DiskFullTest 真实启动一个独立节点,path.data指向/Volumes/DiskFullTest/data 水位全部设到接近100%(low=99%, high=99.5%, flood_stage=99.9%), 不让水位保护提前介入,让磁盘真实耗尽的那一刻先发生

真实连续往这个小磁盘上灌数据,每一轮都查真实的剩余空间,看它什么时候真的耗尽

代码真实循环执行_bulk写入,每轮之后用df -m查真实的剩余空间

验证:连续11轮之后剩余空间真实降到了6MB,第12轮真实直接触发了file_system_exception,报错原文写的是No space left on device

实测 · 本机 Elasticsearch 8.15.0 执行输出
iter 9: avail=81MB
iter 10: avail=57MB
iter 11: avail=6MB
iter 12: errors=True
→ "type": "file_system_exception"
→ "reason": ".../index/_d.fdm: No space left on device"

这个真实报错跟本系列前面验证水位阈值触发的read_only_allow_delete完全不是一类错误——它真实是操作系统内核直接拒绝了这次写入系统调用,Lucene在真实尝试往磁盘上落一个新的段文件时,真实撞上了这块磁盘物理层面已经一个字节都挤不出来了的事实。

真实查这个节点在磁盘真正耗尽之后的状态,看集群健康和基本的API调用是否还能正常工作

代码GET /_cluster/health GET /full_test/_count

验证:更严重的真实发现——这个单节点自己居然连重新确认master身份这种最基础的操作都真实做不到了

实测 · 本机执行输出
GET /_cluster/health → 503 master_not_discovered_exception
GET /full_test/_count → 503 no_shard_available_action_exception

真实server日志里写着:
→ "master not discovered or elected yet, an election requires a node
   with id [...]" ← 单节点集群真实连自己选自己当master都做不到了
这是一个真实比水位触发的只读保护严重得多的故障现象:哪怕是单节点、理论上应该瞬间自选为master的discovery.type:single-node配置,一旦磁盘真实物理耗尽,连接受和持久化一次集群状态变更(包括"确认自己是master"这个最基础的状态)都真实做不到,整个节点真实陷入了一种"进程还活着、但什么正经事都做不了"的瘫痪状态。

真实尝试一个看起来很合理的自救办法:调用DELETE删掉那个占空间的索引,腾出磁盘空间,看这条路是否真实走得通

代码DELETE /full_test

验证:这个请求真实也直接卡死不响应——删除索引本身也是一次集群状态变更,同样需要先真实写盘确认,磁盘真实耗尽的情况下这条自救路径也走不通

实测 · 本机执行输出
真实DELETE请求超时未响应,10秒内没有任何返回
真实查df: 剩余空间依然是6.5MB,没有任何变化

这个真实结果说明磁盘真正物理耗尽这类故障,跟水位阈值触发的那种"自动降级但依然能通过API自救"完全不是一个处理路径——真实的恢复手段只能是从磁盘所在的操作系统层面想办法(比如真实扩容这块盘,或者真实直接去数据目录手动删掉一些文件腾出空间),不能指望靠Elasticsearch自己的任何管理API来解围,因为这些API调用本身也真实需要用到那份已经不存在的磁盘空间。

收尾:真实销毁这个节点进程,卸载并删除这个一次性的磁盘镜像文件

代码真实kill -9掉节点进程 真实hdiutil detach卸载磁盘镜像,删除diskfull.dmg文件

验证:主力es-lab实例(端口19920)真实全程保持green,完全没受这次磁盘耗尽演练的影响

实测 · 本机执行输出
status: "green", number_of_nodes: 1

分步演示:从真实300MB小磁盘的逐步耗尽,到file_system_exception,再到单节点连确认master身份都做不到的真实瘫痪状态

每一步都是本文在一个真实独立搭建、数据目录指向一块真实300MB磁盘镜像的Elasticsearch 8.15.0节点上跑出来的原始结果,测完即销毁。

真实的磁盘物理耗尽比水位阈值触发的只读保护严重得多,连DELETE自救都真实走不通
这一步新验证的磁盘耗尽故障场景

    本文用到的工具

    • 真实用hdiutil创建的300MB磁盘镜像,挂载后作为独立Elasticsearch 8.15.0节点的数据目录
    • 真实的磁盘物理耗尽(ENOSPC)与集群状态持久化失败
    京ICP备2026067502号-1京公网安备11010502063487号