背景:在数据和服务都准备完成的情况下,打开页面,发现请求需要要几秒才返回;
思路:1.查看搜索接口请求本身耗时情况,排除网络抖动因素,发现搜索接口请求到ES返回结果本身耗时较高;
2.检查每次请求到ES的入参,并在原有参数中加入"profile": true,查看ES处理搜索请求的耗时分布情况;
入参:
返回:
发现只是一个简单的termQuery耗时818ms,然后查看是否ES集群负载情况;
3.初步定位:ES集群的cpu和内存消耗较大,磁盘io写入较高,认为是数据同步服务不断的在提交索引建立请求导致ES集群负载较高,影响了查询性能;
4.初步解决:停掉数据同步服务,使ES集群负载降下来,再做查询,发现搜索响应时间没有任何变化,继而再次监控ES机器磁盘IO;
5.再次定位:发现每次搜索请求时,磁盘需要读40M+的数据,然而一次请求的数据不过10+k,考虑到搜索的索引文件是由多个segment组成,这里是读取多个segment到内存进行查询匹配,打开segment分布情况发现一个索引节点有多个小的segment,判断是由于打开多个文件随机读写提升了读取索引数据耗时;
iostat
curl 'http://xxxx:9200/_cat/segments/m_pd_cu_id_wifi_2es_inc_hi_out?v&h=shard,segment,size,size.memory'
6.再次解决:手动合并segment,几分钟后合并完成,并进行搜索,性能显著提升,问题解决;
curl -XPOST 'http://xxxx:9200/_forcemerge?max_num_segments=1'
7.永久解决:加配置项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默认最小值2M
2.索引时不需要做打分的字段,关闭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队列,提升搜索集群索引能力;
以上涉及到索引节点/字段 粒度的配置,均可在创建时代码指定;