Elasticsearch性能优化思路
Elasticsearch是个非常依赖文件缓存的一个数据库,优化主要有两个思路,一个是优化搜索的逻辑,一个优化缓存。
搜索逻辑的优化,可以考虑使用合理的索引设置,合理的搜索方法,使得搜索的路径短、返回快、消耗资源少
缓存的优化就比较多了,首先是文件缓存,就是服务器除了jvm之外的缓存,这部分需要预留的充足,然后就是存储的体积,存储的体积越小,文件缓存能缓存的部分就越多,读磁盘的次数就越少,相应的性能就能起飞。然后是jvm内的缓存,这个就涉及到了优化缓存的淘汰时间,缓存的结构等方向,如何提高缓存的命中率,合理延长缓存的生命周期就很重要了
优化方向与细节
分片数量
分片数量:合理的分片很重要,例如一台机是4核cpu,一共有3台机子,那么理论上分片数量在3*4=12个左右会有比较好的一个性能的利用,如果有副本的话,可以适当减少一些分片数量,不过实际上一个分片可能会有几个大的段存储,所以一个节点的分片数量比节点的cpu线程数少一些会比较好。
副本数量:
设置副本可以提高数据的一个安全性,最大的作用是防止数据丢失,同时提高一些搜索的性能和可用性,但是在源数据不在es即es的数据是从别的数据库同步过来的情况下,其实不用担心数据的丢失。es的副本是比较吃磁盘性能的,集群环境下拥有副本会增加磁盘的读写压力,当磁盘性能不够的时候,可以考虑不要副本。
段合并相关
es的段是不可变的,一个分片拥有一个或者多个段,取决于数据的更新和刷新,对于插入的数据,首先是落在内存缓冲区,形成一个内存的段,然后定时刷入磁盘形成一个磁盘的段(默认是1s),当段数量多的时候,es会合并多个段为一个段,这时候会吃磁盘性能。同时如果段太多,也会影响查询的性能。而es高版本有对段合并进行限流,默认是20M/s。对于段优化来说,主要是刷入时间的设置,如果es的插入是持续不断的,那建议设置大一些的刷新时间,避免持续产生大量的段。同时在手动导入大批量数据的时候也可以调大这个刷新时间,然后导入完成后手动调用api强制进行段合并,可以获得一个良好的初始性能。
字段设置
对于不搜索的只读字段,设置不索引,如果字段只需要排序聚合分组,也可以不索引,这些依赖的是正排索引;当一个字段不需要聚合、排序、分组时候,可以禁用doc_value;text类型的field会存储norm值,用来计算doc的相关度分数,如果我们需要对一个text field进行搜索,但是不关心这个field的分数,那么可以禁用norm值;如果 field 只需要提供搜索,不需要返回则将 stored 设为 false。一般来说,在保证功能的前提下把数据使用的存储空间压的越小,性能越好。除此之外可以考虑使用best_compression压缩算法来压缩索引,比默认的lz4有更高的压缩比,可以通过减少磁盘的总大小来提高性能,但是同时插入的性能会降低一些
内存
内存对于es的搜索来说是非常重要的,一个是文件缓存,一个是应用内存,应用内存就是es的jvm使用的内存,文件缓存就是free命令里面cache使用的内存,一般来说,建议预留一般以上的内存给文件缓存,这样能确保性能。
排序
对于一个搜索功能如果不是按分数排序而是有一个字段的默认排序,则在建立索引的时候设置索引的排序为这个字段,这样设置可以大大的降低大部分搜索请求的性能消耗。同时如果不要求返回总数量可以请求里track_total_hits设置为false,这样es不会尝试搜索所有数据来计算返回总量。
es缓存优化
这里主要指的jvm内的缓存,主要有节点查询缓存、字段数据缓存(排序)、分片请求缓存和索引缓存。而这里面很多缓存的整体生命周期是较短的,和数据的刷新频率有关。这些缓存有一部分是会集体失效的,因为不是长期缓存,所以即使是热词搜索,也不能保证数据一定在内存里。所以,可以针对这些缓存的特征,以及业务日常搜索的特征,进行预热优化,比如,对一些热词进行定时任务预热,可以优化es的缓存结构以及大部分用户的查询体验。
客户端优化
es查询是使用http协议,客户端使用http请求,需要设置合理的连接池,或者使用开源框架并设置合理的连接池配置。以java的spring自带的es客户端来说,http的客户端连接池和超时的配置就过于保守了,如果出现一些请求慢或者卡死的情况,很容易影响所有请求。
索引别名
业务尽量使用索引的别名,在es一个别名可以对应多个索引,业务使用别名,在很多情况下可以很方便的无缝切换索引,提高可用性。
机器配置
对于机器配置,内存>磁盘性能>cpu>其他。内存是最重要的,特别是文件缓存filesystem cache能用的内存。然后是磁盘性能,当内存不足以缓存全部数据,请求就会比较吃磁盘性能,包括es 的一些段合并也会使用到磁盘的性能。然后是cpu主要影响排序聚合以及正则的一些计算。一般来说总体来说的优化思路是,减少数据的磁盘占用,提高可用内存的容量,优化缓存的命中率。(对于查询频率不高,但是数据量很多的业务,可以考虑降低一些jvm的内存,把更多的内存给filesystem cache)