ES的常见操作与原理分析

157 阅读25分钟

ES的常见操作与原理分析

集群

简述

  • 是一个由多个节点组成的网络,这些节点相互连接并共享数据,使用的主从结构(Master-Slave)
  • 集群中的节点可以扮演不同的角色,如:主节点、数据节点或者ingest节点

节点分析

主节点(Master Node)

  • 负责集群层面的相关操作,管理集群变更
  • o 主节点全局唯一,通过选举晋升为Master节点

数据节点(Data Node)

  • 负责保存数据、执行数据相关操作:CRUD、搜索、聚合等

预处理节点(Ingest node)

  • 预处理操作允许在索引文档之前,即写入数据之前,通过事先定义好的一系列的Processors(处理器)和pipeline(管道),对数据进行某种转换、富化

协调节点(Coordinating Node)

  • 客户端请求可以发送到集群的任何节点,每个节点都知道任意文档的位置,然后转发这些请求,收集数据并返回给客户端,处理客户端请求的节点称为协调节点

部落节点(Tribe Node)

  • 该功能运行部落节点在多个集群之间充当联合客户端
  • 它不做主节点、也不做数据节点,仅用于路由请求,本质上是一个智能负载均衡器,从5.0版本开始,这个角色被协调节点取代

集群健康状态

  • Green,所有主分片和副分片都正常运行
  • Yellow,所有主分片都正常运行,存在非正常运行的副分片。这意味着存在单点故障风险
  • Red,有主分片没能正常运行

集群状态

  • 集群状态元数据是全局信息,元数据包括内容路由信息、配置信息等

集群扩容

  • 当扩容集群、添加节点时,分片会均衡地分配到集群的各个节点,从而对索引和搜索过程进行负载均衡,这些都是系统自动完成的
  • 分片副本实现了数据冗余,从而防止硬件故障导致的数据丢失

集群工作原理的关键步骤

  • 节点发现,新节点加入集群或现有节点加入集群时,它们通过广播请求来发现其他节点
  • 组成集群,一旦节点发现,他们将组成一个集群并开始协调工作
  • 分片分配,索引创建过程中,分片被分配给集群中的节点
  • 数据复制,每个分片可以有一个或多个复制,以确保数据的高可用性
  • 负载均衡,当新文档被索引或旧文档被删除时,集群会自动均衡各分片的负载
  • 故障转移,如果主节点或数据节点失效,其他节点会接管失效节点的工作

集群启动流程

  • 选举主节点
    • 选举规则与选举算法
  • 收集集群元信息
    • 收集各节点存储的元信息,根据版本号,确定最新的元信息,然后把这个信息广播下去
  • allocation过程
    • 选主分片
    • 选副分片
  • index recovery
    • 主分片recovery
    • 副分片recovery
  • 集群启动日志

节点启动

流程相关工作

  • 解析配置,包括配置文件和命令行参数
  • 检查外部环境和内部环境,例如JVM版本、操作系统内核参数等
  • 初始化内部资源,创建内部模块,初始化探测器
  • 启动各个子模块和keepalive线程

流程操作

  1. 启动脚本
  2. 解析命令行参数和配置文件
  3. 加载安全配置
  4. 检查内部环境
    • 检查lucene版本
    • 检查jar冲突
  5. 检查外部环境
    • 堆大小检查
    • 文件描述符检查
    • 内存锁定检查
    • 最大线程数检查
    • 最大虚拟内存检查
    • 最大文件大小检查
    • 虚拟内存区域最大数量检查
    • JVM Client模式检查
    • 串行收集检查
    • 系统调用过滤器检查
    • OnError与OnOutOfMemoryError检查
    • Early-access检查
    • G1GC检查
  6. 启动内部模块
    • discovery.start()
    • clusterService.start()
    • nodeConnectionsService.start()
  7. 启动Keepalive线程

节点关闭

