草庐IT

ElasticSearch性能优化

杰锋 2023-11-11 原文

硬件选择

Elasticsearch 的基础是 Lucene,所有的索引和文档数据是存储在本地的磁盘中,具体的 路径可在 ES 的配置文件../config/elasticsearch.yml 中配置。磁盘在现代服务器上通常都是瓶颈。Elasticsearch 重度使用磁盘,你的磁盘能处理的吞吐量 越大,你的节点就越稳定。

1、使用 SSD。就像其他地方提过的, 他们比机械磁盘优秀多了。

2、使用 RAID 0。条带化 RAID 会提高磁盘 I/O,代价显然就是当一块硬盘故障时整个就故障了。不要 使用镜像或者奇偶校验 RAID 因为副本已经提供了这个功能。

3、另外,使用多块硬盘,并允许 Elasticsearch 通过多个 path.data 目录配置把数据条带化分配到它们上 面。

4、不要使用远程挂载的存储,比如 NFS 或者 SMB/CIFS。这个引入的延迟对性能来说完全是背道而驰 的。

分片策略

一、合理设置分片数

1、控制每个分片占用的硬盘容量不超过 ES 的最大 JVM 的堆空间设置(一般设置不超过 32G),因此,如果索引的总容量在 500G 左右,那分片大小在 16 个左右即可;当然, 最好同时考虑原则 2。

2、考虑一下 node 数量,一般一个节点有时候就是一台物理机,如果分片数过多,大大超过了节点数, 很可能会导致一个节点上存在多个分片,一旦该节点故障,即使保持了 1 个以上的副本,同样有可能 会导致数据丢失,集群无法恢复。所以, 一般都设置分片数不超过节点数的 3 倍。

3、主分片,副本和节点最大数之间数量,我们分配的时候可以参考以下关系:节点数<=主分片数*(副本数+1)

二、推迟分片分配

        对于节点瞬时中断的问题,默认情况,集群会等待一分钟来查看节点是否会重新加入, 如果这个节点在此期间重新加入,重新加入的节点会保持其现有的分片数据,不会触发新的 分片分配。这样就可以减少 ES 在自动再平衡可用分片时所带来的极大开销。

        通过修改参数 delayed_timeout ,可以延长再均衡的时间,可以全局设置也可以在索引 级别进行修改:

PUT /_all/_settings 
{
 "settings": {
 "index.unassigned.node_left.delayed_timeout": "5m" 
 }
}

路由选择

        通过下面这个公式来计算文档应该存放到哪个分片中:

shard = hash(routing) % number_of_primary_shards

        查询的时候,可以直接根据 routing 信息定位到某个分配查询,不需要查询所有的分配,经 过协调节点排序。

        向上面自定义的用户查询,如果 routing 设置为 userid 的话,就可以直接查询出数据来, 效率提升很多。

写入速度优化

一、批量数据提交

        ES 提供了 Bulk API 支持批量操作,当我们有大量的写任务时,可以使用 Bulk 来进 行批量写入。

        通用的策略如下:Bulk 默认设置批量提交的数据量不能超过 100M。数据条数一般是 根据文档的大小和服务器性能而定的,但是单次批处理的数据大小应从 5MB~15MB 逐渐 增加,当性能没有提升时,把这个数据量作为最大值。

二、优化存储设备

        ES 是一种密集使用磁盘的应用,在段合并的时候会频繁操作磁盘,所以对磁盘要求较 高,当磁盘速度提升之后,集群的整体性能会大幅度提高。

三、合理使用合并

        Lucene 以段的形式存储数据。当有新的数据写入索引时,Lucene 就会自动创建一个新 的段。

        随着数据量的变化,段的数量会越来越多,消耗的多文件句柄数及 CPU 就越多,查询 效率就会下降。

        由于 Lucene 段合并的计算量庞大,会消耗大量的 I/O,所以 ES 默认采用较保守的策 略,让后台定期进行段合并。

四、减少 Refresh 的次数

        Lucene 在新增数据时,采用了延迟写入的策略,默认情况下索引的 refresh_interval 为 1 秒。

        Lucene 将待写入的数据先写到内存中,超过 1 秒(默认)时就会触发一次 Refresh, 然后 Refresh 会把内存中的的数据刷新到操作系统的文件缓存系统中。

        如果我们对搜索的实效性要求不高,可以将 Refresh 周期延长,例如 30 秒。

        这样还可以有效地减少段刷新次数,但这同时意味着需要消耗更多的 Heap 内存。

五、加大 Flush 设置

        Flush 的主要目的是把文件缓存系统中的段持久化到硬盘,当 Translog 的数据量达到 512MB 或者 30 分钟时,会触发一次 Flush。

        index.translog.flush_threshold_size 参数的默认值是 512MB,我们进行修改。

        增加参数值意味着文件缓存系统中可能需要存储更多的数据,所以我们需要为操作系统 的文件缓存系统留下足够的空间。

