天元突破-ElasticSearch性能究极进化

前言

ElasticSearch系列的完结篇,本篇会尽可能地罗列出性能优化的手段,给出我自己的点评。以官方推荐优化为主,个人常用手段为辅,部分配置因篇幅和时间不会有实战数据对比,仅列出配置说明参考。从我个人实践而言,ElasticSearch本身的优化已经很好了,做好推荐的系统配置后,其实其他软配置大部分效果不会质变,真正质变的是加ElasticSearch的内存,所以终极大招只有一个,加资源。除此之外,给ElasticSearch集群中的各个节点划分职责明确的角色也是很重要的优化手段。文中提到的理论和面试知识点请看ElasticSearch理论体系构建,基础操作和一般场景的设计请看ElasticSearch开发指北和场景题分析,结合以上两篇再看本篇体验更佳。

硬件及系统配置优化

常规推荐

ElasticSearch官方推荐生产系统配置,关于系统配置这块真的没啥好操作的,你在网上其他地方看到的性能优化文章大部分都是官方文档的翻译,那为什么不直接看官方文档呢,是吧。系统配置这方面只要是用于生产环境,严格按照官方指示的去做就行了,不要怀疑。

除此之外,还有一些值得说的系统配置可以调整。

  1. ElasticSearch最好单独部署,并且机器内存32G以上,JVM堆内存配置可用内存的一半最好。除非数据量很少,否则堆内存至少8G,太少会导致各种各样的奇怪问题,详见我之前的实战文章。过小的堆内存可能导致频繁的GC操作,而过大的堆内存可能导致长时间的GC暂停,影响性能。垃圾回收器可按需选择,
  2. Elasticsearch是一个CPU密集型的应用程序,因此建议使用高性能的多核CPU。较高的CPU频率和较多的核心数可以提高搜索和聚合操作的性能。
  3. 硬盘就是能用固态用固态,现在固态价格也被国产打下来了,这对比机械硬盘优势可太大了。

filesystem cache(文件系统缓存)

你往 ElasticSearch 里写的数据,实际上都写到磁盘文件里去了,查询的时候,操作系统会将磁盘文件里的数据自动缓存到 filesystem cache 里面去。es 的搜索引擎严重依赖于底层的 filesystem cache,官方推荐至少将一半可用内存提供给filesystem cache。

这里需要注意的是,文件系统缓存是由操作系统管理的,Elasticsearch 无法直接控制其内部行为。因此,优化文件系统缓存需要在操作系统级别上进行调整和优化,如果只是普通的应用,直接加内存就行了,别调参。

索引及映射配置优化

索引类比于常规关系型数据库的表,但不同于MySQL的表配置那样没啥可操作的,分布式架构下的ElasticSearch索引提供了丰富的配置,能相当大程度的进行性能上的优化。以下是一个待写入大量数据的索引极限配置,接下来会对各个参数进行讲解。www.elastic.co/guide/en/el...,官方对于提升索引速度也有一个推荐配置,但是不太全面也比较简略,建议还是看我写的比较好。对了,先叠个甲,以下所有我推荐的配置均需按照你自己的机器配置进行调整,最好配合监控,比如Kibana、Prometheus。

json 复制代码
{
  "settings": {
    "number_of_shards": n,//分片尽量设置多一些,能提高加载速度
    "number_of_replicas": 0,//副本设置为0,丧失数据安全性
    "refresh_interval": "-1",//刷新时间设置为-1,丧失数据实时性
    "translog.durability": "async",//异步
    "translog.flush_threshold_size": "2gb",//这个参数表示在当未提交的translog日志达到该阈值的时候进行一次刷盘操作。
    "translog.sync_interval": "100s"
  },
  "mappings": {
    "_doc": {
      "properties": {
        "name": {
          "type": "keyword",
          "doc_values":false, //不存储doc,丧失聚合排序等功能
          "index":false  //不索引,丧失查询功能
        }
      }
    }
  }
}

www.elastic.co/guide/en/el...,官方的索引模块配置在这里。但对于我们开发者来说,做性能优化只用关注我上面提到的这些,其他的参数并不太影响最后的性能,触发了边际效应性价比不高。

