【ES实战】ES中关于segment的小结

文章目录

ES中关于segment的小结

segment对于索引的影响

  • segment数量过多会导致搜索的效率降低,主要是搜索需要遍历全部segment文件。

  • segment过大会导致,多次读取磁盘才找到数据,加剧IO和GC

  • segment数量过少会降低并发数

需要根据不同的场景控制segment的数量,单个segment的大小最大就是索引单个分片的大小,大小最大不超过50GB。

本文图片均来自elasticsearch官网

ES中segment相关的原理

一个Lucene的索引即ES中索引的一个分片

Elasticsearch底层依赖的Lucene,引入了按段查询(per-segment search)的概念。一个段(segment)是有完整功能的倒排索引,但是现在Lucene中的索引指的是段的集合,再加上提交点(commit point,即记录所有分段的文件)。当在这个commit point上进行搜索,就是在这个提交点下面的所有的segment文件中搜索,每个segment返回结果,然后汇总返回给用户。

一个Lucene索引的是示意图

在Lucene中的产生segment的过程。(Lucene commit过程)

  1. 新的文档被写入内存中。

  2. 当内存中的文档数达到一定数量或者达到一定时长。缓存会被提交。

    a. 生成一个新的segment文件,写入磁盘。

    b. 生成一个新的commit point文件,记录当前可用的所有segment。

    c. 通过同步方式,等待数据写入磁盘。

  3. 打开新建的segment文件,使其可供搜索。

  4. 清空内存。

Lucene中的分段一旦创建完成,是无法变更的。优点:

  1. 没有必要给逆向索引加锁,因为不允许被更改,只有读操作,所以就不用考虑多线程导致互斥等问题。
  2. 索引一旦被加载到了缓存中,大部分访问操作都是对内存的读操作,省去了访问磁盘带来的io开销。
  3. 因为逆向索引的不可变性,所有基于该索引而产生的缓存也不需要更改,因为没有数据变更。
  4. 使用逆向索引可以压缩数据,减少磁盘io及对内存的消耗。

ES为了实现近实时可查询做了哪些

缩短数据可被搜索的等待时长

Lucene commit实现了数据的持久化(数据存入磁盘),这是一个高代价的操作,耗时且占资源。所以ES旨在减少Lucene commit的次数。

由于Lucene 允许新段被写入和打开---使其包含的文档在未进行一次完整提交时便对搜索可见。所以在文件系统的缓存中新建一个segment,将内存中的数据写入其中,并打开此segment,这样就使得数据可以快速的被搜索。此代价比直接commit的代价要小。

为了增加对上述操作的可操控性,ES提供了refresh操作。此操作就是,将内存中的文档写入新segment(文件系统缓存中),再打开这个segment的轻量的过程。通过减少refresh的间隔时间,会是数据近实时可搜索。

增加数据的可靠性

但是这个segment是临时的,在进程退出或者机器断电的情况下,数据会丢失。为了增加数据的可靠性。ES就提供了translog和flush操作,这个flush操作就是类似ucene的commit操作。

文档索引的过程

  1. 文档在被写入Lucene的内存区域的同时会被写入Translog文件中。先写Lucene,再写translog,在写Lucene时会进行数据的检查,写入会失败,先写Lucene可以避免对translog的回滚处理。
  1. 在refresh执行后,会将内存中的数据写入文件系统缓存中的segment中。
  1. 不同写入和refresh,数据不断的写入到内存和translog中。

  2. 当达到一定的时长,或者translog达到一定大小时,会触发flush操作。

    a. 生成一个新的segment文件,将内存数据写入磁盘

    b. 内存缓冲区被清空。

    c. 生成一个新的commit point文件,记录当前可用的所有segment。

    d.文件系统缓存通过 fsync 被刷新(flush),将文件系统缓存中的segment写入磁盘。

    e.老的 translog 被删除。

优化segment的数量 段合并

自动合并

由于自动refresh流程每个周期会创建一个新的段 ,这样会导致短时间内的段数量暴增。

段数量过多的问题:

  1. 资源过度消耗:占用大量的文件句柄、内存和CPU
  2. 降低搜索的效率:每个搜索请求都必须轮流检查每个段;所以段越多,搜索也就越慢。

ES提供了合并调度程序 (ConcurrentMergeScheduler) ,将较小的segments会定期合并为较大的段以保持索引大小并清除删除。合并过程使用自动节流来平衡合并和其他活动(如搜索)之间硬件资源的使用。

合并的方式是先复制后删除。

合并过程

  1. 根据策略选择合理的一组segment,新建一个大一点segment,将一组中的segment的数据写入新的segment中。

  2. 新的segment刷盘后,新建一个新的提交点(排除被合并的那一组segment,增加新的segment)。

  3. 打开新的segment,供搜索。

  4. 删除被合并的一组segment。

强制合并

强制合并API的源码分析

相关配置

translog