流程相关内容

  1. 关闭快照和HTTPServer,不再响应用户REST请求
  2. 关闭集群拓扑管理,不再响应Ping请求
  3. 关闭网络模块,让节点离线
  4. 执行各个插件的关闭流程
  5. 关闭IndicesService

关闭节点的场景

  • 分片读写过程中执行关闭
  • 主节点被关闭

选主流程

选举算法

  • Bully算法
  • Paxos算法

配置项

  • discovery.zen.minimum_master_nodes
    • 最小主节点数
    • 用于判断的场景
      • 触发选主
      • 决定Master
      • gateway选举元信息
      • Master发布集群状态
  • discovery.zen.ping.unicast.hosts
    • 集群的种子节点列表
  • discovery.zen.ping.unicast.hosts.resolve_timeout
    • dns解析超时时间,默认5秒

选举流程分析

投票与得票的实现分析

确立Master或加入集群

节点失效检测

写入流程

简述

  • 在ES中,写入单个文档的请求称为Index请求,批量写入的请求称为Bulk请求
  • 写单个和多个文档使用相同的处理逻辑,请求被统一封装为BulkRequest

文档操作

操作类型(OpType)

  • INDEX(0),向索引中"put"一个文档的操作称为"索引"一个文档。此处的"索引"为动词
  • CREATE(1),put请求可以通过op_type参数设置操作类型为create,在这种操作下,如果文档已经存在,则请求将失败
  • UPDATE(2),默认情况下,"put"一个文档时,如果文档已经存在,则更新它
  • DELETE(3),删除文档

常见参数

  • version,设置文档版本号,主要用于实现乐观锁
  • version_type,请求参数指定的版本号于存储的文档版本号相同,则写入;默认为internal,其它可选值由external等
  • op_type,可设置为create。代表仅在文档不存在时才写入。如果文档已经存在,则请求失败
  • routing,指定routing可使用routing值进行路由;ES默认使用文档ID进行路由
  • wait_for_active_shards,用于控制一致性,当指定数量的分片副本可用时才执行写入,否则重试直至超时;默认为1,主分片可用即执行写入
  • refresh,写入完毕后执行refresh,使其对搜索可见
  • timeout,请求超时时间,默认1分钟
  • pipeline,指定事先创建好的pipeline名称

Index/Bulk基本流程

协调节点处理流程

  1. 参数检查
  2. 处理pipeline请求
    • 数据预处理(ingest)工作通过定义pipeline和processors实现
    • 如果Index或Bulk请求中指定了pipeline参数,则先使用相应的pipeline进行处理
    • 如果当前节点不具备预处理资格,则将请求随机转发到其它具备资格的节点进行处理
  3. 自动创建索引
    • 如果配置为允许自动创建索引(默认允许),则计算请求中涉及的索引,可能有多个,其中哪些索引是不存在的,然后创建它
  4. 对请求的预先处理
    • 对请求的预先处理只是检查参数、自动生成ID、处理routing等
  5. 检测集群状态
    • 协调节点在开始处理时会先检测集群状态,若集群异常则取消写入。例如:Master节点不存在
  6. 内容路由,构建基于Shard的请求
    • 将用户的bulkRequest重新组织为基于shard的请求列表
    • 根据路由算法计算某文档属于哪个分片
      • 如果这些文档的主分片都属于同一个,则写请求被合并为1个
      • 如果不同则遍历所有涉及的分片
  7. 路由算法
    • 路由算法就是根据routing和文档id计算目标shardid的过程
    • es使用随机id和hash算法来确保文档均匀地分配给分片
  8. 转发请求并等待响应
    • 根据集群状态中的内容路由表确定主分片所在节点,转发请求并等待响应
    • 待收到所有响应后(无论成功还是失败的),回复给客户端