六、减少副本的数量

        ES 为了保证集群的可用性,提供了 Replicas(副本)支持,然而每个副本也会执行分 析、索引及可能的合并过程,所以 Replicas 的数量会严重影响写索引的效率。

        当写索引时,需要把写入的数据都同步到副本节点,副本节点越多,写索引的效率就越 慢。

        如 果 我 们 需 要 大 批 量 进 行 写 入 操 作 , 可 以 先 禁 止 Replica 复 制 , 设 置 index.number_of_replicas: 0 关闭副本。在写入完成后,Replica 修改回正常的状态。

内存设置

        ES 默认安装后设置的内存是 1GB,对于任何一个现实业务来说,这个设置都太小了。可在jvm.option 文件设置ES 的堆大小,Xms 表示堆的初始大小,Xmx 表示可分配的最大内存。

        确保 Xmx 和 Xms 的大小是相同的,其目的是为了能够在 Java 垃圾回收机制清理完 堆区后不需要重新分隔计算堆区的大小而浪费资源,可以减轻伸缩堆大小带来的压力。

        因为 ES 堆内存的分配需要满足以下两个原则:

* 不要超过物理内存的 50%:Lucene 的设计目的是把底层 OS 里的数据缓存到内存中。

* 堆内存的大小最好不要超过 32GB:在 Java 中,所有对象都分配在堆上,然后有一个 Klass Pointer 指 针指向它的类元数据。

        假设你有个机器有 128 GB 的内存,你可以创建两个节点,每个节点内存分配不超过 32 GB。 也就是说 不超过 64 GB 内存给 ES 的堆内存,剩下的超过 64 GB 的内存给 Lucene

重要配置

参数名参数值说明
cluster.nameelasticsearch配置 ES 的集群名称,默认值是 ES,建议改成与所存数据相关的名称,ES 会自动发现在同一网段下的 集群名称相同的节点
node.namenode-1集群中的节点名,在同一个集群中不能重复。节点 的名称一旦设置,就不能再改变了。当然,也可以 设 置 成 服 务 器 的 主 机 名 称 , 例 如 node.name:${HOSTNAME}。
node.mastertrue指定该节点是否有资格被选举成为 Master 节点,默 认是 True,如果被设置为 True,则只是有资格成为 Master 节点,具体能否成为 Master 节点,需要通 过选举产生。
node.datatrue指定该节点是否存储索引数据,默认为 True。数据 的增、删、改、查都是在 Data 节点完成的。
index.number_of_shards1设置都索引分片个数,默认是 1 片。也可以在创建 索引时设置该值,具体设置为多大都值要根据数据 量的大小来定。如果数据量不大,则设置成 1 时效 率最高
index.number_of_replicas1设置默认的索引副本个数,默认为 1 个。副本数越 多,集群的可用性越好,但是写索引时需要同步的 数据越多。
transport.tcp.compresstrue设置在节点间传输数据时是否压缩,默认为 False, 不压缩
discovery.zen.minimum_master_nodes1设置在选举 Master 节点时需要参与的最少的候选 主节点数,默认为 1。如果使用默认值,则当网络 不稳定时有可能会出现脑裂。 合理的数值为 (master_eligible_nodes/2)+1 ,其中 master_eligible_nodes 表示集群中的候选主节点数
discovery.zen.ping.timeout3s设置在集群中自动发现其他节点时 Ping 连接的超 时时间,默认为 3 秒。 在较差的网络环境下需要设置得大一点,防止因误 判该节点的存活状态而导致分片的转移

