大家好,我是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值。
最后
如果公司有条件,建议先扩容再清除,不然投入的时间成本也是挺高的,其实正常的清除过程是:
-
先扩容。 -
找到只读索引。 -
清除索引的数据。 -
通知用户。 -
完美。
原文始发于微信公众号(TodoCoder):线上清除ES数据竟然会把磁盘撑爆,长个教训吧
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/169035.html