主分片节点流程

  1. 检查请求
    • 主分片所在节点收到协调节点发来的请求后,先做校验工作
    • 主要检测要写的是否是主分片,allocationId是否符合预期,索引是否处于关闭状态
  2. 是否延迟执行
    • 判断请求是否需要延迟执行,如果需要延迟则放入队列,否则继续下面的流程
  3. 判断主分片是否已经发生迁移
    • 如果发生迁移,则转发请求到迁移后的节点
  4. 检测写一致性
    • 在写之前,检测本次写操作涉及的shard,活跃shard数量是否足够,不足则不执行写入
    • 默认是,只要主分片可用就执行写入
  5. 写Lucene和事务日志
    • 遍历请求,处理动态更新字段映射,然后调用InternalEngine#index逐条对doc进行索引
    • 先写入Lucene,生成Sequence Number和Version
    • 后写Translog
  6. flush translog
    • 根据配置的translog flush策略进行刷盘控制,定时或立即刷盘
  7. 写副分片
    • 将主分片的变更信息同步至副分片,通过向目标节点发送请求,等待响应的方式,并收集响应信息
  8. 处理副分片写失败情况
    • 主分片所在节点将发送一个shardFailed请求给Master
    • 然后Master会更新集群状态,更新该节点的状态信息

副分片节点流程

  • 执行与主分片基本相同的写doc过程,写完毕后回复主分片节点

写入优化

简述

  • 在ES的默认设置下,是综合考虑数据可靠性、搜索实时性、写入速度等因素的
  • 当离开默认设置、追求极致写入速度时,很多是以牺牲可靠性和搜索实时性为代价的
  • 有时候,业务上对数据可靠性和搜索实时性要求并不高,反而对写入速度要求很高,此时可以调整一些策略,最大化写入速度

优化思路

  • 加大translog flush间隔,目的是降低iops、writeblock
  • 加大index refresh间隔,除了降低I/O,更重要的是降低了segment merge频率
  • 调整bulk请求
  • 优化磁盘间的任务均匀情况,将shard尽量均匀分布到物理主机的各个磁盘
  • 优化节点间的任务分布,将任务尽量均匀地发到各节点
  • 优化Lucene层建立索引的过程,目的是降低CPU占用率及I/O,例如禁用_all字段

相关配置

日志持久化

translog flush

  • index.translog.durability
    • request,每个请求都flush
    • async,表示根据sync_interval配置的策略进行刷新
  • index.translog.sysnc_interval
    • 加大刷盘间隔时间。默认5s,不可低于100ms
  • index.translog.flush_threshold_size
    • 默认值为512MB,超过这个大小会导致refresh操作,产生新的Lucene分段

索引刷新

  • index.refresh_interval
    • 默认情况下索引的refresh_interval为1秒
    • 这意味着数据写1秒后就可以被搜索到,每次索引的refresh会产生一个新的Lucene段,这会导致频繁的segment merge行为
    • 如果不需要这么高的搜索实时性,应该降低索引refresh周期,例如设置120s

段合并

segment merge操作对系统I/O和内存占用都比较高,而merge是由Lucene控制,可以尝试动态调整合并策略的参数来修改merge过程

  • index.merge.policy.segments_per_tier

    • 该属性指定了每层分段的数量,取值越小则最终segment越少,因此需要merge的操作更多,可以考虑适当增加此值,默认为10
  • index.merge.policy.max_merged_segment

    • 单个segment的最大容量,默认5GB,可以考虑适当降低此值

索引缓冲区

indexing buffer在为doc建立索引时使用,当缓冲满时,会刷入磁盘,生成一个新的segment,这是refresh_interval刷新索引外,另一个生成新segment的机会;

每个shard有自己的indexing buffer

  • indices.memory.index_buffer_size

    • 索引buffer的大小,默认为整个堆空间的10%
  • indices.memory.min_index_buffer_size

    • 默认48MB
  • indices.memory.max_index_buffer_size

    • 默认无限制

相关操作

