问题描述
记录一次在单位里做的删除优化,使用delete_by_query的时候发现了一个问题,就是删除效率太低。当打流日志并发变高的时候,删除往往跟不上ES数据增加的速度,导致磁盘占用率持续彪高,直到将所有的内存空间占满.
第一次优化
第一次优化尝试调整过相关代码的删除阈值,发现ES会在查询到大数据量的情况下删除失败,后面经过定位发现是并发写入和删除产生的版本冲突问题。
官方文档中有如下解释
简单翻译一下,意思就是说默认如果出现版本冲突那么会中止后续的删除操作,并且其实当我们ES在并发读写的时候,是很有可能会出现版本冲突的,在删除的时候我们并不需要考虑这一点,所以可以添加参数,如下图所示
//新增conflicts=proceedPOSTtwitter/_doc/_delete_by_query?conflicts=proceed{ "query": { "match_all": {} } }
经过修改后,发现虽然解决了版本冲突导致的删除中断问题,但是在某些极端情况下还是会删除超时。
第二次优化
第二次优化尝试将for循环遍历然后删除索引部分数据的相关代码改造成多线程的解决方案,来保证每次进行一个并发的删除,不需要做一个时间顺序的等待,此时对当下的ES入数并发支持到达了每秒3000.
第三次优化
基于业务的需要,以及另外一个索引我们需要支持每秒15000的数据入数,此时就需要再次优化我们ES的删除效率,其实当时也考虑过是否需要升级ES版本至8.x来兼容我们的DataStream工作流,然后使用ES自带的文档或者时间阈值删除在其基础上再做优化方便扩展,但是后来做方案选型的时候,发现我们的框架版本目前支持到ES6.x版本,如果还需要往上做兼容的话会影响很多现有的功能,基于当时的场景我查询了一下官方文档,发现了2种解决方案:
第一种是ES的异步删除,返回一个taskId。
第二种是使用ES内置的多线程删除。
分析之后,第三次优化决定使用第二种方式来应对当下的业务场景。
下图为具体新增的代码以及相关参数:
使用了这一套方案之后,每秒的删除效率提升到了40000,性能优化了接近10多倍.
//在代码中新增如下参数delete_by_query?conflicts=proceed&scroll_size=5000&slices=10//在这里要注意 slices如果并发设置过大可能会导致协议句柄的增加 比如说scroll数量的增加scroll_size//这个参数是执行删除的时候,每次每个线程会查询的数据量,然后进行删除。//默认是100,就是说每个线程每次都会查询出100条数据然后再删除。slices//这个就相当于开启的线程数,同时会有多少个线程执行查询然后删除程序。//默认是1,就是同时只会有一个线程进行查询删除操作。
但是请注意的是,在这里还有一个坑,就是说在实际运行的时候,你会发现刚开始删除是好好的,但是删除一段时间之后它会报错一个问题,
Tryingtocreatetoomanyscrollcontexts. Mustbelessthanorequalto: [500]
Scroll
那么问题来了,什么是Scroll,为什么他会说小于500呢,下面取自ElasticSearch官方的一张介绍图片
简单翻译一下上述的文字,我们可以了解到其实Scroll的应用场景是在做大数据量查询的时候会被大幅度应用到,它充到了关联上下文的作用,如果有做过大数据量体系下查询的小伙伴应该知道,ES默认最多只能查询10000条数据,这里涉及到一个深度分页的问题,我们暂时不做概述,具体的可以查询笔者之前写的文章,在我们的ES当中,默认的Scroll协议句柄数量配置是500个,当有大量线程请求进来的时候,我们的Scroll很有可能就会不够用,就会导致我们的删除线程出现大批量超时的情况,我们此时可以通过对ES集群进行配置来避免这种情况的发生.
我们也可以看一下下面红色线框住的部分,简单描述一下就是说我们可以通过 search.max_open_scroll_context 这个参数来控制我们Scroll协议句柄的数量,以下为修改具体的集群配置信息
PUT/_cluster/settings{ "persistent":{ "search.max_open_scroll_context":10240 }, "transient":{ "search.max_open_scroll_context":10240 } }
//摘自官方文章中的一段描述scroll_currentindicatesthenumberofscrollcontextscurrentlyopen .
注意:以上这2个优化的值对于不同性能的机器往往是不一样的,其中某段时间内查询的上下文越多,就越容易超过默认500的临界值,以上的只是作为参考依据,我们可以根据实际压测情况,比如删除多少数据,用多少线程,共计多少时间,来设置最符合我们当下业务的线程数量以及每个线程删除的具体数量。