Elasticsearch查询性能优化

您所在的位置:网站首页 压力mmap Elasticsearch查询性能优化

Elasticsearch查询性能优化

2023-11-04 06:52| 来源: 网络整理| 查看: 265

加配置项index.merge.policy.floor_segment=设置每个segment最小值,index.merge.scheduler.max_thread_count=ES集群负载较低时,后台合并segment线程数,一般=核数/2;curl -XPUT http://xxxx:9200/m_pd_cu_id_ip_2es_inc_hi_out/_settings -d '{"index.merge.policy.floor_segment":"100mb"}'curl -XPUT http://xx:9200/m_pd_cu_id_rela_address_2es_dt_out/_settings -d '{"index.merge.scheduler.max_thread_count":"2"}'原因分析:数据同步服务不断的在提交索引构建,ES集群接收到构建请求数据后会缓冲到内存,达到一定量后生成segment,每个segment是一个包含正排(空间占比90~95%)+倒排(空间占比5~10%)的完整索引文件,每次搜索请求会将所有segment中的倒排索引部分加载到内存,进行查询和打分,然后将命中的文档号拿到正排中召回完整数据记录;如果不对segment做配置,提交又特别频繁的话,就会导致查询性能下降,另外将这里的普通硬盘换成SSD,预计搜索性能还会提升3~5倍;

【总结】搜索性能优化建议:1.segment合并;索引节点粒度配置index.merge.policy.floor_segment=xx mb;segment默认最小值2M2.索引时不需要做打分的字段,关闭norms选项,减少倒排索引内存占用量;字段粒度配置omit_norms=true;3.BoolQuery 优于 TermQuery;目前需求场景全部不需要用到分词,所以尽可能用BoolQuery;4.避免使用对象嵌套结构组建document,建议优化为一个扁平化结构,查询多个扁平化结构在内存做聚合关联;5.设定字符串类型为不分词,可以用于字符串排序,但是比起数字排序会消耗cpu,搜索效率更低,慎用;6.cache设置,就目前数据业务类型,保持默认配置即可,设值fielddata.cache之类的缓存命中率低,反而吃掉了ES集群的一部分内存;

索引性能优化建议:1.调小索引副本数;针对索引节点粒度:curl -XPUT http://xxxx:9200/m_pd_cu_id_gps_2es_inc_hi_out/_settings -d '{"number_of_replicas":1}'2.设置延迟提交,延迟提交意味着数据提交到搜索可见,有延迟,需要结合业务配置;针对索引节点粒度:curl -XPUT http://xxxx:9200/m_pd_cu_id_gps_2es_inc_hi_out/_settings -d '{"index.refresh_interval":"10s"}';默认值1s;3.设置索引缓冲buffer,最大512m,默认值是jvm的10%;ES集群粒度config/elasticsearch.yml :indices.memory.index_buffer_size = 10%

4.适当减少备份数,必要字段只需要提供搜索,不需要返回则将stored设为false;

如果ES提交索引请求达到瓶颈,一般任务队列task-queue为50,可以设置task-queue队列,提升搜索集群索引能力;

以上涉及到索引节点/字段 粒度的配置,均可在创建时代码指定;————————————————原文链接:https://blog.csdn.net/my201110lc/article/details/81712183

备注: segment合并的影响可能只有5%;现象:”发现每次搜索请求时,磁盘需要读40M+的数据,然而一次请求的数据不过10+k“,这个是由于,es底层的lucene对文件的读取采用了mmap方式,而你的机器内存不足以映射所有的文件,所以前几次查询时,会读磁盘,而mmap读取磁盘会默认预读2M的数据量,这才是你请求10K的数据,却有40M的io的真正原因,预读的2M数据,假设有20条同步不在一个段上,那么就会产生40M的磁盘io。解决这个问题的方法是设置这个参数:index.store.type为niofs,两种方式,启动时设置yml,对所有索引生效;或者在新建索引时指定settings中,对于已经建好的索引,必须先close,然后修改调用接口修改settings。再提一点,es默认的mmapfs其实是针对内存足够的情况下使用的,也就是堆外内存能把所有的segment数据都加载进来。对于内存不足的情况,用niofs比较合适,因为它不会预读,每次都走磁盘。

index.store.type 为 niofs

curl -XPUT 'http://localhost:9200/twitter/' -d '{ "settings" : { "index" : { "store":{ "type":"niofs" }, "refresh_interval":"60s"

} }}'

 Mmap fs可能让大索引访问变得缓慢:  https://elasticsearch.cn/article/754

总结: mmap fs对比nio fs,省去了磁盘io上的系统调用,并且不需要在jvm内部做io缓存,也减轻了GC压力。 所以通常来说,mmapfs的性能应该更高。 这也是为什么lucene推荐使用mmap fs,并且ES从5.0开始做为默认的store配置的原因。 然而,mmap系统调用,在内核层面默认会有一个2MB的预读大小设置,也就是说,当映射了一个大文件以后,即使读取其中1k个字节,mmap也会预读取2MB的数据到缓存。 这种策略是基于文件的访问大多数是顺序的假设。 在ES这个特定的应用场景,如果某数据结点上索引不是很大,系统剩余缓存也足够,一般不会有问题。但是如果是大数据应用场景,典型的如海量的日志ELK应用,则可能对大索引的搜索聚合,产生较多的随机磁盘访问。 从而mmap的预读策略,可能会导致大量的无用数据从磁盘读取到系统缓存。 在系统可用的缓存不是非常宽裕的情况下,某些极端场景下,会导致热数据被过于频繁的踢出内存,再反复读入,让磁盘IO不堪重负。 Lucene有一个NativePosixUtil.madvise(buffer,NativePosixUtil.RANDOM)的native调用,可以用于指导内核对mmap过的文件做读取的时候,禁用预读。 上文作者将该调用hack进lucene代码,做搜索对比测试。 结论是对于磁盘io和cache的消耗,niofs都要好于mmapfs,而patch过的mmapfs则比niofs更好。 作者的测试仅限于搜索,对于其他类型的io操作,如写入,merge没有做过详尽测试,因此不清楚利弊。 ES官方开发人员认为这是一个有趣的发现,值得深入去探究。对于用户报告的mmap fs性能比nio fs更差的问题,猜测可能是在大索引读取的场景下,预读带来的额外开销,抵消了相对niofs节省的系统调用等开销。  ES官方提到Lucene已经有一种类似功能的store,叫做NativeUnixDirectory(显然ES目前还没有对这种store的支持),用户动手能力强的话,应该可以利用这个store自己写一个ES plugin。 另外提到JAVA 10提供了O_DIRECT to streams / channels ,似乎官方打算等这个出来以后再看怎么处理这个问题。 要注意,这个预读是mmap层面的,和块设备的预读是两回事。 我们曾经尝试过使用 blockdev --setra 这个linux命令取消块设备预读,证实无法解决这个问题。  结论: 如果ES结点上会存放海量的索引数据,经常会有大索引(如1TB+)的搜索聚合操作,使用NIOFS会更安全,可以避免很多怪异的性能问题。


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3