Elasticsearch-优化
Elasticsearch 优化相关文档
How to
https://www.elastic.co/guide/en/elasticsearch/reference/7.17/how-to.html
检索性能调优
Elasticsearch Guide [7.17] » How to » Tune for search speed
https://www.elastic.co/guide/en/elasticsearch/reference/7.17/tune-for-search-speed.html
增加系统缓存
操作系统文件缓存/文件系统缓存/页缓存 Filesystem Cache/Page Cache
Elasticsearch 的搜索性能高度依赖操作系统的文件系统缓存,为了加快检索速度,要 保证至少一半可用内存用于系统缓存,以保证 Elasticsearch 可将热点索引放到物理内存中。
这也是为什么官方建议堆内存不要超过可用内存的一半。
In general, you should make sure that at least half the available memory goes to the filesystem cache so that Elasticsearch can keep hot regions of the index in physical memory.
Set the JVM heap size
https://www.elastic.co/docs/reference/elasticsearch/jvm-settings
Xms 和 Xmx 不超过 Elasticsearch 节点总可用内存的 50%
适度预读避免缓存抖动
预读(Readahead) 是操作系统为了优化磁盘读取性能而采用的一种策略。当应用程序需要读取磁盘上的某个数据块时,文件系统可能会“提前”将其后面相邻的若干数据块也一并加载到页面缓存(Page Cache)中。这种机制基于“局部性原理”,对顺序读写操作有很好的效果。
而 Elasticsearch 的搜索请求通常会产生大量的随机读取 I/O。这意味着系统需要从磁盘的不同位置快速读取大量小文件(如倒排索引、文档值等)。在这种情况下,一个过高的预读值会导致
- 不必要的 I/O 操作:系统预读了大量本次搜索根本不需要的数据,浪费了宝贵的 I/O 带宽。
- 页面缓存抖动(Page Cache Thrashing):这些被提前读取的、无用的数据挤占了页面缓存的空间,而这些空间本应留给真正的“热”数据(即频繁访问的索引数据)。这会导致缓存命中率下降,迫使系统更频繁地去磁盘查找数据,从而严重拖慢搜索(或更新)性能
一般来说,多数 Linux 发行版中单个设备的预读值都是 128KiB,较为合适。
问题出现在使用了软件 RAID、LVM 或 dm-crypt 等逻辑卷管理或加密技术的情况下。这些技术会创建一个虚拟的块设备,而 Linux 发行版有时会为这类设备设置一个非常大的预读值(可能达到几MiB)
lsblk -o NAME,RA,MOUNTPOINT,TYPE,SIZE 查看磁盘的预读值,结果中的 RA(Read-Ahead) 就是预读值,结果单位是 KiB(Kibibytes)
例如,下面几个设备的预读值都是 128KiB
# lsblk -o NAME,RA,MOUNTPOINT,TYPE,SIZE
NAME RA MOUNTPOINT TYPE SIZE
nvme0n1 128 disk 3.7T
├─nvme0n1p3 128 /data part 3.6T
├─nvme0n1p1 128 part 2M
└─nvme0n1p2 128 / part 93.1G
loop0 128 /mnt/cdrom loop 4.3G
使用更快的硬件
1、保证文件系统缓存足够
2、使用 SSD 磁盘
优化文档模型
避免 nested 嵌套字段,避免 join 关系字段。
nested 字段有几倍的性能损失,join 关系字段会带来几百倍的性能损失。
使用copy_to合并字段
将多个字段的内容 copy_to 到一个字段中,方便搜索
提前计算中间结果
比如经常需要对 price 字段进行聚合查询,聚合为 0-200,200-500,500+,可以在插入文档时就计算好这个聚合分类
使用keyword代替数字类型
ES 对 integer, long 等数字类型做了优化更适合 range 查询,但 keyword 类型适合 term 级别查询。
并不是所有的数字类型数据都要存储为数字类型(integer, long等),例如数字类型的 ISBN 号、产品ID等,很少会用做范围 range 查询,更多的是 term 查询,所以更适合保存为 keyword 类型。
避免脚本搜索
强制合并只读索引
将只读索引强制合并为单个 Segment 可加快查询。对于 log 等基于时间写入的索引尤其适用,只保留当天的日志可写,将之前的日志合并为一个索引。
预热全局序号
全局序号用于加速聚合查询,是 fielddata 缓存结构的一部分,位于 JVM 堆内存中,在查询时触发。
对于常用的聚合字段,告诉 ES 提前预热该字段的全局序号缓存,可加快聚合查询速度。
预热文件系统缓存
机器重启后操作系统文件缓存会丢失,随着查询请求才会逐渐将索引中的热区域加载到系统缓存中。
对于常用的索引,配置到 "index.store.preload": ["index1", "index2"],以便启动时自动预热数据
冷->热->缓存
冷数据:查询条件term的索引文件还未加载系统缓存,读磁盘
热数据:查询条件term的索引文件已加载到系统缓存,使用同条件查询一次后触发,读内存
缓存后:用完全相同的查询条件再次查询,结果是完全缓存在内存的
索引数据排序
Elasticsearch 从 6.0 版本开始引入了一个新的特征,叫 Index Sorting(索引排序)。用户可以将索引数据按照指定的顺序存储在硬盘上,这样在搜索排序取前 N 条时,不需要访问所有的匹配中的记录再进行排序,只需要访问前 N 条记录即可。
文档插入(索引)性能调优
Elasticsearch Guide [7.17] » How to » Tune for indexing speed
https://www.elastic.co/guide/en/elasticsearch/reference/7.17/tune-for-indexing-speed.html
使用批量操作API _bulk
_bulk 批量操作,批量插入、更新、删除文档
多线程并发插入
修改或关闭刷新间隔(refresh_interval)
index.refresh_interval
https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules.html#index-refresh-interval-setting
默认值 1 秒,可设为 -1 来禁用 refresh。
未显式设置时,分片在 index.search.idle.after 秒未收到 search 请求后会停止后台的定时 refresh 任务,直到再次收到 search 请求。这么做的目的是为了加快批量索引的速度。
refresh_interval 可以在既存索引上进行动态更新。
1、当正在建立一个大的新索引时,可以将刷新间隔临时调整为较大的值,创建完再调整为默认值。
注意:refresh_interval 需要一个 持续时间 值, 例如 1s (1 秒) 或 2m (2 分钟)。 一个绝对值 1 表示的是 1 毫秒。
PUT /index/_settings
{ "refresh_interval": "30s" } 30s自动刷新。
PUT /index/_settings
{ "refresh_interval": "1s" } 每秒自动刷新。
2、当正在建立一个大的新索引时,可以先关闭自动刷新,待开始使用该索引时,再把它们调回来:
PUT /index/_settings
{ "refresh_interval": -1 } 关闭自动刷新。
PUT /index/_settings
{ "refresh_interval": "1s" } 每秒自动刷新。
禁用副本
在做批量索引时,可以考虑把副本数 index.number_of_replicas 设置成0,因为document从主分片(primary shard)复制到从分片(replica shard)时,从分片也要执行相同的分析、索引和合并过程,这样的开销比较大,你可以在构建索引之后再开启副本,这样只需要把数据从主分片拷贝到从分片
curl -XPUT 'localhost:9200/my_index/_settings' -d ' {
"index" : {
"number_of_replicas" : 0
}
}'
禁用操作系统swap
Disable swapping
https://www.elastic.co/docs/deploy-manage/deploy/self-managed/setup-configuration-memory
避免 JVM 堆内存被操作系统 swap 到磁盘。
系统级临时关闭 swapsudo swapoff -a
开启 bootstrap.memory_lock
elasticsearch.yml 中配置:
bootstrap.memory_lock: true
GET /_nodes 结果看 mlockall 字段可确认是否生效
增加系统缓存
操作系统文件缓存/页缓存 filesystem cache/page cache
保证至少一半可用内存用于系统缓存
使用自动生成的文档id
如果指定 id 创建文档,es 需要先检查此 id 是否已存在,较为耗时。
使用SSD磁盘
增加索引buffer size
indices.memory.index_buffer_size
读写分离
Shard 分片调优
Size your shards
https://www.elastic.co/docs/deploy-manage/production-guidance/optimize-performance/size-shards
总体原则:
- 单个 shard 大小控制在 10GB 到 50GB 之间
- 单个 shard 文档数小于 2亿
kNN 近似搜索调优
Tune approximate kNN search
https://www.elastic.co/guide/en/elasticsearch/reference/8.19/tune-knn-search.html
向量量化存储
float 类型 dense_vector 向量支持量化存储
- 优点:减少内存占用、加快 kNN 检索速度
- 缺点:降低 kNN 检索精度,增加磁盘占用(同时存储 float 向量 和 量化向量)
对于维度大于 384 的 float 向量,强烈建议开启量化
降低向量维度
kNN 检索速度与向量维度线性相关。
多数 Embedding 向量模型都支持输出不同维度的向量。
在精度下降可接受的情况下,尽可能选择维度更低的向量
此外还可以使用 主成分分析 PCA(Principal Component Analysis) 等降维技术降低向量维度。
禁止向量字段存储和检索返回
_source 字段中会存储原始高维向量,数据量很大。
- 从检索结果排除向量字段:如果检索返回数据包含高维向量会导致数据量过大、降低 kNN 检索速度。
- 关闭
dense_vector向量字段在_source中的存储:mappings 配置中,支持从_source中排除指定字段。不影响 kNN 向量检索。
增加系统缓存
Elasticsearch 使用 HNSW 算法进行 kNN 搜索。
HNSW 是一个基于图的算法,只有当向量数据都在内存中时,HNSW 才能实现高效搜索。
HNSW 图需要的内存大小估算:num_vectors * 4 * HNSW.m,默认 HNSW.m 是 16
这里说的内存,和文档插入、检索调优中一样,指的也是操作系统文件缓存,不是 JVM 堆内存。
预热系统缓存
机器重启后 文件系统缓存(filesystem cache) 会被清空,操作系统需要一些时间才能将热点区域加载到系统缓存。
向量相关的 index.store.preload 配置:
vexHNSW 图的结构信息,用于高效导航向量空间。强烈建议预加载。对 kNN 搜索性能至关重要。vec所有未量化的原始向量值(如 float 类型)。若使用量化,则无需预加载。避免为已量化的索引浪费内存。veq经过量化的向量值(如int4, int8)。若使用量化索引,应预加载。这是量化后搜索实际使用的数据。veb二值向量(binary vectors)经过量化(如BBQ)后的数据。若使用二值向量量化,应预加载。
如果使用量化索引,应预加载 "index.store.preload": ["vex", "veq"]
如果未使用量化,只需预加载 "index.store.preload": ["vex"]
上一篇 Java-线程与线程池
页面信息
location:protocol: host: hostname: origin: pathname: href: document:referrer: navigator:platform: userAgent: