概要

本篇我们来看看shard内部的一些操作原理,了解一下人家是怎么玩的。

倒排索引

倒排索引的结构,是非常适合用来做搜索的,Elasticsearch会为索引的每个index为analyzed的字段建立倒排索引。

基本结构

倒排索引包含以下几个部分:

  • 某个关键词的doc list
  • 某个关键词的所有doc的数量IDF(inverse document frequency)
  • 某个关键词在每个doc中出现的次数:TF(term frequency)
  • 某个关键词在这个doc中的次序
  • 每个doc的长度:length norm
  • 某个关键词的所有doc的平均长度

记录这些信息,就是为了方便搜索的效率和_score分值的计算。

不可变性

倒排索引写入磁盘后就是不可变的,这样有几个好处:

  1. 不需要锁,如果不更新索引,不用担心锁的问题,可以支持较高的并发能力
  2. 如果cache内存足够,不更新索引的话,索引可以一直保存在os cache中,可以提升IO性能。
  3. 如果数据不变,filter cache会一直驻留在内存。
  4. 索引数据可以压缩,节省cpu和io开销。

doc底层原理

前面提到倒排索引是基于不可变模式设计的,但实际Elasticsearch源源不断地有新数据进来,那光是建立、删除倒排索引,岂不是非常忙?

如果真是不停地建立,删除倒排索引,那ES压力也太大了,肯定不是这么实现的。ES通过增加新的补充索引来接收新的文档和修改的文档,而不是直接用删除重建的方式重写整个索引。

doc写入

整个写入过程如下图所示:

  1. 新文档先写入内存索引缓存
  2. 当间隔一定时间(1秒),将缓存的数据进行提交,这个过程会创建一个Commit Point,Commit Point包含index segment的信息。
  3. 缓存的数据写入新的index segment。
  4. index segment的数据先写入os-cache中
  5. 等待操作系统将os-cache的数据强制刷新到磁盘中
  6. 写入磁盘完成后,新的index segment被打开,此时segment内的文档可以被搜索到。
  7. 同时buffer的数据被清空,等待下一次新的文档写入。

index segment翻译过来叫"段",每秒会创建一个,ES把这个1秒内收到的、需要处理的文档都放在这个段里,可以把段认为是倒排索引的一个子集。

索引、分片、段的关系如下:

索引包含多个分片,每个分片是一个Lucene索引实例,一个分片下面有多个段。如果把分片看作是一个独立的倒排索引结构,那么这个倒排索引是由多个段文件的集合。

三者之间是包含关系:索引包含多个分片,分片包含多个段。

doc删除和更新

当文档被删除时,Commit Point会把信息记录在.del文件中,在.del文件中会标识哪些文档是有deleted标记的,但该文档还是存在于原先的index segment文件里,同样能够被检索到,只是在最终结果处理时,标记为deleted的文档被会过滤掉。

更新也是类似的操作,更新会把旧版本的文档标记为deleted,新的文档会存储在新的index segment中。

近实时搜索

上面的流程细节的童鞋可以会发现,每次都需要fsync磁盘,数据才是可搜索的,那IO压力将特别大,耗费时间比较长,并且执行周期由操作系统控制,从一个新文档写入到可以被搜索,超过1分钟那是常有的事。

所以Elasticsearch对此做了一个改进:

index segment信息写入到os-cache中,即完成上面的第4步,该segment内的文档信息就可以被搜索到了。fsync操作就不立即执行了,

os-cache的写入代价比较低,最耗时的fsync操作交由操作系统调度执行。

上述的index segment写入到os-cache,并打开搜索的过程,叫做refresh,默认是每隔1秒refresh一次所以,es是近实时的,数据写入到可以被搜索,默认是1秒。

refresh的时间也可以设置,比如我们一些日志系统,数据量特别大,但实时性要求不高,我们为了优化资源分配,就可以把refresh设置得大一些:

PUT /music
{
"settings": {
"refresh_interval": "30s"
}
}

此参数需要在创建索引时使用,要注意一下的是除非有充分的依据,才会对refresh进行设置,一般使用默认的即可。

translog机制

