正常将数据写入到Elasticsearch时,发现写入失败,出现如下报错
cannot run anywhere due to node and executor blacklist.
Most recent failure:
Lost task 0.1 in stage 0.0 (TID 1, slave0001.test.com, executor 2): org.elasticsearch.hadoop.EsHadoopException: Could not write all entries for bulk operation [604/604]. Error sample (first [5] error messages):
org.elasticsearch.hadoop.rest.EsHadoopRemoteException: cluster_block_exception: blocked by: [FORBIDDEN/12/index read-only / allow delete (api)];
{"index":{"_id":null}}
{此处为json数据}
检查Elasticsearch集群的active master节点的日志,并没有发现error,但有WARN告警,显示与 flood stage disk watermark [90%] 有关。
2023-06-13T15:34:51,372 WARN [elasticsearch[node-1][management][T#2]] org.elasticsearch.cluster.routing.allocation.DiskThresholdMonitor:warnAboutDiskIfNeeded:84 - flood stage disk watermark [90%] exceeded on [TtNr4xotQZCd6dJjRI9G6g][olcmsprddb63][/data00/es-test/nodes/0] free: 49.1gb[9.9%], all indices on this node will be marked read-only
上下文有 low disk watermark [80%] 的INFO日志信息,再次证明与disk watermark 有关联。
2023-06-13T15:34:51,372 INFO [elasticsearch[node-1][management][T#2]] org.elasticsearch.cluster.routing.allocation.DiskThresholdMonitor:warnAboutDiskIfNeeded:90 - low disk watermark [80%] exceeded on [j_72JxYYT_yYB6BoxakcJQ][olcmsprddb52][/data00/es-test/nodes/0] free: 94.7gb[19.2%], replicas will not be assigned to this node
2023-06-13T15:34:51,372 WARN [elasticsearch[node-1][management][T#2]] org.elasticsearch.cluster.routing.allocation.DiskThresholdMonitor:warnAboutDiskIfNeeded:84 - flood stage disk watermark [90%] exceeded on [TtNr4xotQZCd6dJjRI9G6g][olcmsprddb63][/data00/es-test/nodes/0] free: 49.1gb[9.9%], all indices on this node will be marked read-only
2023-06-13T15:34:51,372 INFO [elasticsearch[node-1][management][T#2]] org.elasticsearch.cluster.routing.allocation.DiskThresholdMonitor:warnAboutDiskIfNeeded:90 - low disk watermark [80%] exceeded on [XvE1mMGeSqGJlAf5xVbSPQ][olcmsprddb73][/data00/es-test/nodes/0] free: 96gb[19.5%], replicas will not be assigned to this node
get /cluster/settings
随即检查了Elasticsearch集群settings设置,在这里可以看到disk.watermark.flood_stage和日志信息可以对上,设置的是90%的阀值,那就是它导致的。
{
"persistent": {
"cluster": {
"routing": {
"allocation": {
"cluster_concurrent_rebalance": "30",
"node_concurrent_recoveries": "20",
"disk": {
"watermark": {
"low": "80%",
"flood_stage": "90%",
"high": "90%"
}
},
"exclude": {
"_ip": ""
},
"node_initial_primaries_recoveries": "20"
}
},
"blocks": {
"read_only": "false"
}
},
"indices": {
"recovery": {
"max_bytes_per_sec": "80mb"
}
}
},
"transient": {}
}
为什么cluster.routing.allocation.disk.watermark.flood_stage会导致index read-only / allow delete呢?
以下是watermark相关的几个配置,我们来看看这几个配置的官网解释。详情可以参考官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/6.7/shards-allocation.html#_shard_allocation_settings
1、cluster.routing.allocation.disk.threshold_enabled
默认为true. 设置为false禁用磁盘分配决策器。
2、cluster.routing.allocation.disk.watermark.low
控制磁盘使用的低水位线。它默认为85%,这意味着 Elasticsearch 不会将分片分配给磁盘使用率超过 85% 的节点。它还可以设置为绝对字节值(如500mb),以防止 Elasticsearch 在可用空间少于指定的空间量时分配分片。此设置对新创建索引的主分片没有影响,或者特别是以前从未分配过的任何分片。
3、cluster.routing.allocation.disk.watermark.high
控制磁盘使用的高水位线。它默认为90%,这意味着 Elasticsearch 将尝试将分片从磁盘使用率超过 90% 的节点重新定位。它也可以设置为绝对字节值(类似于低水位线),以便在节点的可用空间小于指定数量时将分片重新定位。此设置会影响所有分片的分配,无论之前是否分配过。
4、cluster.routing.allocation.disk.watermark.flood_stage
控制磁盘洪水阶段水位线。index.blocks.read_only_allow_delete它默认为 95%,这意味着 Elasticsearch在每个索引上强制执行一个只读索引块 ( ),该索引在至少有一个磁盘超过泛滥阶段的节点上分配了一个或多个分片。这是防止节点耗尽磁盘空间的最后手段。一旦有足够的可用磁盘空间允许索引操作继续进行,就必须手动释放索引块。
重点看disk.watermark.flood_stage参数就能发现问题,我这个集群阀值从默认的95%被修改为90%了。所以当磁盘使用率达到90%,就导致索引被强制置于只读模式,所以导致索引写入失败。
默认情况下,Elasticsearch 是基于可用磁盘空间的百分比设置的,因此在大磁盘上,即使您有数 GB 的可用空间,也会发生这种情况。
disk.watermark.flood_stage默认为 95%,因此在 1TB 驱动器上您至少需要 50GB 的可用空间,否则 Elasticsearch 会将其自身置于只读模式。
正确的解决方案取决于环境的实际情况,你可以根据自己的实际环境情况选择适合的方案,也可以选择多种方案组合使用。
删除一部分不需要的索引数据,或者删除path.data挂载盘下非es相关的数据(这种情况多出现数据盘混用的情况下),最低要释放超过 5% 的磁盘足空间。
DELETE 不需要的索引
或
#检查elasticsearch.yml配置文件中,找到path.data配置的挂载盘中无用的数据。(生产环境默认非es相关的目录都是无用数据。)
du -sh /data00/*
328M /data00/es-test
800M /data00/test
#例如test目录为无用数据,那就删掉它,用以释放磁盘空间。
cd /data00/ && rm -rf test
一旦有足够的可用磁盘,Elasticsearch 不会自动退出只读模式,您必须执行类似这样的操作来解锁索引:
PUT/_all/_settings -d '{"index.blocks.read_only_allow_delete": null}'
由上图可依法向我的 cluster.routing.allocation.disk.watermark.flood_stage 配置的是90%,如果需要释放5%的磁盘空间,那我可以调整到95%。不过这个值既可以设置为较低的百分比,也可以设置为磁盘的剩余空间大小。以下是更改设置的命令:
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%"
}
}
或
PUT _cluster/settings
{
"transient": {
"cluster.routing.allocation.disk.watermark.low": "100gb",
"cluster.routing.allocation.disk.watermark.high": "50gb",
"cluster.routing.allocation.disk.watermark.flood_stage": "10gb",
"cluster.info.update.interval": "1m"
}
}
检查迁移进度,当集群没有RELOCATING状态的分片时,就意味着迁移完成。
get /_cat/shards?v&pretty&s=state:desc
同样,执行此操作后,您必须使用命令解锁索引,之后它们不应再次进入只读模式。
PUT/_all/_settings -d '{"index.blocks.read_only_allow_delete": null}'
当长期解决方案到位时,重置或重新配置disk.watermarks。这里介绍的是恢复默认值。
PUT _cluster/settings
{
"persistent": {
"cluster.routing.allocation.disk.watermark.low": null,
"cluster.routing.allocation.disk.watermark.high": null,
"cluster.routing.allocation.disk.watermark.flood_stage": null
}
}
按照Elasticsearch扩容方法完成扩容,扩容后的集群容量应该满足如下要求:集群磁盘总容量*80% > 实际数据所需容量。
同样,执行扩容操作后,您必须使用命令解锁索引,之后它们不应再次进入只读模式。
PUT/_all/_settings -d '{"index.blocks.read_only_allow_delete": null}'
物理机的CUP和内存资源一般都比较重组,如果想在物理机扩容增加新磁盘,操作方法有很多。我这里介绍一种单个节点启动两个Elasticsearch实例的扩容方法。
su - es
cd /home/es/software/elasticsearch
#现在增加了一个/data01数据盘,copy一份 elasticsearch 的 config 配置文件,命名为 config2
cp -r config config2
#1、修改config2目录下elasticsearch.yml文件中path.data的数据盘从/data00修改为/data01
#2、修改config2目录下elasticsearch.yml文件中node.name的node-1为node-10。(和集群不重复的值)
#3、修改config2目录下elasticsearch.yml文件中path.logs的logs为logs2
#4、#http.port: 9200 修改为 http.port: 9201
#5、#transport.tcp.port: 9300 修改为 transport.tcp.port: 9301
#启动第二实例
cd /home/es/software/elasticsearch/bin
./elasticsearch -d -p /home/es/software/config2/config2.pid
同样,执行扩容操作后,您必须使用命令解锁索引,之后它们不应再次进入只读模式。
PUT/_all/_settings -d '{"index.blocks.read_only_allow_delete": null}'
虚拟机一般CUP和内存资源都比较紧张,所以不方便启动双实例,所以只能在中增加一个磁盘。但是需要重启es生效。
su - es
cd /home/es/software/elasticsearch/config
#在elasticsearch.yml文件path.data中增加一个磁盘,使用逗号分隔。
path.data: /data00/es-test 修改为 path.data: /data00/es-test,/data01/es-test
最后重启Elasticsearch进程服务,使/data01相关的配置生效。
同样,执行扩容操作后,您必须使用命令解锁索引,之后它们不应再次进入只读模式。
PUT/_all/_settings -d '{"index.blocks.read_only_allow_delete": null}'
这种方法有一个弊端,就是es在节点内部没有办法自动均衡。可以使用迁移的方法,将node-1节点数据先迁移走,再迁移回来。手动实现节点内部磁盘均衡。
#1、开始迁移数据
PUT /_cluster/settings
{
"persistent" :{
"cluster.routing.allocation.exclude._ip" : "192.168.168.1"
},
"transient" :{
"cluster.routing.allocation.exclude._ip" : "192.168.168.1"
}
}
#2、检查数据迁移进度,RELOCATING表示正在迁移中。
get /_cat/shards?v&pretty&s=state:desc
index shard prirep state docs store ip node
testIndex 3 p RELOCATING 214311 107.9mb 192.168.168.1 node-1 -> 192.168.168.3 XcE1mMGeSQGJlXf5xVbSPM node-3
#3、如果迁移速度比较慢,可以调整传输速度和线程数
#每秒传输速度,默认40Mb。如果节点内存16G-32G的选择125mb,大于32G的选择250mb
PUT /_cluster/settings
{
"persistent" :{
"indices.recovery.max_bytes_per_sec" : "125mb"
},
"transient" :{
"indices.recovery.max_bytes_per_sec" : "250mb"
}
}
#集群内同时启动的数据任务个数,默认是2个
PUT /_cluster/settings
{
"persistent": {
"cluster.routing.allocation.cluster_concurrent_rebalance": "10"
},
"transient": {
"cluster.routing.allocation.cluster_concurrent_rebalance": "10"
}
}
#添加或删除节点及负载均衡时并发恢复的线程个数,默认4个
PUT /_cluster/settings
{
"persistent": {
"cluster.routing.allocation.node_concurrent_recoveries": "5"
},
"transient": {
"cluster.routing.allocation.node_concurrent_recoveries": "5"
}
}
#初始化数据恢复时,并发恢复线程的个数,默认4个
PUT /_cluster/settings
{
"persistent": {
"cluster.routing.allocation.node_initial_primaries_recoveries": "5"
},
"transient": {
"cluster.routing.allocation.node_initial_primaries_recoveries": "5"
}
}
#4、恢复设置,数据会自动迁移回来。
PUT /_cluster/settings
{
"persistent" :{
"cluster.routing.allocation.exclude._ip" : ""
},
"transient" :{
"cluster.routing.allocation.exclude._ip" : ""
}
}
如果你的disk.watermark相关的配置用的是默认值,而且短时间内因为数据倾斜导致的集群性能要求不高,而且新增数据增长不快,那也可以不用做任何操作。
当单个磁盘水位达到90%之后,数据也会自动触发迁移至其他节点。但是如果达到95%,会有再次触发索引写入失败[FORBIDDEN/12/index read-only / allow delete (api)]的风险。
磁盘空间不足,我们也可以从500G扩容到1T。这种方法一般只适合虚拟机,不适合物理机。扩容前建议将扩容节点数据先迁移走,这样防止数据丢失。
#1、开始迁移数据
PUT /_cluster/settings
{
"persistent" :{
"cluster.routing.allocation.exclude._ip" : "192.168.168.1"
},
"transient" :{
"cluster.routing.allocation.exclude._ip" : "192.168.168.1"
}
}
#2、检查数据迁移进度,RELOCATING表示正在迁移中。
get /_cat/shards?v&pretty&s=state:desc
index shard prirep state docs store ip node
testIndex 3 p RELOCATING 214311 107.9mb 192.168.168.1 node-1 -> 192.168.168.3 XcE1mMGeSQGJlXf5xVbSPM node-3
#3、数据排空后,重启Elasticsearch进程
#4、恢复设置,数据会自动迁移回来。
PUT /_cluster/settings
{
"persistent" :{
"cluster.routing.allocation.exclude._ip" : ""
},
"transient" :{
"cluster.routing.allocation.exclude._ip" : ""
}
}
这个方案并不好,因为当我们出现告警的时候,就已经出现空间不足的告警了。一般这种方法只能配合删索引或有临时中转空间时使用。