likes
comments
collection
share

ElasticSearch深入-进阶篇

作者站长头像
站长
· 阅读数 13

引言

之前写了一篇关于 ES 的一些基础知识篇,属于入门级别。传送门: ElasticSearch基础-入门篇。

本篇主要讲解 ES 的一些深入特性以及原理,属于进阶篇。

一、复制模型

1.1 复制组

在入门篇中我们讲过,ES 中每个索引都可以多个分片,每个分片可以有多个副本,副本分片是分片的完整副本,可以为搜索请求提供服务,一个主分片与其副本本分片统称为复制组,主分片和副本在操作文档时必须保持同步,不然就会导致不同副本之间数据不一致。还有需要注意一点就是主分片永远不可能与其副本分片在同一节点上。

1.2 ES中的复制

复制也是在索引级别配置的。ES 中的每个索引操作首先使用路由算法(通常基于文档ID)解析到一个复制组,一旦确定了复制组,该操作将在内部转发到该组当前的主分片(primary)。primary 负责验证操作并转发到其他的副本(replica)。primary 遵循如下操作流程。

  1. 验证传入操作是否符合 ES 的接口规范,如果不符合,直接拒绝。

  2. 在本地执行操作(索引、更新或删除文档)。这还将验证字段的内容(如关键字对索引而言过长),并在需要时拒绝。

  3. 将操作转发到当前同步副本组中的每个 replica。如果有多个副本,是并行完成的。

  4. 一旦所有的副本成功地执行了操作并对 primary 进行了响应,primary 就确认完成了请求并返回给用户。

1.3 ES中读取数据

当发送读取请求时,会将其传送到特定节点(协调节点),负责协调请求。基本流程如下:

  1. 将读取请求解析到相关分片组(一个或多个)。

  2. 从同步副本组中选择一个相关的 shard 的活动分片(可以是 primary,也可以是 slave)。ES 会根据各种指标选择最佳副本。

  3. 向所选分片发送读取请求。

  4. 将结果整合。如果是根据文档 ID查询,只会有一个相关分片,没有此步骤。

到这里,就体会到了副本的威力。如果只有一个主分片,所有查询都落到主分片上,随着工作负载的增长,此策略无法有效扩展,副本分片就会分担压力。

二、段(segment)

ES 底层依赖 lucene 来提供搜索能力,一个分片就是一个 lucene 实例,一个 lucene 实例由多个段(segment) 组成,一个 segment 是有完整功能的倒排索引。

Segment 是最小的数据存储单元。其中包含了文档中的词汇字典、词汇字典的倒排索引以及 Document 的字段数据。Segment 直接提供了搜索功能

三、缓冲区(buffer)

ES 索引的过程不会直接写入磁盘,而是先写入一个缓冲区,定时刷新到磁盘或者等缓冲区满了以后刷新到磁盘中的 segments 中,这个缓冲区就是 indexing buffer。节点上所有分片共享该区域。这部分空间是可以通过 GC 被反复利用的。索引缓冲区的大小通过配置indices.memory.index_buffer_size 指定,默认值为10%。

四、事务日志(translog)

ES 每次调用 lucene 的接口写入或删除数据后,都会先写入内存缓冲区,并将操作日志写入 translog,每个分片都对应一个translog,防止意外断电或程序崩溃等原因导致数据丢失。

translog 存储尚未在 lucene 中安全保留的所有操作 (即,不是 lucene 提交点的一部分)。虽然这些操作是可用于读取,如果分片停止,则需要重放它们并且必须恢复。

translog 默认是每隔 5s 写一次磁盘,如果出现宕机等问题,这可能会导致 5s 的数据丢失。

五、近实时性

ES 写入的数据默认不会立即查询到(有的API是可以的),而是默认 1s 后才能查询到,这就是 ES 的近实时性。

文档物理性的写入磁盘 代价是很高的,所以有了以上我们所讲的缓冲区、事务日志等概念。ES 将数据从缓冲区写到了 Cache 中,数据才可以被搜索到的。数据先写入缓冲区,默认 1s 缓冲区中的数据会刷到Cache,Cache 会刷新到磁盘中。

六、文档写入流程

文字无比枯燥,还是图来的彻底!

ElasticSearch深入-进阶篇

七、refresh和flush

打眼一看 refresh 和 flush 都是将某些操作的结果可以立即被查询到,那么为什么要有两个 API,它们之间究竟有什么区别呢?

7.1 refresh

其实上文已经提到过了 refresh 了,默认情况下,ES 会每秒 refresh 一次,每次 refresh 都会把 buffer 的内容拷贝到新创建的 segment 中去,这个时候新的文档就会被搜索了。

7.2 flush

ES 中的 flush 操作是指将索引中的数据立即写入磁盘,以确保数据不会丢失。

flush 操作意味着,所有在 buffer 的文档被写到新的 segment 中,也就是所有在内存中的 segment 被提交到了磁盘进行存储,此时 translog 也可以被清除了。有没有想过每次文档写入都会写入 translog,这将导致 translog 越来越大,为了避免这个问题,ES 会在 translog 达到了一定大小的时候,触发 flush 操作。默认 30 分钟,也会触发 flush 操作将内存中的数据写入磁盘。

八、GET API的实时性

默认情况下,Get API (通过索引ID查询)是实时的,不受 refresh 操作的影响,即数据没有进行 refresh 操作,也可以被查询到,这又是怎么个事呢?

通过上文的讲解,想必大家都已经猜到了,没错就是通过 translog 来实现的实时性。GET API 默认是实时的(realtime=true), 则先从 translog 中读取 source, 没有读取到才从索引中读取,可以将 realtime 设置为 false 来禁用默认。