索引分片配置

www.elastic.co/guide/en/el...,官方列举了一大堆,反正结论是看你机器配置,我会结合我自己的经验进行讲解以供参考。number_of_shards,分片数量在3-50个最佳,单个分片在2亿数据量以下,大小在50G以内最好,受到索引数据量、删改操作频繁程度和机器硬件影响。

  1. 索引数据量不大的话,其实一小组大分片会比一大组小分片消耗更少的资源,其中性能的差距也不会很明显,但资源的消耗明显。
  2. 增删改操作如果很频繁,会涉及到分片的重新分配和数据迁移,这会引入额外的开销和延迟,一小组大分片的性能会更好。
  3. 如果机器配置比较好的话,一个节点上可以分配多个分片,多个分片会一定程度上提升性能。

索引副本配置

number_of_replicas,副本的选择一般是按你机器配置和使用场景来配置,如果是不太重要的数据或者有别的持久化手段,副本数1就行了。通常会受到如下几个方面的影响:

  1. 读写场景分析,副本数量与读取速度成正相关,与写入速度成反相关。可以把副本当作从库理解,越多副本读取的速度越快,但是写入时更多的副本会带来更多的写入开销和延迟。
  2. 增删改操作频繁的情况下,不适合有过多的部分,会严重影响操作速度。比如上面这个写入性能优化的极端例子,将副本数量暂时设置为0,会极大地提高写入速度,但是因为副本数是动态字段,可以随时调整,大量写入完成后,改成正常地副本数即可,ES会自动创建副本。

索引刷新间隔调整

refresh_interval,索引刷新是将内存中的文档写入磁盘并使其可搜索的过程。这个默认是每秒进行刷新,这也是ElasticSearch是近实时的原因,当然我觉得这对于搜索引擎来说足够了,我自己做的日志收集系统,一般是设置5s。

增加刷新间隔可以减少磁盘写入的频率,减少对磁盘的负载,提高写入性能。较长的刷新间隔可以将多个文档的写入操作合并为一个较大的批量写入操作,减少写入操作的开销。上面这个极端的例子中直接设置为"-1",也就是不刷新数据,这是正式上面不能用的,意味着你新写入的数据是不能被搜索到的,但是无刷新会带来一定程度上的写入性能提升。

综上所述,我们在调整刷新间隔时需要平衡数据可用性和写入性能之间的需求,根据自己的业务场景进行调整。

事务日志配置优化

Elasticsearch的translog(事务日志)是用于持久化未刷新到磁盘的索引操作的机制。

  • "index.translog.durability",Elasticsearch提供了两种translog持久化策略:request(默认)和async。request策略在每次写入操作后都会调用fsync,将数据持久化到磁盘,提供更高的数据可靠性,但会引入较高的写入延迟。async策略将数据异步地写入磁盘,提供更高的写入性能,但在发生故障时可能会丢失一部分数据。
  • "index.translog.sync_interval", Translog 多长时间同步到磁盘并提交一次。默认为 5s ,不允许小于 100ms 的值。增加刷新间隔可以减少磁盘写入的频率,从而提高写入性能。然而,较长的刷新间隔会增加数据丢失的风险。
  • "index.translog.flush_threshold_size",默认为512MB。当translog的大小达到阈值时,会触发translog刷新操作。增加translog的大小可以减少translog刷新的频率,提高写入性能。然而,较大的translog会占用更多的磁盘空间,并且在发生故障时可能会丢失更多的数据。

translog是Elasticsearch重要的持久化机制,因此如果我们能容忍部分数据丢失,那就可以进行调整优化写入性能。

映射配置优化

Elasticsearch默认提供动态映射和显式映射两种配置方式。当我们不知道具体数据格式,可以直接将数据写入索引,Elasticsearch会自动创建映射配置来适配。当然最好还是通过显式映射进行配置,得到最好的性能效果。

  1. 选择合适且尽量准确的数据类型,避免不必要的类型转换开销。数据类型选择时要尽量精简,比如String类型,能用keyword就不要用text。
  2. mapping允许为字段定义各种特性,如索引、存储、排序、分词等。禁用不需要的字段特性可以减少索引和查询的开销。

