Elasticsearch系列---shard内部原理

概要

本篇我们来看看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机制应该非常熟悉,原理上大同小异,仅作抛砖引玉,谢谢。

专注Java高并发、分布式架构,更多技术干货分享与心得,请关注公众号:Java架构社区
可以扫左边二维码添加好友,邀请你加入Java架构社区微信群共同探讨技术


Java架构社区
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容

  • 宋.柳永.八声甘州 对潇潇暮雨洒江天,一番洗清秋,渐霜风凄紧,关河冷落,残照当楼,是处红衰翠减,苒苒物华休。惟有...
    小成和大成阅读 83评论 0 1
  • 《克拉恋人》或许有着关于成长的主题。因为“克拉”交汇时空的“恋人”们,在错综缠绕的主线支线里,努力表达现代都市的情...
    黄小淇阅读 1,064评论 6 38
  • 2018-11-13 终于等到成绩结果的一天 一个月的等待,好似一场漫长的路,忐忑紧张辗转难眠 点击“确定”的时候...
    HeleniaZhang阅读 123评论 0 0
  • iOS篇 一、安装Xcode [ 安装过的跳过此步骤 ] 去App Store直接搜索下载安装即可。 安装完打开X...
    码代码的青年阅读 566评论 0 3
  • 总有一天,你需要和自己生活在一起! 陪伴你最长久的就是你自己, 这个世界上你最应该关心的就是这个人了!
    程洁网络21阅读 224评论 0 0