大家好,我是Coder哥, 最近线上客户反应,有部分数据没发生,作为一个打工人那我有必要是快速呼应排查了一下,后来定位到是ES磁盘达到阈值,索引变为read only形式了,便是只能读不能写了,我说等我几分钟,我把ES磁盘整理一下(不扩容的原因是,历史数据没啥用,主要是节约本钱),然后就快速的制定如下计划:

  1. 找到只读索引。
  2. 铲除索引半年之前的数据。
  3. 告诉用户。
  4. 完美。

如上,第一次跟领导有相同的想法,君子所见略同啊。

【生产环境】老板让我清理ES数据,我竟然把它清理爆了,大坑啊

经过上面剖析后我就开工了,最终阅历了各种坑,总结如下问题:

  1. ES索引为啥忽然变成了read only状况了?
  2. 整理数据整理到一半的时分磁盘爆了ES又变成只读了?
  3. 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值。

最终

假如公司有条件,建议先扩容再铲除,否则投入的时刻本钱也是挺高的,其实正常的铲除进程是:

  1. 先扩容。
  2. 找到只读索引。
  3. 铲除索引的数据。
  4. 告诉用户。
  5. 完美。