ElasticSearch性能优化手段汇总

ES性能优化的维度有很多,比如集群维度,节点维度,索引维度,读写维度等,我们针对不同的维度下来探讨可使用的优化措施。

集群维度优化

  • 如果集群不大,节点不多,建议把所有节点都设置成Master eligible,这样能降低集群内少数节点宕机时发生Master选举失败的概率
  • 如果集群很大,建议专门设置几个服务器作为master eligible,因为大集群下集群选举是一个密集IO的网络风暴形式,如果此时master节点还是data节点,同时在进行着耗资源的服务时,会对master的集群状态操作造成极大的影响,甚至可能导致OOM,所以需要单一功能的master eligible节点。
  • 当集群大时,建议将节点设置成单一职责的,比如某个服务器只作为master eligible, data ,injest, coordinating only 中的一种。指定少数几台服务器作为master eligible,让他们自动选择出master,这几台服务器可以有较少的cpu,内存,磁盘资源;使用较高cpu,内存,磁盘的服务器作为data节点;使用中等cpu,较高内存,较低磁盘的服务器作为coordinating(协调)节点。
  • 当有较多的耗资源的查询服务时,可以加入一些Coordinating Only Node,即配置master=false,data=false,injest=false。作为一个协调节点,能够有效的降低master和node的负载,负责搜索结果的Gather/Reduce。甚至耗费资源的搜索请求都集中发给协调节点,实现节点的读写职责分离。
  • 集群设置适当的 discovery.zen.minimum_master_nodes,其值要大于一半的master eligible节点个数,防止出现脑裂。当增加或减少master eligible节点时,记得修改此参数
  • 假设某节点上有Index A的Shard 2的primary, 有Index B shard 1 的replica, 当此节点宕机时,master会立即提拔另一个含有Index A Shard 2 的replica的节点其上的replica为primary,然后等待一分钟,如果在一分钟内宕机的节点没有重新加入集群,那么会在其他不含Index A Shard 2的节点上重新分配一个Index A Shard 2 的replica, 然后从新的primary 上同步数据。一分钟时间很短暂,如果宕机的节点在一分钟之后重新启动,此时新分片数据正在同步,那么master会比较Index A Shard 2的数据在节点宕机期间有没有发生变化,如果有,新的索引分片还会继续同步,删除恢复节点上的索引分片数据;如果没有,取消正在同步分片,复用宕机节点上的索引分片,但其primary的地位会降低为replica。
  • 针对上述情况,设置index.unassigned.node_left.delayed_timeout, 即集群在分片宕机多久后可以开始分片重分配;或者通过命令在短暂时间内禁止分片分配
  • 如果是整个集群重启,那么上述配置不太适用,可设置 gateway.recover_after_nodes 参数,此参数主要是用作整个集群重启时抑制分片的无用分配,就是说要等待集群有多少节点数后开始恢复;设置gateway.expected_nodes gateway.recover_after_time 集群在达到多少个节点或者在启动多久后开始恢复。
  • 根据数据量合理分配分配数和备份数,每个索引的每个分片的数据量不要超过30G,增加备份数能有效降低查询压力,但备份数过多也会增加主节点的数据同步压力。

Node维度优化

  • 在分配节点的JVM内存时,不要超过32G,因为超过32G会使JVM禁用指针压缩,当JVM内存接近50G时才能和指针压缩时的32G内存的实际空间相当。
  • 分配JVM内存时不要超过物理内存的一半,因为ES底层使用Lucene作为搜索架构,其大量使用了系统文件缓存,如果JVM内存分配的太多,会导致Lucene的效率降低。
  • 大集群下根据节点的资源合理的选择角色,尽量使用单一节点角色配置

索引维度优化

  • 在创建索引时,设置好setting,根据数据量及节点数量设置合理的分片数和备份数,每个分片的数据量最好不要超过30G
  • 在创建索引时,设置好mapping,根据字段是否需要索引,存储,分词设置好字段类型,是否索引,是否存储等;字段是否需要排序聚合设置DocValues;日志类型字段提前设置好格式;数组类型字段如果要检索设置Nested类型;关联关系使用Parent/Child模型。
  • 生产环境中对新增字段的索引控制级别不要使用Dynamic,而使用Strict,精确控制新增字段是否被索引和存储
  • 选择合适的分词策略,如果要对分词字段排序需要提前开启FieldData
  • 对类似日志型的会过期的索引,可考虑使用别名,一个别名指向多个索引,当索引过期时直接删除或者关闭索引,这样能防止数据膨胀造成的性能问题
  • 索引使用Nested模型时,通过内部对象查询文档时效率会慢好几倍;使用Parent/Child模型,通过Child查询整个Parent和Child时效率会慢几百倍