使用bulk请求

  • 简述
    • 批量操作比单个操作效率高得多
    • 但要注意bulk请求的整体字节数不要太大,太大的请求可能会给集群带来内存压力
    • 因此每个请求最好避免超过几十兆字节,即使较大的请求看上去执行的更好
  • bulk线程池和队列
    • 建立索引的过程属于计算密集型任务,应该使用固定大小的线程池配置,来不及处理的任务放入队列
    • 队列大小可以适当增加,但一定要严格控制大小,过大的队列导致较高的GC压力,并可能导致FGC频繁发生
  • 并发执行bulk请求

磁盘间的任务均衡

  • 简单轮询

    • 在系统初始阶段,简单轮询的效果是最均匀的
  • 基于可用空间的动态加权轮询

    • 以可用空间作为权重,在磁盘之间加权轮询

节点间的任务均衡

  • 通过cat接口观察bulk线程池和队列情况
  • get {host}/_cat/thread_pool

索引过程中的优化思路

  • 自动生成doc ID
  • 调整字段Mappings
    • 减少字段数量,对于不需要建立索引的字段,不写入ES
    • 将不需要建立索引的字段index属性值设置为not_analyzed或no
    • 对字段不分词或者不索引可以减少很多运算操作,降低CPU占用,尤其是binary类型,默认情况下占用CPU非常高,而这种类型进行分词通常没有什么意义
    • 减少字段内容长度,如果原始数据的大段内容无需全部建立索引,则可以尽量减少不必要的内容
    • 使用不同的分析器(analyzer),不同的分析器在索引过程中运算复杂度也有较大的差异
  • 调整_source字段
    • _source字段用于存储doc原始数据,对于部分不需要存储的字段,可以通过includes excludes过滤
    • 或者将_source禁用,一般用于索引和数据分离
    • 这样可以降低I/O的压力,不过实际场景中大多不会禁用_source
  • 禁用_all字段
    • ES 6.x后_all字段默认不启用
    • 可以在mapping中将enabled设置为false来禁用_all字段
  • 对analyzed的字段禁用norms
    • norms用于在搜索时计算doc的评分,如果不需要评分,则可以将其禁用
  • index_options设置
    • 用于控制在建立倒排索引过程中,哪些内容会被添加到倒排索引
    • 设置可以一定程度降低索引过程中的运算任务,节省CPU占用率

I/O异常处理

节点故障

可能触发关闭引擎的操作,造成节点故障

  • createSearcherManager,创建搜索管理器
  • index,索引文档
  • delete,删除文档
  • sync flush,同步刷新
  • sync commit,同步提交
  • flush,刷入磁盘
  • force merge,手工合并Lucene分段

Engine关闭过程

  • 将Lucene标记为异常
  • 关闭shard,然后汇报给Master

Master的对应处理

  • 收到节点的SHARD_FAILED_ACTION_NAME消息后,Master通过reroute将失败的shard通过reroute迁移到新的节点,并更新集群状态

异常处理流程

  1. 如果请求在协调节点的路由阶段失败,则会等待集群状态更新,拿到更新后,进行重试,如果再次失败,则仍旧等集群状态更新,直到超时1分钟为止。超时后仍失败则进行整体请求失败处理
  2. 在主分片写入过程中,写入是阻塞的。只有写入成功,才会发起副本请求。如果主shard写失败,则整个请求被认为处理失败。如果有部分副本写失败,则整个请求被认为处理成功
  3. 无论主分片还是副分片,当写一个doc失败时,集群不会重试,而是关闭本地shard,然后向Master汇报,删除是以shard为单位的

补充

  • Get操作/读取Doc失败不会触发shard迁移

读取流程

简述

  • ES的读取流程分为Get和Search两种操作,这两种读取操作有较大的差异
  • GET/MGET必须指定三元组:_index、_type、_id。也就是根据文档id从正排索引中获取内容
  • 而Search不指定_id,根据关键词从倒排索引中获取内容
  • GET API默认是实时的,实时的意思是写完了可以立即读取,但仅限于GET、MGET操作,不包括搜索
  • GET/MGET的实时读取依赖于从translog中读取实现(5.x版本之后改为refresh),因此系统对实时读取的支持会对写入速度有负面影响

