elasticsearch参数优化

本文探讨了Elasticsearch的写入与搜索速度优化策略,包括调整translog、refresh间隔,优化bulk请求,磁盘任务均匀分布,节点间任务均衡,Lucene层建立索引优化,以及搜索速度和磁盘使用量的优化方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

写入速度优化

提升写入速度从以下几方面入手:
· 加大translog flush间隔,目的是降低iops、writeblock。
ES 2.x开始,在默认设置下,translog的持久化策略为:每个请求都“flush”。对应配置项如下:
index.translog.durability: request
由于数据既没有刷到Lucene,translog也没有刷盘,恢复时translog中没有这个数据,数据丢失),则调整translog持久化策略为周期性和一定大小的时候“flush”,例如:
index.translog.durability: async设置为async表示translog的刷盘策略按sync_interval配置指定的时间周期进行。index.translog.sync_interval: 120s加大translog刷盘间隔时间。默认为5s,不可低于100ms。index.translog.flush_threshold_size: 1024mb超过这个大小会导致refresh操作,产生新的Lucene分段。默认值为512MB。
· 加大index refresh间隔,除了降低I/O,更重要的是降低了segment merge频率。
如果不需要这么高的搜索实时性,应该降低索引refresh周期,例如:
index.refresh_interval: 120s
merge策略index.merge.policy有三种:
· tiered(默认策略);· log_byete_size;· log_doc。
index.merge.policy.segments_per_tier
该属性指定了每层分段的数量,取值越小则最终segment越少,因此需要merge的操作更多,可以考虑适当增加此值。默认为10,其应该大于等于index.merge.policy.max_merge_at_once。index.merge.policy.max_merged_segment指定了单个segment的最大容量,默认为5GB,可以考虑适当降低此值。
下面的这个buffer大小的配置需要除以这个节点上所有shard的数量:
indices.memory.index_buffer_size默认为整个堆空间的10%。indices.memory.min_index_buffer_size默认为48MB。indices.memory.max_index_buffer_size默认为无限制。
· 调整bulk请求。
如果 CPU 没有压满,则应该提高写入端的并发数量。但是要注意 bulk线程池队列的reject情况,出现reject代表ES的bulk队列已满,客户端请求被拒绝,此时客户端会收到429错误(TOO_MANY_REQUESTS),客户端对此的处理策略应该是延迟重试。
· 优化磁盘间的任务均匀情况,将shard尽量均匀分布到物理主机的各个磁盘。
为ES增加了两种策略。
· 简单轮询:在系统初始阶段,简单轮询的效果是最均匀的。
基于可用空间的动态加权轮询:以可用空间作为权重,在磁盘之间加权轮询。
· 优化节点间的任务分布,将任务尽量均匀地发到各节点。
当使用Java API或REST API的bulk接口发送数据时,客户端将会轮询发送到集群节点,节点列表取决于:
· 使用Java API时,当设置client.transport.sniff为true(默认为false)时,列表为所有数据节点,否则节点列表为构建客户端对象时传入的节点列表。· 使用REST API时,列表为构建对象时添加进去的节点。
理论上,Java API在序列化上有性能优势,但是只有在吞吐量非常大时才值得考虑序列化的开销带来的影响,通常搜索并不是高吞吐量的业务。
要观察bulk请求在不同节点间的均衡性,可以通过cat接口观察bulk线程池和队列情况:_cat/thread_pool
· 优化Lucene层建立索引的过程,目的是降低CPU占用率及I/O,例如,禁用_all字段。
通过ES写入流程可以看出,写入doc时如果外部指定了id,则ES会先尝试读取原来doc的版本号,以判断是否需要更新。这会涉及一次读取磁盘的操作,通过自动生成doc ID可以避免这个环节。
调整字段Mappings
(1)减少字段数量,对于不需要建立索引的字段,不写入ES。
(2)将不需要建立索引的字段index属性设置为not_analyzed或no。
(3)减少字段内容长度。
(4)使用不同的分析器(analyzer),不同的分析器在索引过程中运算复杂度也有较大的差异。
_source 字段用于存储 doc 原始数据,对于部分不需要存储的字段,可以通过 includes excludes过滤,或者将_source禁用,一般用于索引和数据分离。
_all字段中包含所有字段分词后的关键词,作用是可以在搜索的时候不指定特定字段,从所有字段中检索。ES 6.0默认禁用_all字段主要有以下几点原因:
· 由于需要从其他的全部字段复制所有字段值,导致_all字段占用非常大的空间。
· _all 字段有自己的分析器,在进行某些查询时(例如,同义词),结果不符合预期,因为没有匹配同一个分析器。
· 由于数据重复引起的额外建立索引的开销。
Norms用于在搜索时计算doc的评分,如果不需要评分,则可以将其禁用:
"title": {"type": "string","norms": {"enabled": false}}
index_options用于控制在建立倒排索引过程中,哪些内容会被添加到倒排索引,例如,doc数量、词频、positions、offsets等信息,优化这些设置可以一定程度降低索引过程中的运算任务,节省CPU占用率。
参考配置

{
"template":*",
"order" : 0,
"settings": {"index.merge.policy.max_merged_segment" :2gb","index.merge.policy.segments_per_tier" :24","index.number_of_replicas" :1","index.number_of_shards" :24","index.optimize_auto_generated_id" :true","index.refresh_interval" :120s","index.translog.durability" : "async","index.translog.flush_threshold_size" :1000mb","index.translog.sync_interval" :120s","index.unassigned.node_left.delayed_timeout" :5d}}
elasticsearch.yml中的配置:indices.memory.index_buffer_size: 30%