映射这块很重要,配置的时候直接影响索引的大小和速度。补充一下,如果是不常用的字段,可以考虑用运行时字段。

ElasticSearch.yml优化

这个我觉得有必要在安装的时候就做好配置,不像索引修改那么方便了,而且这些配置还挺重要的。

索引缓冲区配置

makefile 复制代码
indices.memory.index_buffer_size: 10%
设置百分比 or 字节大小值。默认为10%,意味着10%分配给节点的总堆将用作所有分片共享的索引缓冲区大小。
indices.memory.min_index_buffer_size: 48m
如果index_buffer_size设置为百分比,则可以使用此设置指定最小值。默认为48mb。
indices.memory.max_index_buffer_size
如果index_buffer_size设置为百分比,则可以使用此设置指定最大值。默认为无限制。

www.elastic.co/guide/en/el...,已经索引好的文档会先存放在内存缓存中,等待被写到到段(segment)中。缓存满的时候会触发段刷盘(吃i/o和cpu的操作)。这个索引缓冲区有点类似于MySQL的Buffer Pool,给的越多查询和聚合分析能力越强,这个值一般设置30%或者多一些都可以,这个百分比是设置的Java堆内存百分比。

设置index、merge、bulk、search的线程数和队列数

www.elastic.co/guide/en/el...,网上其他博客写的线程池数量修改都过时了,新版的参数都是随运行时核数进行调整,而且合理了很多,如无必要,无需修改。

设置FieldDataCache大小

www.elastic.co/guide/en/el...,Elasticsearch 的 fielddata 缓存用于存储字段数据的加载和分析结果,以便在查询过程中快速访问。它主要用于支持聚合、排序、脚本计算等需要对字段进行分析和计算的操作。

设置节点之间的故障检测配置

www.elastic.co/guide/en/el...,官方配置还是太保守了,生产时候不调大点,真的很容易报错和丢节点。

arduino 复制代码
discovery.zen.ping_timeout: 60s      //超时时间,默认3s
discovery.zen.fd.ping_interval: 30s    //节点多久ping一次master,默认1s
discovery.zen.fd.ping_timeout: 60s    //等待响应时间,默认30s
discovery.zen.fd.ping_retries: 6       //失败或超时后重试的次数,默认3

场景方案专项优化

设计阶段调优

  1. 基于数据+时间滚动创建索引,每天递增数据。控制单个索引的量,一旦单个索引很大,存储等各种风险也随之而来,所以要提前考虑及早避免。
  2. 使用别名进行索引管理,方便索引变更之类的切换。
  3. 每天凌晨定时对索引做force_merge操作,以释放空间。
  4. 采取冷热分离机制,热数据存储到SSD,提高检索效率。冷数据定期进行转移到数据库备份,以缩减存储。
  5. 索引和映射配置能优化的进行优化。

写入调优

www.elastic.co/guide/en/el...,以下是我参考官方文档结合自己实践所得。

  1. 写入前副本数设置为0,写入前关闭refresh_interval设置为-1,禁用刷新机制,写入后恢复副本数和刷新间隔。
  2. 写入时采取多线程以及Bulk API批量写入,但也要注意单次写入数据大小不能过大。
  3. 文档ID采用自动生成,Elasticsearch对自动生成的ID有优化,避免了版本查找带来的检查开销。

按照上面的索引和硬件配置进行优化.......

查询调优

www.elastic.co/guide/en/el...,以下是我参考官方文档结合自己实践所得。

  1. 需要大量拉取数据的场景,可以采用search_after 或者 scroll api来实现,而不是from/size一个大范围。
  2. 充分利用文件系统缓存,做一个预热子系统,对热数据定时访问,刷入到缓存。

按照上面的索引和硬件配置进行优化.......

分页性能优化