查询优化

  • 如果数据一经写入就不再修改,仅仅做查询,那么可以强制索引的segment个数为1,这样能显著提高查询性能
  • 查询时指定返回字段,仅查询需要的字段,这样能有效降低IO,提高响应速度
  • 如果有多个查询条件,尽量把能结果集小的筛选条件放在第一位,ES执行查询时是按顺序处理条件的,如果第一个条件的结果集最小,这样能极大的提高后续条件的处理速度,提高响应速度
  • 当使用 phase_query时,通过 minium_should_match 控制结果必须要匹配多少个单词,可以使用百分比,这样能有效的控制精度,避免长尾效应
  • 深度分页时不要使用from to,es默认每次从分片fetch最多10000(可通过参数修改)条数据,超过会报错。深度分页可以使用scroll,不能跳页
  • 如果不需要排序。可以关闭评分功能,使用High Level Rest Api 的 ConstantScoreQuery
  • 如果索引查询情况较多,可以适当增加query cache的内存阈值或者缓存条数,提高缓存命中率
  • 同一层级下的检索条件的评分权重是相同的,比如同层级 A ,B,C 三个条件,总得评分是 ScoreA/3 + ScoreB/3 +ScoreC/3;同层级的A,B,C(X,Y), 总评分是 ScoreA/3 + ScoreB/3 +(ScoreX/2 + ScoreY/2)/3,变相的削弱了X,Y的评分权重,多个条件下合理的编排条件层级以达到检索时的评分侧重。或者通过boost为条件增加不同的权重。
  • 当数据较少时,多分词查询 的topN结果可能不准确,因为每个Shard的评分是基于当前分片的文档,而不是全部文档。可以设置搜索方式为:DFS Query Then Ferch,即协调节点把所有节点的评分数据汇总起来,计算全局评分,但是这个会很耗费性能,不建议生产环境使用。可以通过shard_size参数设置协调节点向各个分片请求的词根个数,然后在协调节点进行聚合,最后只返回size个词根给到客户端,shard_size >= size,如果shard_size设置小于size,ES会自动将其设置为size,默认情况下shard_size为(1.5 * size + 10)
  • 当查询请求较多时,可以适当增加ES服务器的查询线程池: elasticsearch.yml threadpool.index.queue_size:XX,或者通过Rest Api修改;可将多次查询组合成一个Bulk Request,提高查询效率
  • 尽量将数据先行计算,然后在存入ES,尽量避免在查询时使用Script计算
  • 严禁使用通配符 * 开头的 Term查询,这样会查询Field的所有Term
  • 如果对查询实时性要求很高,可以在参数中设置refresh=true,即立即刷新segment以查询实时数据

写入优化

  • 当有大量的写入请求时,合并写入请求为Bulk请求,提高写入效率。单个Bulk请求数据量不要太大,官方建议5mb-15mb,写入的bulk请求的超时时间足够长,至少60S以上;尽量将数据均衡的写入到不同的Shard上。
  • 可以适当增加索引线程池的任务队列,但线程数不变,避免过多的线程数会导致的上下文切换。
  • 当需要索引大量数据时,可以暂时关闭或者降低 refresh 的频率,或者增大索引缓存:indices.memory.index_buffer_size,默认10%,超过会触发refresh。减少在索引时生成的Segment,以牺牲查询实时性来提高索引的速度;
  • 写入数据时可以通过 wait_for_active_shards 来控制分片Primary 和 Replica 间的数据同步,默认需要所有Replica都同步到数据后才返回。可以降低此值或者设为0 来提高写入请求的响应速度。
  • 没有特殊需求时尽量使用ES 的自动生成的RequestID,这样能提高写入效率同时也能保证数据能均匀分布在所有分片上
  • 设置index.translog.durability=async,默认是sync,即每次Request请求都会落盘;index.translog.sync_interval=60sindex.translog.flush_threshold_size=512,设置translog没60S执行一次flush,或者translog的新内容超过512MB时执行flush。降低可靠性来提高写入效率

你可能感兴趣的:(elasticsearch)