GET操作

可选参数

  • realtime,默认为true。Get api默认是实时的,不受索引刷新(refresh)频率设置的影响
  • source filtering,默认情况下,返回文档的全部内容(在_source字段中)。可用设置为false,不返回文档内容;同时可用使用_source_include和_source_exclude过滤返回原始文档的部分字段
  • stored Fields,对于索引映射中store设置为true,本选项用来指定返回哪些字段
  • _source,只返回原始文档内容,其它的_id等元信息不返回
  • routing,自定义routing
  • preference,默认情况下,从分片的多个副本中随机选择一个,通过指定优先级(preference)可以选择从主分片读取,或者尝试从本地读取
  • refresh,默认为false,若设置为true,则可以在读取之前先执行刷新操作,这对写入速度有负面影响
  • version,如果指定了版本号,那么当文档实际版本号与请求的不符时,将返回409错误

基本流程

  1. 客户端发送请求
  2. 协调节点接收到请求,并通过请求中的参数,来确认文档所属分片
  3. 协调节点通过集群状态中的内容表查询分片的详细信息,分片与副本信息
  4. 协调节点将请求转发到任意副本节点进行处理请求
  5. 副本节点接收到请求,进行索引文档,并将结果返回给协调节点
  6. 协调节点获取返回的结果,并将该结果返回给客户端

详细分析

  • 协调节点
    • 内容路由
      • 在构造函数中,准备集群状态、节点列表信息
      • 根据内容路由算法计算目标shardid,也就是文档应该落在哪个分片上
      • 计算出目标shardid后,结合请求参数中指定的优先级和集群状态确定目标节点,由于分片可能存在多个副本,因此计算出的是一个列表
    • 转发请求
      • 作为协调节点,向目标节点转发请求,或者目标是本地节点,直接读取数据
  • 数据节点
    • 读取及过滤
    • 封装结果并进行返回

MGET操作

基本流程

  1. 遍历请求,计算出每个doc的路由信息,得到由shardid为key组成的request map
  2. 循环处理组织号的每个shard级请求,调用处理GET请求时使用的处理单个doc的流程
  3. 收集Response,全部Response返回后,执行finishHim(),给客户端返回结果
  4. 回复的消息中文档顺序与请求的顺序一致。如果部分文档读取失败,则不影响其它结果,检索失败的doc会在回复信息中标出

SEARCH操作

搜索类型

  • DFS_QUERY_THEN_FETCH,dfs查询阶段的流程要多一些,它使用全局信息来获取更准确的评分
  • QUERY_THEN_FETCH(默认)

搜索流程

原始数据(文本)

  • 精确值搜索
    • 比如日期和用户id、IP地址等
    • 对精确值的比较是二进制的,查询要么匹配,要么不匹配
  • 全文检索
    • 指文本内容,比如一条日志,或者邮件的内容
    • 全文内容的查询无法给出"有"还是"没有"的结果,它只能找到结果是"看起来像"你要查询的东西
    • 因此把查询结果按照相似度排序,评分越高,相似度越大

文本分析器

通过分析器对搜索的文本进行分析

  • 字符过滤器,· 主要对字符串进行预处理,例如,去掉HTML,将&转化成and
  • 分词器,将字符串分割为单个词条,例如,根据空格和标点符号分割,输出的词条称为词元(Token)
  • Token过滤器,根据停止词(Stop word)删除词元,例如and、the等无用词,或者根据同义词表增加词条
  • 语言处理,对上一步得到的Token做一些和语言相关的处理,例如,转为小写,以及将单词转换为词根的形式。语言处理组件输出的结果称为词(Term)

建立索引

  • 分析完毕后,将分析器输出的词(Term)传递给索引组件,生成倒排和正排索引,再存储到文件系统中