关于分页的优化,Elasticsearch目前提供了三种,from + size、scroll和search_after。在小分页,也就是未筛选的查询结果集不超过1W条(Elasticsearch默认只让查1W,但是可配置index.max_result_window)的情况下,用普通的from + size即可。from + size在深度分页场景下,性能差的原因是查询时会创建一个 from+size 的空优先队列,每个分片会返回 from+size 条数据,默认只包含文档 ID 和得分 Score 给协调节点。 如果有 N 个分片,则协调节点再对(from+size)×n 条数据进行二次排序,然后选择需要被取回的文档。当 from 很大时,排序过程会变得很沉重,占用 CPU 资源严重。

Elasticsearch7之前大家一般用scroll也就是滚动查询来解决这个问题,但从7.*版本开始官方不再推荐使用Scroll方法来进行深分页,而是推荐使用带PIT的search_after来进行查询,参见官网www.elastic.co/guide/en/el...。使用方面见仁见智吧,个人总结如下,按需使用。

分页方式 性能 优点 缺点 场景
from + size 灵活性好,实现简单 深度分页问题,官方不推荐查询超过1W条数据 数据量比较小,能容忍深度分页问题
scroll 解决了深度分页问题 无法反应数据的实时性(快照版本)维护成本高,需要维护一个 scroll_id 快照读最友好的场景肯定是导出啦
search_after 性能最好,能够反映数据的实时变更 实现复杂,需要有一个全局唯一的字段连续分页的实现会比较复杂,因为每一次查询都需要上次查询的结果,它不适用于大幅度跳页查询 海量数据的分页

外链好文

消息积压问题难?思路代码优化细节全公开

消息积压问题难?思路代码优化细节全公开--2988阅读64赞104收藏

这一篇和本篇相关联的地方在于验证了我前言所说的,给Elasticsearch集群节点划分具体的角色会一定程度上影响整个集群的性能。除此之外,里面也有几个Elasticsearch实战时遇到问题的解决方法,总的来说值得一看。

ElasticSearch不停机重建索引引申来的优化与思考

ElasticSearch不停机重建索引引申来的优化与思考--5175阅读29点赞44收藏,本篇的阅读数超乎我预料的高,让我有点没想到。从我个人写文的出发点来看,本篇并不属于我推崇的体系文章,算是纯纯的实战文章,有大量的问题和详细的操作步骤,和本篇的性能一说有那么点关系,感兴趣的可以看看。

写在最后

本周依旧是加班忙碌的,周末写上一篇的时候,其实原意是合到一块,但是考虑到本文的体量,还是决定拆开。Elasticsearch的开放程度真是超乎想象,我用过很多中间件,像这么能定制化的还是少见,本文也是尽可能详尽地介绍了常见的优化手段,希望能对大家有所帮助。我个人的应用场景是日志收集分析,所以其他场景没有涉及就不多言,避免误人子弟。最近更新频率变高,算是陷入学习狂热阶段,本来打算国庆出去玩,想想还是算了,回家休息放松一下,学习充充电得了。年关将至,尽量存点钱吧,开源节流,大家加油!

相关推荐
devlei7 小时前
从源码泄露看AI Agent未来:深度对比Claude Code原生实现与OpenClaw开源方案
android·前端·后端
慕诗客8 小时前
repo管理多仓库
大数据·elasticsearch·搜索引擎
Accerlator9 小时前
2026 年 4 月 1 日电话面试
面试·职场和发展
努力的小郑9 小时前
Canal 不难,难的是用好:从接入到治理
后端·mysql·性能优化
Victor35610 小时前
MongoDB(87)如何使用GridFS?
后端
Victor35610 小时前
MongoDB(88)如何进行数据迁移?
后端
小红的布丁10 小时前
单线程 Redis 的高性能之道
redis·后端
GetcharZp10 小时前
Go 语言只能写后端?这款 2D 游戏引擎刷新你的认知!
后端
宁瑶琴12 小时前
COBOL语言的云计算
开发语言·后端·golang
普通网友12 小时前
阿里云国际版服务器,真的是学生党的性价比之选吗?
后端·python·阿里云·flask·云计算