上述的写入流程当中,如果fsync到磁盘的操作没执行完成,服务器断电宕机了,可能会导致Elasticsearch数据丢失。Elasticsearch也设计了translog机制,跟关系型数据库的事务日志机制非常像,整个写入过程将变成这样:

  1. 新文档写入内存buffer的同时,也写一份到translog当中。
  2. 内存buffer的数据每隔1秒写入到index segment,并写入os-cache,完成refresh操作。
  3. 内存buffer被清空,但translog一直累加。
  4. 每隔5秒translog信息fsync到磁盘上。
  5. 默认每30分钟或translog累积到512MB时,执行全量commit操作,os-cache中的segment信息和translog信息fsync到磁盘中,持久化完成。
  6. 生成新的translog,旧的translog归档(6.x版本translog做归档操作,不删除)。

flush API

这个执行一个提交并且归档translog的行为称作一次flush。分片每30分钟被自动刷新(flush),或者在 translog 太大的时候(默认512MB)也会刷新,当然也可以手动触发flush的执行,如下请求:

POST /music/_flush

但任其自动flush就够了。如果重启节点前担心会对索引造成影响,可以手动flush一下。毕竟节点重启后需要从translog里恢复数据,translog越小,恢复就越快。

durability同步和异步

translog写磁盘行为主要有两种,是由index.translog.durability配置项决定的:

  • request:同步写磁盘,每次写请求完成之后立即执行(新增、删除、更新文档),以及primary shard和replica shard同步都会触发,数据安全有保障,不丢失,但会带来一些性能损失。如果是bulk数据导入,每个文档平摊下来的损失是比较小的。
  • async:异步写磁盘,默认5秒fsync一次,如果有宕机事件,可能会丢失几秒的数据,适用于允许偶尔有数据丢失的场景,如日志系统。

如果系统不接受数据丢失,用translog同步方式,示例设置:

# 异步方式
PUT /music_new
{
"settings": {
"index.translog.durability": "async",
"index.translog.sync_interval": "5s"
}
} # 同步方式
PUT /music_new
{
"settings": {
"index.translog.durability": "request"
}
}

segment合并

Elasticsearch针对活跃的索引,每秒都会生成一个新的index segment,这些segment最终会以文件的形式存储在磁盘里,如果不对其进行处理,那么索引运用一段时间后,会有特别多的文件,零碎的文件太多了,也不是什么好事情,更耗费更多的文件资源,句柄等,搜索过程也会变慢。

合并过程

Elasticsearch会在后台对segment进行合并,减少文件的数量,同时,标记为deleted的文档在合并时会被丢弃(delete请求只是将文档标记为deleted状态,真正的物理删除是在段合并的过程中),合并过程不需要人工干预,让Elasticsearch自行完成即可。

两个已经提交的段和一个未提交的段合并成为一个大的段文件

合并时会挑一些大小接近的段,合并到更大的段中,段合并过程不阻塞索引和搜索。

合并完成后,新的更大的段flush到磁盘中,并完成refresh操作,老的段被删除掉。

optimize API

optimize命令可以强制合并API,并指定最终段的数量,如下命令:

POST /music_new/optimize
{
"max_num_segments": 1
}

指定segment最大数量为1,表示该索引最终只有一个segment文件。

适用场景
  1. 正常活跃的、经常有更新的索引不建议使用
  2. 日志类的索引,对老数据进行优化时,可以将每个分片的段进行合并
使用建议
  1. 一般不需要人工干预合并过程
  2. optimize操作会消耗大量的IO资源,使用要慎重考虑

小结

本篇主要介绍shard内部的原理,包含写入、更新删除,translog机制,segment合并等,了解数据库的童鞋对translog机制应该非常熟悉,原理上大同小异,仅作抛砖引玉,谢谢。