索引级别动态translog配置项:

  • index.translog.sync_interval

    translog 被synced到磁盘并提交的频率。 默认为5s。不允许小于100ms

  • index.translog.durability

    是否在每个索引、删除、更新或批量请求后进行 fsync 和提交 translog。 此设置接受以下参数:

    • request (默认)fsync 并在每次请求后提交。 在硬件故障的情况下,所有确认的写入都已经提交到磁盘。
    • async fsync 并在每个 sync_interval 后台提交。 在硬件故障的情况下,自上次自动提交以来的所有确认写入都将被丢弃。
  • index.translog.flush_threshold_size

    translog 一旦达到最大大小,就会发生flush,生成一个新的 Lucene 提交点。 默认为512mb

  • index.translog.retention.size

    要保留的 translog 文件的总大小。 保留更多的 translog 文件会增加在恢复副本时执行基于操作的同步的机会。 如果 translog 文件不足,副本恢复将回退到基于文件的同步。 默认为512mb

  • index.translog.retention.age

    translog 文件将被保留的最长时间。 默认为12h

如果集群健康状态优秀,同时可以接收数据丢失的话,可以将translog配置调整一下,增加数据写入速率。

json 复制代码
index.translog.durability: async
index.translog.sync_interval: 120s
index.translog.flush_threshold_size: 1024mb

合并策略相关

索引级别的相关动态配置

  • index.merge.policy.expunge_deletes_allowed :当调用expungeDeletes时,我们仅在其删除百分比超过此阈值时才合并掉一个段。默认值10
  • index.merge.policy.floor_segment:小于此的段将"向上取整"到此大小,即视为合并选择的相等(下限)大小。 这是为了防止频繁刷新微小段,从而防止索引中出现长尾。默认值2MB。
  • index.merge.policy.max_merge_at_once :在"normal"合并期间一次合并的最大段数。默认值10
  • index.merge.policy.max_merge_at_once_explicit :在强制合并或 expungeDeletes 期间,一次合并的最大段数。默认值30
  • index.merge.policy.max_merged_segment :在正常合并(not explicit force merge)期间生成的最大段。此设置是近似值:合并段大小的估计是通过对要合并的段的大小求和(补偿已删除文档的百分比)得出的。默认值5GB
  • index.merge.policy.segments_per_tier :设置每层允许的段数。较小的值意味着更多的合并但更少的段。默认为 10。请注意,此值需要大于 max_merge_at_once 的值,否则您将强制发生太多合并。
  • index.merge.policy.deletes_pct_allowed :控制索引中允许的已删除文档的最大百分比。较低的值会使索引的空间效率更高,但会增加 CPU 和 I/O 活动。值必须介于 2050 之间。默认值为 33

进行写入优化的时候可以将index.merge.policy.segments_per_tier适当的变大,建议:20,在降低合并的操作次数。同时降低index.merge.policy.max_merged_segment的值,建议值:2GB,来加快写入的速度。

5.X 调整index.merge.policy.reclaim_deletes_weight增加合并含有已删除segment的权重。6已经标记为废弃。

合并调度相关

调度相关动态配置,不建议调整

  • index.merge.scheduler.max_thread_count:一次可以合并的最大线程数。 默认为 Math.max(1, Math.min(4, Runtime.getRuntime().availableProcessors() / 2)),它适用于良好的固态硬盘 (SSD)。 如果是机械硬盘,将其减少到 1。
  • index.merge.scheduler.auto_throttle:如果是true(默认值),则合并调度程序将根据随时间请求的合并次数将合并的 IO(写入)速率限制为自适应值。 一个低索引率的应用程序不幸突然需要一个大的合并,将会看到合并被严重限制,而一个执行大量索引的应用程序会看到限制调整的更高,以允许合并跟上正在进行的写入。
  • index.merge.scheduler.max_merge_count:一次可以合并的最大分段数。默认值由最大线程数据+5。最小值为1。

相关API

手动refresh

shell 复制代码
POST /index1,index2/_refresh

手动flush

shell 复制代码
POST index1,index2/_flush

强制合并API

强制合并API的使用

相关推荐
SimonKing4 分钟前
分享一款可以管理本地端口的IDEA插件:Port Manager
java·后端·程序员
索荣荣10 分钟前
Maven配置文件(pom.xml)终极指南
java·开发语言
代码栈上的思考23 分钟前
SpringBoot 拦截器
java·spring boot·spring
送秋三十五27 分钟前
一次大文件处理性能优化实录————Java 优化过程
java·开发语言·性能优化
龙山云仓29 分钟前
MES系统超融合架构
大数据·数据库·人工智能·sql·机器学习·架构·全文检索
雨中飘荡的记忆30 分钟前
千万级数据秒级对账!银行日终批处理对账系统从理论到实战
java
jbtianci35 分钟前
Spring Boot管理用户数据
java·spring boot·后端
Sylvia-girl38 分钟前
线程池~~
java·开发语言
魔力军42 分钟前
Rust学习Day3: 3个小demo实现
java·学习·rust
时艰.1 小时前
java性能调优 — 高并发缓存一致性
java·开发语言·缓存