ElasticSearch--优化写入速度的方法--修改配置
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ElasticSearch--优化写入速度的方法--修改配置相关的知识,希望对你有一定的参考价值。
简介
说明
本文介绍如何优化ElasticSearch的写入性能。
相关网址
ElasticSearch--写入数据的流程(原理)_IT利刃出鞘的博客
方案说明
下边的方案,有的比较推荐改动,有的不推荐改动。不推荐的原因一般是得不偿失,比如:数据容易丢失,查询效率变低等。
tranlog flush(推荐)
改为异步刷新(推荐)
说明
从ES 2.x开始,translog默认的持久化策略为:每个请求都“flush”(写入磁盘)。对应配置项如下:
index.translog.durability: request
这是影响 ES 写入速度的最大因素。但是这样写操作比较可靠。如果系统可以接受一定概率的数据丢失(例如:数据写入主分片成功,尚未复制到副分片时,主机断电。由于数据既没有刷到Lucene,translog也没有刷盘,恢复时translog中没有这个数据,数据丢失),则调整translog持久化策略。
优化方案
1.异步写磁盘
index.translog.durability: async
减少刷盘次数(不推荐)
说明
每30分钟或当translog达到一定大小(由index.translog.flush_threshold_size控制,默认512mb), ES会触发一次flush操作,此时ES会先执行refresh操作将buffer中的数据生成segment,然后调用lucene的commit方法将所有内存中的segment 写(fsync)到磁盘。
优化方案
1.加大translog刷盘间隔时间。默认为5s,不可低于100ms。
index.translog.sync_interval: 120s
2.加大translog刷盘的最大触发值。默认值为512MB。
index.translog.flush_threshold_size: 1024mb
设置为async表示translog的刷盘策略按sync_interval配置指定的时间周期进行。
增大indexing buffer(推荐)
说明
indexing buffer是为doc建立索引时使用的,当缓冲满时会生成一个新的segment并触发刷盘操作。这是除refresh_interval刷新索引外,另一个生成新segment的机会。
默认值不太够用,对于大量写入的场景也显得有点小。
设置的这个index buffer大小,是所有的shard公用的,那些特别活跃的shard会更多的使用这个buffer。对于每个shard来说,最多给512mb,因为再大性能就没什么提升了。
优化方案
1.index_buffer_size(默认为10%,即:JVM堆大小的10%)
indices.memory.index_buffer_size=20%
2.min_index_buffer_size(默认为48m)
indices.memory.min_index_buffer_size=48MB
3.max_index_buffer_size(默认为无限制,一般无需改动)
indices.memory.min_index_buffer_size=xxx
增大线程池(推荐)
相关网址:ElasticSearch--线程池(ThreadPool)--使用/设置_IT利刃出鞘的博客
说明
大量的写入考虑使用bulk请求。
Bulk写入索引的过程属于计算密集型任务,应该设置使用固定大小的线程池,来不及处理的任务放入队列。线程池最大线程数量应配置为CPU核心数+1(这也是默认设置),可以避免过多的上下文切换。队列大小可以适当增加,但要严格控制大小,过大的队列会导致较高的GC压力,并可能导致FGC频繁发生。
优化方案
设置search、write、index、merge的队列长度。线程池大小保持默认就好;一般修改队列大小。
# Search pool
#thread_pool.search.size: 5
thread_pool.search.queue_size: 100
# Write pool
# thread_pool.bulk.size: 16
thread_pool.bulk.queue_size: 300
# Index pool
# thread_pool.index.size: 16
thread_pool.index.queue_size: 300
# 这个参数慎用!强制修改cpu核数,以突破写线程数限制
# processors: 16
减小fielddata(推荐)
说明
在ES中,text类型的字段使用一种叫做fielddata的查询时内存数据结构。当字段被排序,聚合或者通过脚本访问时这种数据结构会被创建。它是通过从磁盘读取每个段的整个反向索引来构建的,然后存存储在java的堆内存中。
fielddata默认是不开启的。Fielddata可能会消耗大量的堆空间,尤其是在加载高基数文本字段时。一旦fielddata已加载到堆中,它将在该段的生命周期内保留。此外,加载fielddata是一个昂贵的过程,可能会导致用户遇到延迟命中。这就是默认情况下禁用fielddata的原因。如果尝试对文本字段进行排序,聚合或脚本访问,将看到以下异常:
“Fielddata is disabled on text fields by default. Set fielddata=true on [your_field_name] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory.”
如果要对分词的field执行聚合操作,必须将fielddata设置为true:
POST /test_index/_mapping/test_type
"properties":
"test_field":
"type": "text",
"fielddata": true
优化方案
默认是没有限制的,无限制可能导致频繁的OOM,限制使用则有可能导致频繁的驱逐(eict和relaod)、大量的IO性能损耗,内存碎片,gc。
indices.fielddata.cache.size: 20%
也可以设置为绝对内存比如16g等。超出限制,则会清除内存已有的fielddata。
增大refresh interval(不推荐)
说明
默认情况下索引的refresh_interval为1秒,这意味着数据写1秒后就可以被搜索到,进而满足Elasticsearch的近实时查询。
每次索引的refresh会产生一个新的Lucene段,会导致频繁的segment merge行为,造成大量的磁盘io和内存占用,影响效率。如果不需要这么高的实时性,应该增大索引refresh周期。
优化方案
1.增大索引refresh周期。(默认为1s)
index.refresh_interval: 30s
段合并(不推荐)
说明
segment merge操作对系统I/O和内存占用都比较高,merge行为由Lucene控制。相关配置如下:
index.merge.scheduler.max_thread_count (default Math.max(1, Math.min(4, Runtime.getRuntime().availableProcessors()/2)))
index.merge.policy.*
merge策略有三种:
- tiered(默认策略):分层合并策略,该策略将大小相似的段放在一起合并,当然段的数量会限制在每层允许的最大数量之中。
- log_byte_size:字节大小对数合并策略,将创建由多个大小处于对数运算后大小在指定范围索引组成的索引。
- loc_doc:文档数量对数合并策略,与log_byte_size策略类似,只是将以段的字节大小来计算的方式换成了文档数量。
索引创建时合并策略就已确定,不能更改,但是可以动态更新策略参数。如果堆栈经常有很多merge,则可以考虑适当增加index.merge.policy.segments_per_tier配置的值(该配置指定了每层分段的数量,取值越小则最终segment越少,因此需要merge的操作越多,可以考虑适当增加此值)。同时可以考虑适当降低index.merge.policy.max_merged_segment的值(指定了单个segment的最大容量)。
index.merge.policy.segments_per_tier (default 10,其应该大于等于index.merge.policy.max_merge_at_once。)
index.merge.policy.max_merged_segment (default 5GB)
优化方案
1.修改最大线程数
最大线程数max_thread_count的默认值是一个比较理想的值,如下:
Math.max(1, Math.min(4, Runtime.getRuntime().availableProcessors() / 2))
- 如果节点配置的cpu核数较高,merge占用的资源可能会偏高,影响集群的性能。
- 如果只有一块硬盘并且非 SSD,则应该把它设置为1,因为在旋转存储介质上并发写,由于寻址的原因,只会降低写入速度。
- 如果Elasticsearch写路径配置多个磁盘,可以在磁盘数的范围内结合集群的负载取一个合适的值。
可以通过下面的命令调整某个index的merge过程的并发度:
index.merge.scheduler.max_thread_count:2
2.修改策略参数
索引创建时合并策略就已确定,不能更改,但可以动态更新策略参数。如果堆栈经常有很多merge,则可以尝试调整以下策略配置:
配置1:
index.merge.policy.segments_per_tier
该属性指定了每层分段的数量,默认为10,取值越小则最终segment越少,因此想要merge的操作更多,可以考虑适当增加此值。其应该大于等于index.merge.policy.max_merge_at_once(默认为10)。
配置2:
index.merge.policy.max_merged_segment
指定了单个segment的最大容量,默认为5GB,大于这个大小的segment,不用参与归并(forcemerge 除外)。为了减少参与merge的segment的数量,减少磁盘IO以及内存占用,可以考虑适当降低此值,此场景适用于按天或者时间段建index的场景,当index变为只读后使用forcemerge进行强制归并,在提高检索和Reindex效率的同时,减少内存的占用。
节点探查时间(推荐)
官网网址:Zen Discovery | Elasticsearch Guide [6.6] | Elastic
说明
大量写入的场景,会占用大量的网络带宽,很可能使节点之间的心跳超时。并且默认的心跳间隔也相对过于频繁(1s检测一次)。
优化方案
discovery.zen.fd.ping_timeout: 60s
discovery.zen.fd.ping_retries: 6
discovery.zen.fd.ping_interval: 30s
配置 | 默认值 | 描述 |
ping_interval | 1秒 | 节点ping的频率。 |
ping_timeout | 3秒 | 等待节点响应的超时时间。 |
ping_retries | 3 | ping失败/超时重试次数。 |
以上是关于ElasticSearch--优化写入速度的方法--修改配置的主要内容,如果未能解决你的问题,请参考以下文章
Elasticsearch7.8.0版本优化——写入速度优化
《Elasticsearch 源码解析与优化实战》第18章:写入速度优化
《Elasticsearch 源码解析与优化实战》第18章:写入速度优化