大家好,我是Coder哥, 最近线上客户反应,有部分数据没发生,作为一个打工人那我有必要是快速呼应排查了一下,后来定位到是ES磁盘达到阈值,索引变为read only形式了,便是只能读不能写了,我说等我几分钟,我把ES磁盘整理一下(不扩容的原因是,历史数据没啥用,主要是节约本钱),然后就快速的制定如下计划:
- 找到只读索引。
- 铲除索引半年之前的数据。
- 告诉用户。
- 完美。
如上,第一次跟领导有相同的想法,君子所见略同啊。
经过上面剖析后我就开工了,最终阅历了各种坑,总结如下问题:
- ES索引为啥忽然变成了read only状况了?
- 整理数据整理到一半的时分磁盘爆了ES又变成只读了?
- ES集群磁盘散布不均是为什么?
ES索引为啥忽然变成了read only状况了?
ES正在运用,忽然单个索引变为只读了,刺进时分报错如下:
报错:Elasticsearch exception [type=cluster_block_exception, reason=blocked by: [FORBIDDEN/12/index read-only / allow delete (api)];]
这个是由于ES的默许磁盘运用机制
原由于:es 的默许三个阈值是 85% 和 90 %,85%
当为85%时:Elasticsearch不会将碎片分配给磁盘运用率超越85%的节点( cluster.routing.allocation.disk.watermark.low: “85%”)
当为90%时:Elasticsearch测验从头分配给磁盘低于运用率90%的节点(cluster.routing.allocation.disk.watermark.high: “90%”)
当为85%时:Elasticsearch履行只读模块(cluster.routing.allocation.disk.watermark.flood_stage: “85%”)
基于以上机制,来看一下咱们线上的数据:
todocoer:~# curl -X GET -u todocoder:todocoder http://127.0.0.1:9200/_cat/allocation?v
shards disk.indices disk.used disk.avail disk.total disk.percent host ip node
73 757gb 811.8gb 172.2gb 984.1gb 82 xxx1 xxx1 node1
73 748.6gb 803.4gb 180.7gb 984.1gb 81 xxx2 xxx2 node2
6 879.9gb 932.3gb 51.7gb 984.1gb 94 xxx3 xxx3 node3
参数 | 解释 |
---|---|
shards | 分片个数 |
disk.used | 已用磁盘巨细 |
disk.indices | 索引所占磁盘巨细 |
disk.avail | 能够运用磁盘巨细 |
disk.total | 磁盘总容量 |
disk.percent | 磁盘运用百分比 |
node | 节点名称 |
从磁盘状况能够看出节点node3
运用率现已达到94%了,也便是说现已超越85%了,所以这个上面的索引应该都会变成只读的。
咱们看一下都哪个索引分配到这个节点上了
todocoer:~# curl -X GET -u todocoder:todocoder http://127.0.0.1:9200/_cat/shards?v | grep "node3"
index shard prirep state docs store ip node
style 1 p STARTED 113431552 219.2gb 10.0.0.3 node3
style 2 r STARTED 112811799 219.3gb 10.0.0.3 node3
style 3 r STARTED 112789097 219.1gb 10.0.0.3 node3
style 4 p STARTED 113420875 219.2gb 10.0.0.3 node3
能够看到索引style
现已占了94%了,所以ES把这个索引置为 read_only_allow_delete: true
如下:
todocoer:~# curl -X GET -u todocoder:todocoder http://127.0.0.1:9200/style/_settings?pretty
{
"style" : {
"settings" : {
"index" : {
"search" : {
...
},
"refresh_interval" : "5s",
"indexing" : {
...
},
"number_of_shards" : "5",
"blocks" : {
"read_only_allow_delete" : "true"
},
...
"number_of_replicas" : "1",
}
}
}
}
至此咱们知道了索引不能写入了的原因了,那么接下来咱们怎样处理呢?由于领导不让扩容,所以只能在当时容量下铲除部分数据,那么履行删去操作之前先把 read_only_allow_delete置为false
todocoer:~# curl -X PUT -u todocoder:todocoder http://127.0.0.1:9200/style/_settings -H "Content-Type:application/json" -d '{"index.blocks.read_only_allow_delete":false}'
然后再履行删去操作,删去字段 insert_time <= 2022-06-10 23:59:59
的数据,如下:
todocoer:~# curl -X POST -u todocoder:todocoder http://127.0.0.1:9200/style/_delete_by_query -H "accept:application/json" -H "Content-Type:application/json" -d '{"query":{"bool":{"must":[{"range":{"insert_time":{"lte":"2022-06-10 23:59:59"}}}]}}}'
...
// 过了5分钟左右忽然又出现下面的错误了
报错:Elasticsearch exception [type=cluster_block_exception, reason=blocked by: [FORBIDDEN/12/index read-only / allow delete (api)];]
删去了5分钟,又只读了???那么就引出了上面的问题2: 整理数据整理到一半的时分ES又变成只读了
整理数据整理到一半的时分ES又变成只读了
这个时分看了一下索引,占用的磁盘变大了,所以网上恶补了一下ES删去逻辑:
ES删去操作是软删去,原理如下:
ES每个segment中保护了一个.del文件。ES删去文档的时分,仅在.del文件中将文档标记为已删去,并未将磁盘上的数据进行整理。ES履行segment merge 时,挑选segment进行兼并生成新的segment,此刻标记为删去的文档并不进行处理,因此磁盘空间进行了释放。默许的状况下ES选择部分segment进行兼并,因此只要一切的segment都进行了处理之后磁盘空间彻底释放,中心会有冗余数据的存在,以确保正常切换。
shard 和 segment的差异
Shard 是数据分片,比如一个索引有10G的内容,分红5shard, 放在不同的节点,这个数量是number_of_shards 在创立索引的时分指定的,后边无法更改。
Segment : 每个shard包括多个segment, 每个segment都是一个倒排索引,查询时会汇总一切segment的数据返回。
那这样不行啊,得想个办法处理一下这个问题,已然他会主动的变为只读,那我把阈值调高点是不是就不会主动触发了,介于当时用了94%了,那我把阈值调flood_stage
到97%,同时调了下indices.recovery.max_bytes_per_sec
这个参数(可是不要调太高,比较吃资源),增加兼并时分的吞吐量如下:
todocoer:~# curl -X PUT -u todocoder:todocoder http://127.0.0.1:9200/_cluster/settings -H "Content-Type:application/json" -d '{"transient":{"cluster.routing.allocation.disk.watermark.flood_stage":"97%","indices.recovery.max_bytes_per_sec":"100mb"}}'
履行完后,持续上面的步骤,修正read only, 铲除索引,最终手动触发兼并操作:
todocoer:~# curl -X POST -u todocoder:todocoder http://127.0.0.1:9200/style/_forcemerge?only_expunge_deletes=true&max_num_segments=1
only_expunge_deletes 该优化操作是否只清空打有删去标签的索引记载。在Lucence中,在履行删去操作时,不会直接删去segment中的记载,而是对该记载打上delete标签。当多个segment进行兼并操作时,就会生成一个新的segment,而该新的segment中不再包括删去的记载。这个参数允许只对哪些包括删去记载的segment进行优化操作。
max_num_segments
指定segment的数量
履行完上面步骤,就等待系统兼并完成。最终记得把flood_stage
复原。
履行完后,发现整个进程比较慢还可能会影响用户查询速度,由于咱们数据的特殊性,即便丢失也不太影响系统,所以我这边直接进行副本缩容:
todocoer:~# curl -X PUT -u todocoder:todocoder http://127.0.0.1:9200/style/_settings -H "Content-Type:application/json" -d '{"index":{"number_of_replicas":0}}'
number_of_replicas: 0, 意思就一份数据,不要副本。这个指令收效很快,几分钟就收效了,容量一下就多了1T。。
ES集群磁盘散布不均是为什么?
以上是ES的铲除进程,从这次铲除ES发现了一些问题,某些索引的shard假如比较小的话,会造成数据散布不均,比如咱们的索引 style
,一年 1T多点的数据,number_of_shards值是5, 加上副本的话一共是2T数据分了10份,一份219G,那么一个节点巨细为1000G的话,分4份就超越85%了,导致索引变成只读,可是这个时分其他的节点还有空间,造成了数据不均匀的状况,所以在创立索引的时分需要预估一下索引容量,分配合理的number_of_shards值。
最终
假如公司有条件,建议先扩容再铲除,否则投入的时刻本钱也是挺高的,其实正常的铲除进程是:
- 先扩容。
- 找到只读索引。
- 铲除索引的数据。
- 告诉用户。
- 完美。