Elasticsearch-08-性能优化
4. 性能优化
4.1 写入速度优化
4.1.1 增大translog flush间隔
配置项:index.translog.durability
默认值是request
,也就是每次写入完成后马上进行刷盘。这实际上是影响ES写入性能最大的因素。但只有这样,才能保证每个写操作都是安全的
如果系统可以忍受一定概率的数据丢失,那么可以调整为 async
,同时增大刷盘间隔和translog最大大小来提高写入性能
index.translog.durability: async
index.translog.sync_interval: 5s
index.translog.flush_threshold_size: 512mb
4.1.2 增大index refresh间隔
配置项: index.refresh_interval
默认是1秒,这意味着数据在写入后1秒就可以被搜索到了。如果间隔过短,则会产生大量Lucene的段,这将导致频繁的段合并。如果不需要这么高的实时搜索性能,可以适当考虑降低索引refresh周期
4.1.3 段合并优化
段合并是ES在运行中不可避免的操作,通过段合并可以提高搜索的速度,并节约系统资源。但由于段合并时需要消耗大量的CPU和I\O资源,所以,过于频繁的段合并反而会拖慢ES的运行速度
配置项:index.merge.scheduler.max_thread_count
默认值是Math.max(1, Math.min(4, <<node.processors, node.processors>> / 2))
。默认值的设置对于ssd来说很友好,但如果只有一块机械硬盘的话,还是设置成1比较好
4.1.4 indexing buffer
index buffer是在ES为doc创建索引时使用。当缓冲区写满之后,会生成一个新的段。每个分片都有自己的buffer,在实际计算每个分片有多少buffer的时候要除以分片数
配置项
indices.memory.index_buffer_size: 10%
indices.memory.min_index_buffer_size: 48MB
indices.memory.max_index_buffer_size: 100MB # 默认是无限制
4.1.5 使用bulk请求
批量写入比多次单个写入要高效的多,但要注意控制批量请求的大小和数量。
如果太大的话内存扛不住
如果过多的话,则可能造成过长的等待队列,这可能会引起频繁gc
4.1.6 调整索引过程
1)使用自动生成的文档id
如果手动给出了文档id,那么ES在写入时会先去检查是否要执行更新操作,这属于不必要的操作
2)调整字段mapping
对于不需要建立索引的字段,index属性设置为no或者not_analyzed,这么做可以降低CPU的占用
3)调整 _source 字段
source 字段用于存储 doc 原始数据,对于部分不需要存储的字段,可以通过 includes excludes过滤,或者将source禁用,一般用于索引和数据分离。
4.2 搜索速度优化
4.2.1 预留足够的内存空间
在一般情况下,应用程序的读写都会被操作系统cache(除了direct方式),cache保存在系统物理内存中(线上应该禁用swap),命中cache可以降低对磁盘的直接访问频率。搜索很依赖对系统cache 的命中,如果某个请求需要从磁盘读取数据,则一定会产生相对较高的延迟。应该至少为系统cache预留一半的可用物理内存,更大的内存有更高的cache命中率。
4.2.2 使用冗余字段
ES虽然允许join操作,但嵌套查询的效率比普通查询低好几倍,而父子文档可能会更慢。
所以,使用冗余字段往往比嵌套查询和父子文档来高效的多
同时,冗余字段还在某些特定方面表现优秀
如果所有的文档都有某些相同字段,并且大多数查询都会对其在一个固定的范围上进行聚合。那我们可以在创建索引的时候把这个固定的范围带上,并使用term聚合来加快聚合速度
例如:搜索商品时按照价格区间进行搜索,那么我们可以在创建索引的时候加入价格区间这个字段来加快索引
4.2.3 强制进行段合并
对于几乎不怎么更新或者不再更新的索引执行强制段合并。因为较少了段的数量,结果的合并速度会提高,同时还能提高恢复的速度
4.2.4 使用全局序号(global ordinals)
全局序号是一种数据结构,用于在keyword字段上进行term聚合。它用一个数值来代表字段中的字符串值,然后为每一数值分配一个 bucket。默认情况下,他们会延迟构建。但由于ES不知道哪些字段会被用于term聚合,所以我们要提前告诉他
PUT index
{
"mappings":{
"type":{
"properties": {
"foo":{
"type": "keyword",
"eager_global_ordinals": true
}
}
}
}
}
4.2.5 限制搜索请求涉及到的分片数
一个搜索请求涉及的分片数量越多,协调节点的CPU和内存压力就越大。默认情况下,ES会拒绝超过1000个分片的搜索请求。我们应该更好地组织数据,让搜索请求的分片数更少。如果想调节这个值,则可以通过action.search.shard_count配置项进行修改。虽然限制搜索的分片数并不能直接提升单个搜索请求的速度,但协调节点的压力会间接影响搜索速度,例如,占用更多内存会产生更多的GC压力,可能导致更多的stop-the-world时间等,因此间接影响了协调节点的性能
4.2.6 使用ARS来提高响应速度
自适应分片选择(Adaptive Replica Selection)可以避免搜索请求路由到负载较高的节点上。该选项在集群负载均衡是能略微提高吞吐量和响应速度;在出现繁忙节点时,能有效提高吞吐量和响应速度
配置项: cluster.routing.use_adaptive_replica_selection
该配置从ES6.1开始启用,但默认是关闭状态。不过再ES7中,它将默认开启
4.3 故障诊断常用手段
- profile API 来定位慢查询
- explain API 来分析为什么分片分配失败
- cat API 来检查内存使用情况
4.4 内存里都有些啥
- bulk队列
- Netty内存池
- index buffer,写入缓冲区
- 数据集的聚合
- segment
- 各种cache,fielddata cache,node query cache,shard request cache
推荐阅读
- 使用索引生命周期管理实现热温冷架构:https://www.elastic.co/cn/blog/implementing-hot-warm-cold-in-elasticsearch-with-index-lifecycle-management
- 高级调优:查找并修复 Elasticsearch 慢查询:https://www.elastic.co/cn/blog/advanced-tuning-finding-and-fixing-slow-elasticsearch-queries
- Elasticsearch 集群协调迎来新时代:https://www.elastic.co/cn/blog/a-new-era-for-cluster-coordination-in-elasticsearch
- Elasticsearch 缓存深度剖析:一次提高一种缓存的查询速度,https://www.elastic.co/cn/blog/elasticsearch-caching-deep-dive-boosting-query-speed-one-cache-at-a-time
- 使用ARS来提高搜索响应速度:https://www.elastic.co/cn/blog/improving-response-latency-in-elasticsearch-with-adaptive-replica-selection
- https://www.elastic.co/guide/en/elasticsearch/reference/current/removal-of-types.html#_migrating_multi_type_indices_to_single_type