Elasticsearch系列---shard内部原理的更多相关文章

  1. Elasticsearch系列---聚合查询原理

    概要 本篇主要介绍聚合查询的内部原理,正排索引是如何建立的和优化的,fielddata的使用,最后简单介绍了聚合分析时如何选用深度优先和广度优先. 正排索引 聚合查询的内部原理是什么,Elastich ...

  2. Elasticsearch系列---增量更新原理及优势

    概要 本篇主要介绍增量更新(partial update,也叫局部更新)的核心原理,介绍6.3.1版本的Elasticsearch脚本使用实例和增量更新的优势. 增量更新过程与原理 简单回顾 前文我们 ...

  3. Elasticsearch由浅入深(六)批量操作:mget批量查询、bulk批量增删改、路由原理、增删改内部原理、document查询内部原理、bulk api的奇特json格式

    mget批量查询 批量查询的好处就是一条一条的查询,比如说要查询100条数据,那么就要发送100次网络请求,这个开销还是很大的如果进行批量查询的话,查询100条数据,就只要发送1次网络请求,网络请求的 ...

  4. Elasticsearch系列---分布式架构机制讲解

    概要 本篇主要介绍Elasticsearch的数据索引时的分片机制,集群发现机制,primary shard与replica shard是如何分工合作的,如何对集群扩容,以及集群的容错机制. 分片机制 ...

  5. 深入理解javascript作用域系列第一篇——内部原理

    × 目录 [1]编译 [2]执行 [3]查询[4]嵌套[5]异常[6]原理 前面的话 javascript拥有一套设计良好的规则来存储变量,并且之后可以方便地找到这些变量,这套规则被称为作用域.作用域 ...

  6. [转]js作用域系列——内部原理

    前面的话 javascript拥有一套设计良好的规则来存储变量,并且之后可以方便地找到这些变量,这套规则被称为作用域.作用域貌似简单,实则复杂,由于作用域与this机制非常容易混淆,使得理解作用域的原 ...

  7. ElasticSearch 学习记录之集群分片内部原理

    分片内部原理 分片是如何工作的 为什么ES搜索是近实时性的 为什么CRUD 操作也是实时性 ES 是怎么保证更新被持久化时断电也不丢失数据 为什么删除文档不会立即释放空间 refresh, flush ...

  8. JVM 内部原理系列

    JVM 内部原理(一)— 概述 JVM 内部原理(二)— 基本概念之字节码 JVM 内部原理(三)— 基本概念之类文件格式 JVM 内部原理(四)— 基本概念之 JVM 结构 JVM 内部原理(五)— ...

  9. ElasticSearch之 控制相关度原理讲解

    控制相关度 相关度评分背后的理论 如何计算评分的 Lucene 使用布尔模型(Boolean model) 查找匹配文档 并主要的借鉴了 词频/逆向文档频率(term frequency/invers ...

随机推荐

  1. Android开发 文件读写openFileOutput与openFileInput

    package com.example.androidtest; import java.io.ByteArrayOutputStream; import java.io.FileInputStrea ...

  2. POJ2226(二分图建图/最小点覆盖)

    题意: 给定m*n的棋盘,有若干只咕咕.希望去掉一部分咕咕使得剩下的咕咕在上下左右四个方向越过咕咕槽的情况下都看不到咕咕. 思路: 建立一个二分图的方法有很多,这里采用xy二分. 假设没有咕咕槽的情况 ...

  3. Docker最全教程——从理论到实战(二十三)

    如何节约云端成本? 上云在大部分情况下就是为了降低成本,在这方面,主流的容器服务基本上都能够有效地降低成本——不仅能够高效自动化的管理和控制容器,而且不需支付Kubernetes 主节点的费用.不过, ...

  4. 下载 Microsoft JDBC driver 7.2 for SQL Server

    下载 Microsoft JDBC driver 7.2 for SQL Server:https://www.microsoft.com/zh-cn/download/confirmation.as ...

  5. java中的多构造函数以及类字段的初始化顺序

    1.同一个类可以有多个构造函数,多个构造函数之间通过参数来区分.这是方法重载的一个实例.构造函数之间可以相互调用. 2.类的初始化块:可以在类中使用“{”和“}”将语句包围起来,直接将其作为类的成员. ...

  6. [CF1304F] Animal Observation - dp,单调队列

    设 \(f[i][j]\) 为第 \(i\) 天在第 \(j\) 个位置放置的最大值,设 \(s[i][j]\) 是第 \(i\) 行的前缀和,则 \[ \begin{align} f[i][j] & ...

  7. 为什么要使用NoSQL数据库

    NoSQL概念 随着web2.0的快速发展,非关系型.分布式数据存储得到了快速的发展,它们不保证关系数据的ACID特性(原子性.一致性.隔离性.持久性,一个支持事务的数据库,必需要具有这四种特性,否则 ...

  8. JS代码的位置

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. 野路子码农(5)Python中的装饰器,可能是最通俗的解说

    装饰器这个名词一听就充满了高级感,而且很多情况下确实也不常用.但装饰器有装饰器的好处,至少了解这个对装逼还是颇有益处的.网上有很多关于装饰器的解说,但通常都太过“循序渐进”,有的还会讲一些“闭包”之类 ...

  10. sencha Architect 3.2及以下版本都适用的 破解方法

    找到 没有的话 打开隐藏文件夹 C:\Users\ll\AppData\Local\Sencha\Sencha Architect 3.2 用编辑器 打开user.license 把 Print 修改 ...