Elasticsearch - 常见的优化策略详解(索引合并、分片副本数调整、JVM、swap)
作者:hangge | 2025-05-20 08:41
1,Too many open files 的问题
(1)ES 中的索引数据都是存储在磁盘文件中的,每一条数据在底层都会产生一份索引片段文件。这些索引数据默认的存储目录是在 ES 安装目录下的 data 目录里面。
- 其中路径的 0DZ2Lm20RG6FyMPdjx3S5w 表示是索引库的 UUID。

(2)ES 在查询索引库里面数据的时候需要读取所有的索引片段,如果索引库中数据量比较多,那么 ES 在查询的时候就需要读取很多索引片段文件,此时可能就会达到 Linux 系统的极限,因为 Linux 会限制系统内最大文件打开数。
- 这个最大文件打开数的的配置在安装 ES 集群的时候我们已经修改过了,主要是 /etc/security/limits.conf 文件中如下这些参数:
* soft nofile 65536 * hard nofile 131072 * soft nproc 2048 * hard nproc 4096
(3)理论上来说,不管我们将最大文件打开数修改为多大,在使用的时候都有可能会出问题,因为 ES 中的数据是越来越多的,那如何解决?
- 其实也不用过于担心,因为 ES 中默认会有一个自动的索引片段合并机制,这样可以保证 ES 中不会产生过多的索引片段。
- 只要是单个索引片段文件小于 5G 的,在自动索引片段合并机制触发的时候都会进行合并。
2,索引合并优化,清除标记为删除状态的索引数据
(1)Elasticsearch 中的删除并不是真正的删除,只是会给数据标记一个删除状态,索引片段在合并的时候,是会把索引片段中标记为删除的数据真正删掉,这样也是可以提高性能的,因为标记为删除状态的数据是会参与查询的,只不过会被过滤掉。
- 索引片段合并除了可以避免产生 Too many open files 这个问题,其实它也是可以显著提升查询性能的,因为我们读取一个中等大小的文件肯定是比读取很多个小文件效率更高的
(2)除了等待自动的索引片段合并,也可以手工执行索引片段合并操作。
注意:索引片段合并操作是比较消耗系统 IO 资源的,不要在业务高峰期执行,也没必要频繁调用,可以每天凌晨执行一次。
curl -XPOST 'http://192.168.121.128:9200/log_20260322/_forcemerge'
(3)如果一个索引库中的数据已经非常多了,手工执行索引片段合并操作可能会产生一些非常大的索引片段(超过 5G 的),如果继续向这个索引库里面写入新的数据,那么 ES 的自动索引片段合并机制就不会再考虑这些非常大的索引片段了(超过 5G 的),这样会导致索引库中保留了非常大的索引片段,从而降低搜索性能。
- 这种问题该如何解决呢?往下面继续看!
3,分片和副本个数调整
(1)分片数过少或过多,都会降低检索效率。单个索引库,建议使用 5-20 个分片比较合适。
- 分片数过多会导致检索时打开比较多的文件,另外也会导致多台服务器之间的通讯。
- 而分片数过少会导致单个分片索引过大,所以检索速度也会慢。
(2)建议单个分片存储 20G 左右的索引数据,最高也不要超过 50G,否则性能会很差。
- 所以,大致有一个公式:分片数量=数据总量/20G
(3)当数据规模超过单个索引库最大存储能力的时候,只需要新建一个索引库即可,所以 ES 中的海量数据存储能力是需要依靠多个索引库的,这样就可以解决前面所说的索引库中单个索引片段过大的问题。
(4)副本多的话,理论上来说可以提升检索的能力,但是如果设置很多副本的话也会对服务器造成额外的压力,因为主分片需要给所有副本分片同步数据,所以建议最多设置 1-2 个副本即可。
注意:从 ES7.x 版本开始,集群中每个节点默认支持最多 1000 个分片,这块主要是考虑到单个节点的性能问题,如果集群内每个节点的性能都比较强,当然也是支持修改的。
curl -XGET 'http://192.168.121.128:9200/_cluster/settings?pretty'
- 接着修改节点支持的最大分片数量:
curl -H "Content-Type: application/json" \
-XPUT "http://192.168.121.128:9200/_cluster/settings" \
-d '{
"persistent": {
"cluster.max_shards_per_node": "10000"
}
}'
- 重新查询集群最新的参数配置:
4,初始化数据时,建议将副本数设置为 0
(1)如果是在项目初期,ES 集群刚安装好,需要向里面批量初始化大量数据,此时建议将副本数设置为 0,这样是可以显著提高入库效率的。
(2)如果有副本的话,在批量初始化数据的同时,索引库的主分片还需要负责向副本分片同步数据,这样会影响数据的入库性能。
5,close 不使用的索引库
针对不使用的 index,建议 close,减少性能损耗。具体的操作方式可以参考我之前写的文章:
6,调整 ES 的 JVM 内存大小,单个 ES 实例最大不超过 32G
(1)单个 ES 实例官方建议最大使用 32G 内存,如果超过这个内存 ES 也使用不了,这样会造成资源浪费。
- 所以在前期申请 ES 集群机器的时候,建议单机内存在 32G 左右即可。
(2)如果由于历史遗留问题导致每台机器的内存都很大,假设是 128G 的,如果在这台机器上只部署一个 ES 实例,会造成内存资源浪费,此时有一种取巧的方式,在同一台机器上部署多个 ES 实例,只需要让这台机器中的每个 ES 实例监听不同的端口就行了。
- 这样这个 128G 内存的机器理论上至少可以部署 4 个 ES 实例。
- 但是这样会存在一个弊端,如果后期这台机器出现了故障,那么 ES 集群会同时丢失 4 个节点,可能会丢数据,所以还是尽量避免这种情况。
7,优化 swap
(1)在现代操作系统中,基本都支持交换区,也叫做 swap 分区。当操作系统发现可用的物理内存不足的时候,就会把物理内存里的一部分页淘汰出来,放到磁盘上,也就是放到 swap 分区。
提示:我们可以把 swap 分区看作是“虚拟内存”。可以想到,如果触发了这种交换,性能就会显著下降。交换越频繁,下降越快

(3)Elasticsearch 也是一个内存依赖非常严重的中间件,在触发了 swap 的时候,性能下降得很快。对此,我们有两种做法:
- 第一种做法是在操作系统层面上直接禁用了 swap,或者把 vm.swappness 设置成一个非常小的值。比如说 Kafka 等中间件也都可以采用这种优化手段。
- 第二种做法是在 Elasticsearch 里把 bootstrap.memory_lock 设置成 true。
全部评论(0)