前言
在运维 Elasticsearch (ES) 集群时,你是否遇到过这样的场景:业务数据突然无法写入,日志报错 cluster_block_exception: index read-only?这通常不是 Bug,而是 ES 在拼命拉住你,防止磁盘写满导致节点崩溃。
本文将带你深入了解 ES 的磁盘水位线机制,并手把手教你如何正确、安全地解除"只读模式"。
一、现象:集群为何突然"罢工"?
当你的 ES 集群磁盘使用率过高时,你会看到如下报错:
{
"error": {
"type": "cluster_block_exception",
"reason": "blocked by: [FORBIDDEN/12/index read-only / allow delete (api)];"
}
}
此时,Kibana 只能查询历史数据,无法写入新日志,索引健康状态可能变为 Yellow 或 Red。
二、核心机制:ES 的三道防线
ES 通过三个水位线阈值来保护集群,防止磁盘被写满:
| 水位线 | 默认阈值 | 触发行为 |
|---|---|---|
| Low (低水位) | 85% | 停止向该节点分配新的分片。 |
| High (高水位) | 90% | 尝试将该节点上的分片迁移到其他节点。 |
| Flood Stage (洪水期) | 95% | 强制将所有索引设为只读 ( read_only_allow_delete),禁止写入。 |
注意: 我们遇到的"无法写入"问题,正是因为磁盘使用率超过了 95% 的洪水期水位线。
三、诊断:确认是否触发水位线
-
检查磁盘使用率
使用以下命令查看各节点的磁盘使用情况:curl -X GET "http://127.0.0.1:9200/_cat/allocation?v"
-
关注
disk.percent列,如果任何节点超过 95%,说明已触发洪水期保护。 -
检查索引是否被设为只读
确认索引的read_only_allow_delete属性:curl -X GET "http://127.0.0.1:9200/_all/_settings?pretty" | grep "read_only_allow_delete"
-
如果返回结果中包含
"read_only_allow_delete" : "true",则说明索引已被锁定。
四、解决:四步安全解锁法
切记:不要一看到报错就急着解锁!不先清理空间直接解锁,无异于饮鸩止渴。
-
第一步:立刻清理磁盘空间
这是解决问题的根本。删除过期或不需要的索引。警告:此操作不可逆,请谨慎执行
curl -X DELETE "http://127.0.0.1:9200/old-logs-2024-*"
-
在执行删除前,可以先用
curl -X GET "http://127.0.0.1:9200/_cat/indices?v&s=store.size:desc"查看占用空间最大的索引。 -
第二步:确认磁盘使用率下降
再次执行curl -X GET "http://127.0.0.1:9200/_cat/allocation?v",确保磁盘使用率已降至 95% 以下(建议低于 90%)。 -
第三步:安全解除只读限制
在确保磁盘空间已释放后,手动移除索引的只读属性。curl -X PUT "http://127.0.0.1:9200/_all/_settings" -H 'Content-Type: application/json' -d'
{
"index.blocks.read_only_allow_delete": null
}' -
成功执行后,你会看到返回
{"acknowledged": true}。 -
第四步:验证解锁结果
再次检查索引设置,确认read_only_allow_delete标志已消失:curl -X GET "http://127.0.0.1:9200/_all/_settings?pretty" | grep "read_only_allow_delete"
-
如果没有任何输出,说明解锁成功,集群已恢复正常。
五、进阶:动态调整水位线
如果你的业务需要,可以动态调整水位线阈值,无需重启集群。
示例:将水位线调整为更宽松的阈值
curl -X PUT "http://127.0.0.1:9200/_cluster/settings" -H 'Content-Type: application/json' -d'
{
"persistent": {
"cluster.routing.allocation.disk.watermark.low": "90%",
"cluster.routing.allocation.disk.watermark.high": "95%",
"cluster.routing.allocation.disk.watermark.flood_stage": "97%"
}
}'
警告: 将水位线设置得过高(如 99%)是极高风险的操作,可能导致磁盘写满,节点崩溃。
六、预防:建立长期防护机制
-
启用索引生命周期管理 (ILM)
配置 ILM 策略,让 ES 自动滚动创建新索引并删除过期旧索引,从根源上管理磁盘空间。 -
配置监控告警
使用 Prometheus + Grafana 等工具监控磁盘使用率,设置告警规则(如磁盘使用率 > 80% 时报警),以便提前干预。 -
限制 Docker 日志大小
如果是 Docker 部署,务必配置日志轮转,防止 Docker 自身日志占满磁盘。修改宿主机的/etc/docker/daemon.json文件:{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
总结
ES 的磁盘水位线机制是保护集群的"安全气囊"。遇到问题时,正确的处理流程是:先清理空间,再解除限制,最后建立长效预防机制。切勿本末倒置,否则只会让问题雪上加霜。