es插⼊很慢_ElasticSearch插⼊性能优化
⼀、问题分析
最近公司的es插⼊/更新性能⼤幅度下降,单⽇数据(70w)刷⼊从原来10min+,变成了现在的解决3h。插⼊效率从1k-2k条/s,到现在100-200条/s。
总结了下问题的原因,有以下⼏点:
堆内存不⾜
segment数量过多导致内存吃紧
业务线程阻塞在BulkProcessor对象
⼆、问题优化⽅案
1、堆内存不⾜问题
如下图可看出,堆内存已经⾮常吃紧。Index Memory/segment这些都会吃掉我们⼤量内存。3g堆内存已经不能满⾜业务需求,只能充钱扩容了。
2、segment数量过多导致内存吃紧
更新数据导致索引变⼤
我们的业务是⼀个⽉⼀个索引,默认5个分⽚。每个⼀段时间会对⼏个⽉的数据进⾏重刷,重刷完后改动⼏率很低,基本只供查询。另外我对数据设置了唯⼀ID,没有⽤⾃动⽣成对ID。按道理,相同id对数据进⾏覆盖,重刷后索引⼤⼩不应该发⽣变化。但是每次重刷完后,索引⼤⼩都会变⼤⼏个G。这是什么原因导致对呢?
这⾥⽤mysql的索引和es的segment索引进⾏对⽐,mysql的索引在做了更新操作只会,会重构索引树。对于⼤量数据,这个操作是⾮常耗时的。我们看看es官⽅⽂档对于索引更新的介绍:
es对于更新和删除操作,不会重构原来的索引,这样会⾮常耗时,不够快。怎么最快?把原来的数据标记为删除,新建索引。
对于删除和更新:
段是不可改变的,所以既不能从把⽂档从旧的段中移除,也不能修改旧的段来进⾏反映⽂档的更新。 取⽽代之的是,每个提交点会包含⼀个 .del ⽂件,⽂件中会列出这些被删除⽂档的段信息。
当⼀个⽂档被 “删除” 时,它实际上只是在 .del ⽂件中被 标记 删除。⼀个被标记删除的⽂档仍然可以被查询匹配到, 但它会在最终结果被返回前从结果集中移除。
⽂档更新也是类似的操作⽅式:当⼀个⽂档被更新时,旧版本⽂档被标记删除,⽂档的新版本被索引到⼀个新的段中。 可能两个版本的⽂档都会被⼀个查询匹配到,但被删除的那个旧版本⽂档在结果集返回前就已经被移除。
在 “段合并” , 我们展⽰了⼀个被删除的⽂档是怎样被⽂件系统移除的。
总结:更新操作导致索引变⼤的原因是因为旧的数据实际上并没有被删除,要删除旧的doc,只能通过“段合并”的⽅式。
segment数⽬太多,需要合并
段数⽬太多会带来较⼤的⿇烦。 每⼀个段都会消耗⽂件句柄、内存和cpu运⾏周期。更重要的是,每个搜索请求都必须轮流检查每个段;所以段越多,搜索也就越慢。"段合并"操作应⽤于不常更新的索引。
对不常更新的索引进⾏"段合并",每个分区合并为⼀个段。合并的原理如图:
基于5.X版本的段合并:
(1)获取⽬前索引各个分⽚的段⼤⼩和内存占⽤情况
GET /_cat/segments/imy-index-202003?v&h=shard,segment,
(这是测试环境的情况,段数及其占⽤内存都⽐较⼩)
(2)进⾏段合并,每个分区合并为⼀个段
POST /my-index-202003/_forcemerge?max_num_segments=1
max_num_segments:各分区合并后的段数
(3)段合并后的情况
3、业务线程阻塞在BulkProcessor对象优化
业务场景:10个线程并发执⾏,共享9个type的BulkProcessor(每个type⼀个BulkProcessor对象);
⽤jconsole命令查看线程运⾏情况,发现线程阻塞在BulkProcessor对象的获取。刷⼀天数据,单个线程的阻塞数去到⼏千。
原因分析:
(1)es未进⾏扩容前,内存吃紧。写⼊es⾮常耗时,导致BulkProcessor提交数据⾮常耗时(BulkProcessor默认累计1000个doc或者数据达到5m就会触发提交)。锁住了BulkProcessor对象,影响了业务线程调⽤BulkProcessor对象的add()⽅法。
(2)BulkProcessor类是允许多线程提交的,通过设置concurrentRequests参数(默认:1),这个参数代表并发数,⽤于创建信号量。经查看,原来是公司组件设置了1个并发,emmm。
优化:mysql操作官方文档
(1)修改基础组建,提⾼并发数。
(2)如何在并发情况下,不让业务线程阻塞在BulkProcessor.add()呢?(如何让业务线程可以继续执⾏业务操作,不受锁的影响)
借鉴BulkProcessor对象的1000个doc/5m数据才触发提交的思想。⽤空间换时间,在业务线程和BulkProcessor间新增⼀个阻塞队列(缓存作⽤),⽤于存放doc。
n个线程负责计算业务,⽣成doc对象,添加到阻塞队列;
n个线程负责从阻塞队列读取数据,并把数据往BulkProcessor.add()。
这样就可以避免业务线程因为调⽤BulkProcessor.add()被Blocked的情况。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。