「干货」图解 Elasticsearch 写入流程【图文】_zhenghhgz_51CTO博客

请访问原文

ES的写入和mysql的写入 es 写入_ES的写入和mysql的写入

 

整体上看,Client 向 ES 发送写请求,es 接收数据,写入磁盘文件,返回响应给 Client 写入成功,这样就完成了。

然后拉近看一下,看看内部都做了什么工作。

2. ES 整体结构

ES的写入和mysql的写入 es 写入_缓存_02

 

ES 集群里面有多个 Server 节点,一个 ES Index 有多个 shard 分片,每个 shard 有多个副本。

ES的写入和mysql的写入 es 写入_数据_03

 

其中有一个 primary 主副本,负责写入,其他副本为 replica,不能写,只能同步 primary 的数据,但可以处理读请求。

ES 收到写请求后,会将请求路由到目标 shard 的 primary 副本。

ES的写入和mysql的写入 es 写入_ES的写入和mysql的写入_04

 

每一个 shard 就是一个 Lucene Index,包含多个 segment 文件,和一个 commit point 文件。

segment 文件存储的就是一个个的 Document,commit point 记录着都有哪些 segment 文件。

ES的写入和mysql的写入 es 写入_ES的写入和mysql的写入_05

 

了解了 ES 的整体结构,可知 primary shard 收到写请求,就是把 Document 数据写入 segment。

3. 直接写 Segment 效率低怎么办?
如果每次写操作都是直接落盘的话,I/O 效率会比较低。

ES的写入和mysql的写入 es 写入_elasticsearch_06

 

所以,ES 使用了一个内存缓冲区 Buffer,先把要写入的数据放进 buffer。

内存性能好,但不安全,会丢数据,所以 es 使用了一个日志文件 Translog。就像 MySQL 的 Binlog,记录着每一条操作日志,如果 ES 出现故障,重启之后可以从 Translog 中恢复数据。

因为日志文件只是单纯的做内容追加,没有其他逻辑操作,所以写入速度很快。

并不是每条操作直接写入磁盘,也是有一个内存缓冲,每隔5秒写入磁盘。所以,极端情况下会有5秒数据的丢失,如果要严格保证数据安全,可以调整这个时间。

这样,数据来到 primary shard 之后,先是进入 buffer,并把操作记录写入 Translog。

4. Buffer 中数据怎么写入 Segment 文件?

ES的写入和mysql的写入 es 写入_大数据_07

 

ES 每隔一秒执行一次 refresh 操作,会创建一个 Segment 文件,将 buffer 中的数据写入这个 segment,并清空 buffer。

进入 segment 的数据就进入了 Lucene,建立好了倒排索引,可以被搜索到。

5. 如何进一步提升写 Segment 效率?

ES的写入和mysql的写入 es 写入_elasticsearch_08

 

需要注意,ES 虽然把数据写入了 segment 文件,但实际上还没有真正落盘,因为操作系统的文件系统也是有缓存的,这是操作系统层面的性能优化,由操作系统决定物理落盘时间,除非程序写文件时使用同步写 fsync。

ES 为了性能自然没有使用 fsync,因为有 Translog 记录了所有操作步骤。

虽然可能还没实际写入 segment 物理文件,但只要进入了操作系统的文件系统,就可以被搜索了,这一点不用担心。

6. Translog 日志文件越来越大怎么办?

随着写入数据的增加,Translog 也越来越大,需要清理。

触发清理动作需要2个条件:

大小触发设定的阈值

30分钟

任意条件满足即触发一次 commit 提交操作。

操作流程:

执行 refresh 操作。

把这次提交动作之前所有没有落盘的 segment 强制刷盘,确保写入物理文件。

创建一个提交点,记录这次提交对应的所有 segment,写入 commit point 文件。

清空 Translog,因为 Segment 都已经踏实落地了,之前的 Translog 就不需要了。

这个提交流程,称为 flush。

7. Segment 太多怎么办?
通过上面的流程,可以发现,segment 文件太多了,一秒就产生一个,这会严重影响搜索性能。

es 有一个后台程序,用于 merge 合并这些 segment 文件,把小 segment 整合到一个大的 segment 中,并修改 commit point 的 segment 记录。

merge 过程还会清理被删除的数据。

es 接收到删数据请求时,不会真的到 segment 中把数据删了,而是把要删除的数据写到 '.del' 文件中,在读操作时,会根据这个文件进行过滤。

merge 合并时才真正删除,合并后的 segment 中就没有已经删除的数据了。

8. 小结
写操作时,ES 把写请求路由到目标 Shard 所在的 Server 节点,Doc 先被放入 Buffer,并记录此请求的操作日志,写入 Translog。

每隔一秒,执行 Refresh 操作,将 Buffer 中数据写入 Segment 文件,并清空 Buffer。

Refresh 实际写入的 Segment 文件缓存,会在 Flush 操作中刷盘到物理文件。

当 Translog 过大,或者每隔 30 分钟,执行一次 Flush 操作。

先执行一次 Refresh,然后将所有 Segment 文件缓存刷盘到物理文件,并创建提交点,记录此次操作设计的 Segment,写入 Commit Point 文件,最后清空 Translog。

ES 的 Merge 程序负责合并小 Segment,并清除被删除的 Document。
-----------------------------------
「干货」图解 Elasticsearch 写入流程
https://blog.51cto.com/u_7117633/2866130

文章2

Elasticsearch源码:写入流程原理分析(一)-Solr|Nutch|Lucene|ES-About云开发

ES的写入和mysql的写入 es 写入_缓存_09

 ES的写入采用一主多副的模式,写操作一般会经过三种节点:协调节点、主分片所在节点、副本分片所在节点。
客户端发送请求到Node1(相当于协调节点),协调节点收到请求之后,确认写入的文档属于分片P0,于是将请求转发给P0所在的节点Node3,Node3写完成之后将请求转发到P0所属的副本R0所在的节点Node1和Node2。

思考:

整体上看

Client 发送请求到es-es接收到数据写入磁盘,返回响应给Client,写入成功

从节点,shard考虑

客户端请求到协调节点,协调节点hash(key)*shard,确定消息该发到哪个(主)分片,这个分片可能在其他节点,协调节点将请求转发到目标分片对应节点,主分片写完成后,请求转发到副本所在节点,数据同步;

总结:协调节点接收,主分片写入,副本同步

从内存磁盘考虑

看下面两个图

刚才说写到主分片,具体写到哪里,写到主分片下的segment,这是个啥:系统文件缓存,注意这是个缓存,还没有真正落盘,但是可以查询到。还有一个概念buffer,如图3,内存缓冲区Buffer,流程:

请求数据-写入缓存中Buffer-写入文件缓存sengment-定时刷盘到物理磁盘

ES的写入和mysql的写入 es 写入_大数据_10

 

ES的写入和mysql的写入 es 写入_数据_11

 

ES的写入和mysql的写入 es 写入_ES的写入和mysql的写入_12