在生产环境下,无论使用Elasticsearch做检索还是ELK分析的,如果文档数量非常庞大,动辄就是按T计算。Elasticsearch也提供了文档的批处理机制,允许一次性检索多个文档。为了保证集群处在一个最佳负载状态,我们会通过Delete By Query的方式去定期删除索引中的数据。
Delete By Query API 介绍
根据特定的查询条件对ES相关索引中某些特定的文档进行批量删除。
POST index_name/_delete_by_query
{
"query": { //这些是自定义查询条件,根据查询条件去批量删除
"match": {//请求体跟Search API是一样的
"message": "some message"
}
}
}
Delete By Query 删除原理
在Elasticsearch中删除和更新都是写操作,但Elasticsearch中的文档是不可变的,因此不能通过更新或者删除以展示其变化。
Delete_by_query并不是真正意义上物理文档删除,而是只是版本变化并且对文档增加了删除标记。当我们再次搜索的时候,会搜索全部然后过滤掉有删除标记的文档。因此,该索引所占的空间并不会随着该API的操作磁盘空间会马上释放掉,只有等到下一次段合并的时候才真正被物理删除,这个时候磁盘空间才会释放。相反,在被查询到的文档标记删除过程同样需要占用磁盘空间,这个时候,你会发现触发该API操作的时候磁盘不但没有被释放,反而磁盘使用率上升了。
使用Delete By Query 删除API注意事项
1.一般生产环境中,使用该API操作的索引都很大,文档都是千万甚至数亿级别。索引大小在几百G甚至几个T,因此,这个操作建议在业务低峰期或者晚上进行操作,因为大数据量情况下删除的需要消耗较多的i/o CPU 资源,容易对生产集群造成影响。
2.在删除过程中要确定集群磁盘有一定的余量,因为标记删除需要占用磁盘空间。如果磁盘空间不够,这个操作的失败率还是很大的。
段合并 --> 强制合并
由于自动刷新流程每秒会创建一个新的段,这样会导致段时间内的段数量暴增。而段数目太多会带来较大的麻烦。每个段都会消耗文件句柄、内存和CPU运行周期。更重要的是,每个请求都必须轮流检查每个段;所以段越多,搜索也就越慢。Elasticsearch通过在后台进行段合并来解决这个问题。小的段被合并到大的段,然后这些大的段再被合并到更大的段。段合并的时候会讲那些旧的一删除的文档从文件系统中清除。被删除的文档(或被更新文档的旧版本)不会被拷贝到新的大段中。启动段合并并不需要你做任何事。进行索引和搜索时会自动进行。
Elasticsearch会有后台线程根据lucene的合并规则定期进行段合并操作,一般不需要用户担心或者采取任何行动。被删除的文档在合并时,才会被真正删除掉。再次之前,它仍然会占用着JVM heap和操作系统的文件cache、磁盘等资源。在某些特定情况下,我们需要ES强制进行段合并,以释放其占用的大量系统、磁盘等资源。POST /index_name/_forcemerge
。
_forcemerge 命令可强制进行segment合并,并删除所有标记为删除的文档。Segment merging要消耗CPU,以及大量的I/O资源,所以一定要在你的ElasticSearch集群处于维护窗口期间,并且有足够的I/O空间的(如:SSD)的条件下进行;否则很可能造成集群崩溃和数据丢失。
_forcemergeAPI 有几个常用的参数:
- max_num_segments: 是表示将某个索引的每个分片强制合并为几个段的意思。
- only_expunge_deletes: 是表示仅将标记删除为文档的进行强制合并物理删除,不进行其它合并操作。
参考
https://www.elastic.co/guide/en/elasticsearch/reference/7.2/docs-delete-by-query.html
https://www.elastic.co/guide/en/elasticsearch/reference/7.2/indices-forcemerge.html#indices-forcemerge
https://www.jianshu.com/p/60a6ad164035