有关ElasticSearch性能优化的更多相关文章

  1. Ruby 的数字方法性能 - 2

    我正在使用Ruby解决一些ProjectEuler问题,特别是这里我要讨论的问题25(Fibonacci数列中包含1000位数字的第一项的索引是多少?)。起初,我使用的是Ruby2.2.3,我将问题编码为:number=3a=1b=2whileb.to_s.length但后来我发现2.4.2版本有一个名为digits的方法,这正是我需要的。我转换为代码:whileb.digits.length当我比较这两种方法时,digits慢得多。时间./025/problem025.rb0.13s用户0.02s系统80%cpu0.190总计./025/problem025.rb2.19s用户0.0

  2. ruby - Ruby 性能中的计时器 - 2

    我正在寻找一个用ruby​​演示计时器的在线示例,并发现了下面的代码。它按预期工作,但这个简单的程序使用30Mo内存(如Windows任务管理器中所示)和太多CPU有意义吗?非常感谢deftime_blockstart_time=Time.nowThread.new{yield}Time.now-start_timeenddefrepeat_every(seconds)whiletruedotime_spent=time_block{yield}#Tohandle-vesleepinteravalsleep(seconds-time_spent)iftime_spent

  3. ruby-on-rails - 如果条件与 &&,是否有任何性能提升 - 2

    如果用户是所有者,我有一个条件来检查说删除和文章。delete_articleifuser.owner?另一种方式是user.owner?&&delete_article选择它有什么好处还是它只是一种写作风格 最佳答案 性能不太可能成为该声明的问题。第一个要好得多-它更容易阅读。您future的自己和其他将开始编写代码的人会为此感谢您。 关于ruby-on-rails-如果条件与&&,是否有任何性能提升,我们在StackOverflow上找到一个类似的问题:

  4. ruby - Rails Elasticsearch 聚合 - 2

    不知何故,我似乎无法获得包含我的聚合的响应...使用curl它按预期工作:HBZUMB01$curl-XPOST"http://localhost:9200/contents/_search"-d'{"size":0,"aggs":{"sport_count":{"value_count":{"field":"dwid"}}}}'我收到回复:{"took":4,"timed_out":false,"_shards":{"total":5,"successful":5,"failed":0},"hits":{"total":90,"max_score":0.0,"hits":[]},"a

  5. ruby - 如何找到我的 Ruby 应用程序中的性能瓶颈? - 2

    我编写了一个Ruby应用程序,它可以解析来自不同格式html、xml和csv文件的源中的大量数据。我如何找出代码的哪些区域花费的时间最长?有没有关于如何提高Ruby应用程序性能的好资源?或者您是否有任何始终遵循的性能编码标准?例如,你总是用加入你的字符串吗?output=String.newoutput或者你会使用output="#{part_one}#{part_two}\n" 最佳答案 好吧,有一些众所周知的做法,例如字符串连接比“#{value}”慢得多,但是为了找出您的脚本在哪里消耗了大部分时间或比所需时间更多,您需要进行分

  6. elasticsearch源码关于TransportSearchAction【阶段三】 - 2

    1.回顾.TransportServicepublicclassTransportServiceextendsAbstractLifecycleComponentTransportService:方法:1publicfinalTextendsTransportResponse>voidsendRequest(finalTransport.Connectionconnection,finalStringaction,finalTransportRequestrequest,finalTransportRequestOptionsoptions,TransportResponseHandlerT>

  7. STM32的HAL和LL库区别和性能对比 - 2

    LL库和HAL库简介LL:Low-Layer,底层库HAL:HardwareAbstractionLayer,硬件抽象层库LL库和hal库对比,很精简,这实际上是一个精简的库。LL库的配置选择如下:在STM32CUBEMX中,点击菜单的“ProjectManager”–>“AdvancedSettings”,在下面的界面中选择“AdvancedSettings”,然后在每个模块后面选择使用的库总结:1、如果使用的MCU是小容量的,那么STM32CubeLL将是最佳选择;2、如果结合可移植性和优化,使用STM32CubeHAL并使用特定的优化实现替换一些调用,可保持最大的可移植性。另外HAL和L

  8. ruby - GC.disable 的任何性能缺点? - 2

    是否存在GC.disable会降低性能的情况?只要我使用的是真正的RAM而不是交换内存,就可以这样做吗?我正在使用MRIRuby2.0,据我所知,它是64位的,并且使用的是64位的Ubuntu:ruby2.0.0p0(2013-02-24revision39474)[x86_64-linux]Linux[redacted]3.2.0-43-generic#68-UbuntuSMPWedMay1503:33:33UTC2013x86_64x86_64x86_64GNU/Linux 最佳答案 GC.disable将禁用垃圾回收。像rub

  9. ruby-on-rails - 使用 Rails (Tire) 和 ElasticSearch 进行模糊字符串匹配 - 2

    我有一个Rails应用程序,现在设置了ElasticSearch和Tiregem以在模型上进行搜索,我想知道我应该如何设置我的应用程序以对模型中的某些索引进行模糊字符串匹配。我将我的模型设置为索引标题、描述等内容,但我想对其中一些进行模糊字符串匹配,但我不确定在何处进行此操作。如果您想发表评论,我将在下面包含我的代码!谢谢!在Controller中:defsearch@resource=Resource.search(params[:q],:page=>(params[:page]||1),:per_page=>15,load:true)end在模型中:classResource'Us

  10. Ruby 缺少常量表达式优化? - 2

    我希望Ruby的解析器会进行这种微不足道的优化,但似乎并没有(谈到YARV实现,Ruby1.9.x、2.0.0):require'benchmark'deffib1a,b=0,1whileb由于这两种方法除了在第二种方法中使用预定义常量而不是常量表达式外是相同的,因此Ruby解释器似乎在每个循环中一次又一次地计算幂常数。是否有一些Material说明为什么Ruby根本不进行这种基本优化或只在某些特定情况下进行? 最佳答案 很抱歉给出了另一个答案,但我不想删除或编辑我之前的答案,因为它下面有有趣的讨论。正如JörgWMittag所说,

随机推荐