elasticsearch - Lucene分片内部逻辑

Posted lqlqlq

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了elasticsearch - Lucene分片内部逻辑相关的知识,希望对你有一定的参考价值。

1.分片内部基本结构

   在一个分片中(Lucene),数据(数据原文和倒排索引)以段为单位存储,只有成为段的数据才能被检索。

   因为文档先被缓存在内存中,创建倒排索引和其他索引结构之后才会成为段,才能被检索

 就像下图中文档先被写入内存,为文档构建一系列索引之后成为段,并且写入磁盘,只有段才是 Searchable (可检索的)。

 需要注意的是,段是不可被更改的,也就是写入到硬盘中是什么就是什么,无法再去硬盘中定位他们进行写操作。

 不能修改当然有利有弊,最大的好处莫过于:

 1.不需要并发控制

 2.段被从硬盘读入到操作系统在内存中的文件缓存时,能被长期缓存,不会因为修改删除之类的操作使得内存中的缓存失效

 最大的坏处 就是他自己本身:不能修改,或者删除

 虽然不能物理上删除或者修改,但是逻辑上行得通,需要使用额外的文件去标记某个段的某条文档是否被删除,更新。

 可能你已经注意到 commit point 了,在ES中,commit point 本身是一个集合,记录着一系列段的名字(或者说唯一标识)。

 当提交新段的时候,会将这个段写入磁盘,并且写入一个新的 commit point,新的 commit point 包含了 新的段的名字。

 提交段生成提交点,语义明确。

 技术图片        技术图片

 

 其实 commit point 类似于 innodb 中的 checkpoint, innodb中的 checkpoint 表示硬盘中的数据页的最新 LSN ,在通过redolog 崩溃恢复的时候,会从 checkpoint 开始

检查redolog 中 LSN 比 checkpoint 大的记录,并且把他们应用到数据页中去。崩溃恢复其实差不多都是这个老套路。

2.随之而来的问题

 假如如上所述,一个新段要同步回硬盘(一般使用系统调用fsync),才能被用来检索的话(Searchable)。

 因为fsync 耗时长,对于对实时性要求高的 应用来说,是不能容忍的(写入数据后要求立刻检索到,比如订单业务)

 那么就不应该调用 fsync 后才使得新段能被打开使用(“打开”意味着能够被检索使用)。

 要知道操作系统在硬盘和用户之间设置了一层缓存,这层缓存在内存中,平时 mmap 文件的时候,使用的也是这一层文件缓存。

 假如不调用 fsync,而是把新段写入操作系统文件缓存就能使得新段Searchable的话,显然是可以接受的,因为写入内存的操作耗时比起写硬盘等外设来说短之又短

 官方提出 近实时搜索 ,就是依据这一点出发的。下图中灰色的是新段,新段还未从内存(操作系统文件缓存)刷入到硬盘。但是他依据是可检索的了(Searchable)

 技术图片      技术图片

 

   官方提供 refresh 操作,将内存中的文档制作成新段,写入到操作系统缓存中(注意不是 flush 操作)

 值得注意的是,对于对实时性要求不高的搜索,可以降低 refresh 的频率,默认是每 秒中 refresh 一次,也就是上一秒写入,下一秒就可检索。

 refresh频率可以手动设置,当然也可以手动 refresh。

 假如对实时性不高,但是数据量大的话,就可以降低频率,从而充分使用 ES 的文档内存缓存

 

3.持久化

 我个人觉得持久化其实套路都差不多;1是用日志的硬盘顺序写代替离散写;2是将只有部分内容,比较小的日志频繁刷盘,或者在事务完成的时候刷盘,保证落盘,保证数据物理安全,并且使用一个 检查点去做为恢复起点。

 ES 使用的策略是 使用类似 mysql redolog 的 Translog,功能差不多。

 ES 每次提交的时候都会生成一个 commit point,Mysql 在内存中脏数据页刷回硬盘的时候也会产生一个 checkpoint。这两个点都是恢复点。

 Translog 的刷盘频率默认是 每5秒一次,可以改成每次索引文档的时候就刷盘。上面提到的refresh并不会让 Translog刷盘,只是把文档内存缓冲区的内容制作成

 新段放入 os cache。

 官方把Translog 的 刷盘 称为 flush:

 将文档缓冲区的文档做成新段写入 os cache

 清空文档缓冲区

 产生新的 commit point 写入 os cache

 调用 fsync 将  尚在os cache 中的新段 和 Translog 刷入硬盘,落盘完毕。

 

4.段合并

 是追加型日志的老套路,redis 的 AOF 重写也是如此。本质的问题是 之后的 语句可以和 之前的语句合并成实际占用物理空间更小的结果

 比如之前新增 A 记录,后来修改 A 记录,然后删除 A 记录。AOF 重写之前需要记录这三条操作,但是重写合并之后,这条操作就不存在了,所以不需要空间记录 A 留下过的痕迹。

 ES 也是如此,对于删除的段,不会出现在合并之后的段中(未证明被更新的旧段是否会删除,理论上会)

 段这个单位需要耗损一定的物理资源 占用一定的物理时间,将属于多个段的内容合并成一个段可以达到清洁的效果。

 并且检索的时候,也是以段为单位 访问的,所以合并段有助于性能提升

 段合并官方文档

 

 

 

 

 

 

以上是关于elasticsearch - Lucene分片内部逻辑的主要内容,如果未能解决你的问题,请参考以下文章

elasticsearch - Lucene分片内部逻辑

Elasticsearch分片大小和个数设计

ES分片副本设置及集群部署

ES分片副本设置及集群部署

ES分片副本设置及集群部署

Elasticsearch 和 Lucene 文档限制