搜索速度的优化

应该至少为系统cache预留一半的可用物理内存,更大的内存有更高的cache命中率。
使用更快的硬件。
为了让搜索时的成本更低,文档应该合理建模。特别是应该避免join操作,嵌套(nested)会使查询慢几倍,父子(parent-child)关系可能使查询慢数百倍,因此,如果可以通过非规范化(denormalizing)文档来回答相同的问题,则可以显著地提高搜索速度。
还可以针对某些查询的模式来优化数据的索引方式。例如,如果所有文档都有一个 price字段,并且大多数查询在一个固定的范围上运行range聚合,那么可以通过将范围“pre-indexing”到索引中并使用terms聚合来加快聚合速度。
有些字段的内容是数值,但并不意味着其总是应该被映射为数值类型,例如,一些标识符,将它们映射为keyword可能会比integer或long更好。
在使用日期范围检索时,使用now的查询通常不能缓存,因为匹配到的范围一直在变化。但是,从用户体验的角度来看,切换到一个完整的日期通常是可以接受的,这样可以更好地利用查询缓存。
为不再更新的只读索引执行force merge,将Lucene索引合并为单个分段,可以提升查询速度。
全局序号是一种数据结构,用于在keyword字段上运行terms聚合。它用一个数值来代表字段中的字符串值,然后为每一数值分配一个 bucket。这需要一个对 global ordinals 和 bucket的构建过程。默认情况下,它们被延迟构建,因为ES不知道哪些字段将用于 terms聚合,哪些字段不会。可以通过配置映射在刷新(refresh)时告诉ES预先加载全局序数:
在这里插入图片描述
terms聚合有两种不同的机制:
· 通过直接使用字段值来聚合每个桶的数据(map)。· 通过使用字段的全局序号并为每个全局序号分配一个bucket(global_ordinals)。ES 使用 global_ordinals 作为 keyword 字段的默认选项,它使用全局序号动态地分配bucket,因此内存使用与聚合结果中的字段数量是线性关系。在大部分情况下,这种方式的速度很快。
如果ES主机重启,则文件系统缓存将为空,此时搜索会比较慢。可以使用index.store.preload设置,通过指定文件扩展名,显式地告诉操作系统应该将哪些文件加载到内存中,
例如,配置到elasticsearch.yml文件中:index.store.preload: ["nvd", "dvd"]
在组合查询中可以通过bool过滤器进行and、or和not的多个逻辑组合检索,这种组合查询中的表达式在下面的情况下可以做等价转换:
(A|B) & (C|D) ==> (A&C) | (A&D) | (B&C) | (B&D )
默认情况下,ES会拒绝超过1000个分片的搜索请求。我们应该更好地组织数据,让搜索请求的分片数更少。如果想调节这个值,则可以通过action.search.shard_count配置项进行修改。

磁盘使用量优化

· _source:原始的JSON文档数据。
· _all:索引所有其他字段值的一种通用字段,这个字段中包含了所有其他字段的值。
索引参数
· index:控制字段值是否被索引。它可以设置为true或false,默认为true。
· doc values:默认情况下,大多数字段都被索引,这使得它们可以搜索。倒排索引根据term找到文档列表,然后获取文档原始内容。
· store:默认情况下,字段值会被索引使它们能搜索,但它们不会被存储(stored)。意味着可以通过这个字段查询,但不能取回它的原始值。
优化措施
所有支持doc value的字段都默认启用了doc value。如果确定不需要对字段进行排序或聚合,或者从脚本访问字段值,则可以禁用doc value以节省磁盘空间:
在这里插入图片描述
默认的动态字符串映射会把字符串类型的字段同时索引为 text 和 keyword。如果只需要其中之一,则显然是一种浪费。通常,id字段只需作为 keyword类型进行索引,而body字段只需作为text类型进行索引。
要禁用默认的动态字符串映射,则可以显式地指定字段类型,或者在动态模板中指定将字符串映射为text或keyword。下例将字符串字段映射为keyword:
在这里插入图片描述
较大的分片可以更有效地存储数据。为了增加分片大小,可以在创建索引的时候设置较少的主分片数量,或者使用shrink API来修改现有索引的主分片数量。但是较大的分片也有缺点,例如,较长的索引恢复时间。
_source 字段存储文档的原始内容。如果不需要访问它,则可以将其禁用。但是,需要访问_source的API将无法使用,至少包括下列情况:
· update、update_by_query、reindex;
· 高亮搜索;
· 重建索引(包括更新mapping、分词器,或者集群跨大版本升级可能会用到);
· 调试聚合查询功能,需要对比原始数据。
_source和设置为"store": true的字段占用磁盘空间都比较多。默认情况下,它们都是被压缩存储的。默认的压缩算法为LZ4,可以通过使用best_compression来执行压缩比更高的算法:DEFLATE。但这会占用更多的CPU资源。
PUT index{"settings": {"index": {"codec": "best_compression"}}}
一个ES索引由若干分片组成,一个分片有若干Lucene分段,较大的Lucene分段可以更有效地存储数据。
使用_forcemerge API来对分段执行合并操作,通常,我们将分段合并为一个单个的分段:max_num_segments=1。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值