执行搜索

  • 精确值搜索
    • 调用Lucene完成
  • 全文检索
    1. 对检索字段使用建立索引时相同的分析器进行分析,产生Token列表
    2. 根据查询语句的语法规则转换成一颗语法树
    3. 查找符合语法树的文档
    4. 对匹配到的文档列表进行相关性评分,评分策略一般使用TF/IDF
    5. 根据评分结果进行排序

分布式搜索过程

协调节点流程

  • 查询(Query)阶段
    1. 将查询广播到索引中每个分片或副分片中
    2. 每个分片在本地执行搜并构建一个匹配文档的优先队列,大小为from + size的有序队列中
    3. 每个分片返回各自优先队列中所有文档的ID和排序值给协调节点,协调节点合并这些值到自己的优先队列中,产生一个全局排序后的列表
    4. 查询阶段并不会对搜索请求的内容进行解析,无论搜索什么内容,只看本次搜索需要命中哪些shard,然后正对每个特定shar选择一个副本,转发搜索请求
  • 取回(Fetch)阶段
    1. 协调节点向本次搜索相关节点发送GET请求
    2. 分片所在节点向协调节点返回数据
    3. 协调节点等待所有文档被取回,然后返回给客户端
    4. 为了避免在协调节点中创建的优先队列过大,应尽量控制分页深度
    5. 该阶段的目的是通过文档ID获取完整的文档内容

数据节点流程

  • 响应Query请求流程

    • 执行查询,然后发送Response
    • 慢查询Query日志的统计时间在于本阶段的处理时间
    • 聚合操作在本阶段实现,在Lucene检索后完成
  • 响应Fetch请求流程

    • 执行fetch,然后发送Response
  • 核心功能

    • execute(),通过调用Lucene、searcher.serach()实现搜索
    • rescorePhase,全文检索且需要打分
    • suggestPhase,自动补全及纠错
    • aggregationPhase,实现聚合

拓展

  • 聚合是在ES中实现的,而非Lucene
  • Query和Fetch请求之间是无状态的,除非是scroll方式
  • 分页搜索不会单独缓存(cache),缓存和分页没有关系
  • 每次分页的请求都是一次重新搜索的过程,而不是从第一次搜索的结果中获取
  • 搜索需要遍历分片素有的Lucene分段,因此合并Lucene分段对搜索性能有好处

读取优化

优化思路

  • 系统资源
  • 数据索引方式
  • 查询方式

