【FusionInsight Elasticsearch二次开发最佳实践】写入优化

网友投稿 775 2022-05-28

1.1 基本优化手段

Elasticsearch默认的设置和参数配置下,是综合考虑了数据的可靠性、搜索实时性、写入速度等因素。如果业务场景中,业务对数据的写入速度要求高,可以通过调整一些策略,优化写入速度。

综合来说,提升写入速度可以从以下几个方面入手:

1.         加大index refresh间隔,除了降低IO,更重要的是降低了segment merge的频率;

2.         加大translog refresh间隔,目的是降低iops、writeblock;

3.         调整bulk请求,控制每次bulk请求提交的量;

4.         优化磁盘间的任务均匀情况,将shard尽量均匀分布到机器的各个磁盘;

【FusionInsight Elasticsearch二次开发最佳实践】写入优化

5.         优化节点间的任务分布,将任务尽量均匀地发布到各节点,避免单点阻塞问题;

6.         优化Lucene层建立索引的过程,目的是降低CPU占用率及IO,例如,禁用_all字段。

1.2 索引刷新间隔

默认情况下索引的refresh_interval为1秒,这意味着数据写1秒后就可以被搜索到,每次索引的refresh会产生一个新的lucene段,这会导致频繁的segment merge行为,如果你不需要这么高的搜索实时性,应该降低索引refresh周期,如:

index.refresh_interval: 120s

1.3 Translog刷新间隔

默认设置下,translog的持久化策略为:每个请求都flush。对应配置项为:

index.translog.durability: request

这是影响Elasticsearch写入速度的最大因素。但是只有这样,写操作才有可能是可靠的,如果系统可以接受一定几率的数据丢失,调整translog持久化策略为周期性和一定大小的时候flush:

index.translog.durability: async

index.translog.sync_interval: 120s

index.translog.flush_threshold_size: 3gb

index.translog.flush_threshold_period: 120m

1.4 段合并优化

segment merge操作对系统CPU和IO占用都比较高,从es 2.0开始,merge行为不再由es控制,而是转由lucene控制。有以下调整开关:

index.merge.scheduler.max_thread_count:最大线程数

index.merge.policy.*

最大线程数的默认值为:

Math.max(1, Math.min(4, Runtime.getRuntime().availableProcessors() / 2))

是一个比较理想的值,如果你只有一块硬盘并且非SSD,应该把他设置为1,因为在旋转存储介质上并发写,由于寻址的原因,不会提升,只会降低写入速度。

index.merge.policy.floor_segment

该属性用于阻止segment的频繁flush,小于此值将考虑优先合并,默认为2M,可考虑适当降低此值,如1M。

index.merge.policy.segments_per_tier

该属性指定了每层分段的数量,取值越小最终segment越少,因此需要merge的操作更多,可以考虑适当增加此值。默认为10,他应该大于等于10。

index.merge.policy.max_merge_at_once

"merge":{

"scheduler":{

"max_thread_count" : "1"

},

"policy":{

"segments_per_tier" : "20",

"max_merge_at_once": "20",

"floor_segment" : "1m",

"max_merged_segment" : "5g"

}

}

1.5 Indexing Buffer

indexing buffer在为doc建立索引时使用,当缓冲满时会刷入磁盘,生成一个新的 segment,这是除refresh_interval外另外一个刷新索引,生成新segment的机会。每个 shard有自己的indexing buffer,下面的关于这个buffer大小的配置需要除以这个节点上所有的shard数量。

indices.memory.index_buffer_size

默认为整个堆的10%,如30GB堆内存,约占300M,在大量的索引操作时,可以考虑适当增大,但不要超过20%。

1.6 Bulk请求

1.         使用批量请求,设置合理的数据条数:使用bulk命令进行批量索引数据时,每批次提交的数据大小为5~15MB;比如每条数据大小为1k,那么建议批量提交的数据条数为5000条;当前集群的最佳批量请求大小,可以从5MB开始测试,缓慢增加这个大小,直到写入性能不能提升为止。

2.         每个批量请求中只处理一个索引的数据:一个bulk请求只写入一个索引的数据,不建议一个bulk请求同时写入多个索引的数据,不同索引的数据分多个bulk请求提交。

3.         建立索引的过程偏计算密集型任务,应该使用固定大小的线程池配置,来不及处理的放入队列,线程数量配置为CPU核心数+1,避免过多的上下文切换。队列大小可以适当增加,但一定要严格控制大小,过大的队列导致较高的GC压力,并可能导致FGC频繁发生。

1.7 磁盘间的任务均衡

如果你的部署方案是为path.data配置多个路径来使用多块磁盘, es在分配shard 时,落到各磁盘上的shard可能并不均匀,这种不均匀可能会导致某些磁盘繁忙,利用率达到100%,这种不均匀达到一定程度可能会对写入性能产生负面影响。

所以建议每个数据实例挂载单块磁盘。

1.8 节点间的任务均衡

为了在节点间任务尽量均衡,数据写入客户端应该把bulk请求轮询发送到各个节点。

当使用java api ,或者rest api的bulk接口发送数据时,客户端将会轮询的发送的集群节点,节点列表取决于:

当client.transport.sniff为true,(默认为 false),列表为所有数据节点。

否则,列表为初始化客户端对象时添加进去的节点。

java api的TransportClient和rest api的RestClient都是线程安全的,当写入程序自己创建线程池控制并发,应该使用同一个Client对象。在此建议使用rest api,兼容性好,只有吞吐量非常大才值得考虑序列化的开销,显然搜索并不是高吞吐量的业务。

观察bulk请求在不同节点上的处理情况,通过cat接口观察bulk线程池和队列情况,是否存在不均:

_cat/thread_pool/bulk?v

另外,也可以搭建NGINX服务来达到负载均衡。

1.9 分片均匀分布

配置total_shards_per_node参数,让分片更加均匀的分布在各个实例上。表示限制每个实例上分布该该索引的分片最大个数,如2,即表示每个实例上最多分布2个该索引的分片。

说明:total_shards_per_node参数值=(索引总分片数/数据实例数) + 1(向上取整)。

1.10 索引过程调整和优化

1.10.1 自动生成doc ID

分析es写入流程可以看到,写入doc时如果是外部指定了id,es会先尝试读取原来doc的版本号,判断是否需要更新,使用自动生成doc id可以避免这个环节,从而避免出现在磁盘IOPS能力不足的情况下,磁盘IO被读IO大量占用,导致写入速度受限于磁盘IO。

1.10.2 调整字段 Mappings

1.         字段的index属性设置为: not_analyzed,或者no。对字段不分词,或者不索引,可以节省很多运算,降低CPU占用。尤其是binary类型,默认情况下占用CPU非常高,而这种类型根本不需要进行分词做索引。

2.         调整_source字段:_source字段用于存储doc原始数据,对于部分不需要存储的字段,可以通过includes excludes来过滤,或者将_source 禁用,一般用于索引和数据分离。

3.         禁用_all字段:_all字段默认是开启的,其中包含所有字段分词后的关键词,作用是可以在搜索的时候不指定特定字段,从所有字段中检索。如果你不需要这个特性,可以禁用_all,可以小幅的降低CPU 压力,对速度影响并不明显。

FusionInsight Elasticsearch EI企业智能

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:技术经理:求求你,别再乱改数据库连接池的大小了!
下一篇:图解 Redis | AOF 持久化
相关文章