优化方式

  • 为文件系统cache预留足够的内存
    • 通常,应用程序的读写都会被操作系统"cache",cache保存在系统物理内存中(线上应该禁用swap),命中cache可以降低对磁盘的直接访问频率
    • 从磁盘读取数据,会产生一定的延迟。从系统cache中读取可以避免这种情况,更大的内存有更高的cache命中率,因此至少为系统cache预留一半的可用物理内存
  • 使用更快的硬件
    • 搜索类型属于计算比较多,可用考虑使用更快的CPU
    • 使用SSD会比旋转类存储介质好很多
    • 尽量避免使用NFS等远程文件系统
  • 文档模型
    • 合理设计文档模型
    • 应该避免join操作
    • 嵌套(nested)会使查询慢几倍
    • 父子(parent-child)关系可能使查询慢数百倍
    • 通过冗余提升搜索速度
  • 预索引数据(文档富化)
    • 可用通过某些查询的模式来优化数据的索引方式,在建立索引时,对文档进行富化
  • 字段映射
    • 有些字段的内容是数值,但并不意味着其总是应该被映射为数值类型
  • 避免使用脚本
    • 如果一定要用,则应该优先考虑painless和expressions
  • 优化日期搜索
    • 使用now的查询通常不能缓存,因为匹配到的范围一直在变化
    • 可用将日期四舍五入到某个固定时间(如:年-月-日 小时这种格式),进行查询
  • 只为读索引执行force-merge
    • 基于日期进行轮询的索引的旧数据一般都不会再更新
    • 为不再更新的只读索引执行force merge,将Lucene索引合并为单个分段,可用提升查询速度
    • 可用在每天选一个时间点,对昨天的索引执行force-merge、shrink等操作
  • 预热全局序列(Global ordinals)
    • 全局序号是一种数据结构,用于在keyword字段上允许terms聚合
    • 默认情况下,它们被延迟构建,因为ES不知道哪些字段将用于terms聚合,哪些字段不会
    • 可用通过配置映射在刷新(refresh)时告诉ES预先加载全局序数
  • execution hint
  • 预热文件系统cache
    • 通过指定文件拓展名,显式地告诉操作系统应该将哪些文件加载到内存中
  • 转化查询表达式
    • 在组合查询中可用通过bool过滤器进行and、or和not的多个逻辑组合检索
  • 调节搜索请求中的batched_reduce_size
    • 该字段是搜索请求中的一个参数
    • 默认情况下,聚合操作在协调节点需要等所有的分片都取回结果后才执行,使用该参数可用不等待全部分片返回结果,而是在指定数量的分片返回结果之后就可以先处理一部分reduce
    • 这样可用避免协调节点在等待结果时占用大量内存,避免极端情况下可能导致的OOM
  • 使用近似聚合
    • 近似聚合以牺少量的精度为代价,大幅提高了执行效率,降低了内存使用
  • 深度优先还是广度优先
    • ES有两种不同的聚合方式,深度优先和广度优先
    • 深度优先是默认设置,先构建完整的树,然后修剪无用节点
  • 限制搜索请求的分片数
    • 一个搜索请求涉及的分片数量越多,协调节点的CPU和内存压力越大
    • ES会拒绝超过1000个分片的搜索请求
    • 我们应该更好的组织数据,让搜索请求的分片数量更少
  • 利用自适应副本选择(ARS)提升ES响应速度

索引恢复

简述

  • 索引恢复(indices.recovery)是ES数据恢复过程
  • 待恢复的数据是客户端写入成功,但未执行刷盘(Flush)的Lucene分段

索引恢复分类(分片性质)

主分片恢复

  • 简述
    • 主分片从translog中自我恢复,尚未执行flush到磁盘的Lucene分段可以从translog中重建
  • 流程

副分片恢复

  • 简述
    • 副分片需要从主分片中拉取Lucene分段和translog进行恢复,但是有机会跳过拉取Lucene分段的过程
  • 流程

索引恢复的触发条件

  • 从快照备份恢复
  • 节点加入和离开
  • 索引的_open操作

恢复时的几个阶段

  • INIT,恢复尚未启动
  • INDEX,恢复Lucene文件,以及在节点间复制索引数据
  • VERIFY_INDEX,验证索引
  • TRANSLOG,启动engine,重放translog,建立Lucene索引
  • FINALIZE,清理工作
  • DONE,完成

索引恢复流程的相关配置

保证副分片和主分片一致性

恢复(recovery)相关监控命令

  • _cat/recovery
    • 列出活跃的和已完成的recovery信息
  • {index}/_recovery
    • 查看特定索引的recovery所处阶段,以及每个分片、每个阶段的详细信息
  • _stats
    • 可以查看分片级信息,包括sync_id、local_checkpoint、global_checkpoint等
    • 可以通过指定索引名称查看索引信息,或者使用_all输出全部索引信息

Shrink原理分析

简述

  • 其可以缩小主分片的数量
  • 其并不对源索引直接进行缩小操作,而是使用与源索引相同的配置创建一个新的索引,仅降低分片数

工作原理

  • 以相同配置创建目标索引,但是降低主分片数量
  • 从源索引的Lucene分段创建硬链接到目的索引,如果系统不支持硬链接,那么索引的所有分段都将复制到新索引,将会花费大量时间
  • 对目标索引执行恢复操作,就像一个关闭的索引重新打开一样