es内部分片原理

1. 使文档可被搜索

   传统的数据库每个字段存储单个值,但这对全文检索并不够。文本字段中的每个单词需要被搜索,对数据库意味着需要单个字段有索引多值(这里指单词)的能力。所以es使用倒排索引来创建数据和关键词之前的关系。

   倒排索引被写入磁盘后是 不可改变 的:它永远不会修改。不能修改有他的好处:

   (1).不需要锁。如果你从来不更新索引,你就不需要担心多进程同时修改数据的问题。
   (2).一旦索引被读入内核的文件系统缓存,由于其不变性。那么大部分读请求会直接命中内存,而不会从磁盘读取。这提供了很大的性能提升。
   (3).其它缓存(像filter缓存),在索引的生命周期内始终有效。它们不需要在每次数据改变时被重建,因为数据不会变化。
   (4).写入单个大的倒排索引允许数据被压缩,减少磁盘 I/O 和 需要被缓存到内存的索引的使用量。

2. 动态更新索引

   如果倒排索引文件是不可变得,那么如何对索引数据进行更新呢?es采用追加索引的方式,当修改或者删除一条数据时,会向倒排索引文件中追加一条记录,检索数据时,会从头开始查询所有结果,在根据检索出来的数据进行合并和过滤。按段搜索的过程如下:

(1) 新增document的过程
  es是基于Lucene的,而在lucene中index被分为多个段(segment),每个段都是一个倒排索引文件。lucene中一个索引包括一个提交点和多个段,提交点包含这些段的所有信息。


image

   a. 新文档被收集到内存索引缓存。


image

   b.当内存索引缓存被占满时,则会进行提交。
   一个新的段(新的倒排索引文件)被写入磁盘,一个新的提交点(包含这个新段)被写入磁盘,将所有内存索引缓存被刷新到磁盘,以确保他们被写入物理文件。


image

   c.开启新的段,使它可以被搜索。

   d.内存索引缓存被清空,等待接收新的文档。

(1) 更新和删除document的过程

   段是不可改变的,所以既不能从把文档从旧的段中移除,也不能修改旧的段来进行反映文档的更新。 取而代之的是,每个提交点会包含一个 .del 文件,文件中会列出这些被删除文档的段信息。

   当一个文档被 “删除” 时,它实际上只是在 .del 文件中被 标记 删除。一个被标记删除的文档仍然可以被查询匹配到, 但它会在最终结果被返回前从结果集中移除。

   文档更新也是类似的操作方式:当一个文档被更新时,旧版本文档被标记删除,文档的新版本被索引到一个新的段中。 可能两个版本的文档都会被一个查询匹配到,但被删除的那个旧版本文档在结果集返回前就已经被移除。

3. 近实时搜索

  随着按段(per-segment)搜索的发展,一个新的文档从索引到可被搜索的延迟显著降低了。新文档在几分钟之内即可被检索,但这里还是不够快,因为提交一个新的段到磁盘需要一个 fsync来确保段被物理性写入磁盘,这样在断电的时候就不会丢失数据,但是每次新增一个文档,都去fsync是十分耗时的操作。

  像之前描述的一样, 在内存索引缓冲区中的文档会被写入到一个新的段中,但是这里新段会被先写入到文件系统缓存,稍后再被刷新到磁盘—​这一步代价比较高。不过只要文件已经在文件系统缓存中, 就可以像其它文件一样被打开和读取了。

  Lucene 允许新段被写入和打开—​使其包含的文档在未进行一次完整提交时便对搜索可见。意味着在当文档被写入内存索引缓存且没有刷新到磁盘,就对外可搜索了, 这种方式比进行一次提交代价要小得多,并且在不影响性能的前提下可以被频繁地执行。

4. refresh API

  在 es中,写入和打开一个新段的轻量的过程叫做 refresh 。 默认情况下每个分片会每秒自动刷新一次。es是近实时搜索的原因: 文档的变化并不是立即对搜索可见,但会在一秒之内变为可见。

  如果你索引了一条数据,但是搜索时没有该记录可以通过以下命令进行手动刷新。

POST /_refresh
POST/index /_refresh

  如果你正在使用 es索引大量的日志文件, 你可能想优化索引速度而不是近实时搜索, 可以通过设置 refresh_interval , 降低每个索引的刷新频率:

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

  refresh_interval 可以在已存索引上进行动态更新。 在生产环境中,当你正在建立一个大的新索引时,可以先关闭自动刷新,待开始使用该索引时,再把它们调回来:

PUT /my_logs/_settings
{ "refresh_interval": -1 }  //关闭自动刷新
PUT /my_logs/_settings
{ "refresh_interval": "30s" }    //30s刷新一次

5. 持久化变更

  如果没有用fsync 把数据从文件系统缓存刷(flush)到硬盘,我们无法确保当出现异常情况时,该数据是否存在。在之前我们说过,当一个document被写入到索引内存缓存时,该文档就能被检索,即使通过每秒refresh,在两次刷新过程中,数据也有可能丢失。
  es确保数据的完整新,增加了一个事务日志(translog),每一次操作es都会进行日志记录。通过translog整个流程看起来如下:

(1)索引一个文档,该文档被添加到内存缓冲区,并向事务日志中增加日志。
(2)refresh,将内存缓冲区的内容的文档写入一个新的段中,但是没有fsync操作,清空缓冲区,但是不清空日志文件。
(3)线程继续工作,更多的文档被添加到缓冲区和日志文件中。
(4)每隔一段时间—​例如 translog 变得越来越大—​索引被刷新(flush);一个新的 translog 被创建,并且一个全量提交被执行。
  所有在内存缓冲区的文档都被写入一个新的段。
  缓冲区被清空。
  一个提交点被写入硬盘。
  文件系统缓存通过 fsync 被刷新(flush)。
  老的 translog 被删除。

6. 刷新api

  这个执行一个提交并且将操作系统缓存中的段刷新到磁盘的行为在 Elasticsearch 被称作一次 flush 。 分片每30分钟被自动刷新(flush),或者在 translog 太大的时候也会刷新。可以通过以下命令手动刷新:更多设置请看 translog 文档

POST /index/_flush
POST /_flush?wait_for_ongoing

  注意:在重启节点或关闭索引之前执行 flush有益于你的索引。当 Elasticsearch 尝试恢复或重新打开一个索引, 它需要重放 translog 中所有的操作,所以如果日志越短,恢复越快

7.段合并

  在每次刷新时,都会将内存缓冲区中的数据写入到一个新的段中,由于自动刷新的存在,所以会导致短时间内会出现多个段,而每一个段都会消耗文件句柄、内存和cpu运行周期。更重要的是,每个搜索请求都必须轮流检查每个段;所以段越多,搜索也就越慢。

  es通过在后台进行段合并来解决这个问题。

段合并的过程如下:

  1.当索引的时候,刷新(refresh)操作会创建新的段并将段打开以供搜索使用。

  2.合并进程选择一小部分大小相似的段,并且在后台将它们合并到更大的段中。这并不会中断索引和搜索。

  3.新的段被刷新(flush)到了磁盘。 es 写入一个包含新段且排除旧的和较小的段的新提交点。新的段被打开用来搜索。老的段被删除。

  合并大的段需要消耗大量的I/O和CPU资源,如果任其发展会影响搜索性能。Elasticsearch在默认情况下会对合并流程进行资源限制,所以搜索仍然 有足够的资源很好地执行。

8.optimize API

  optimize API大可看做是强制合并API。它会将一个分片强制合并到 max_num_segments 参数指定大小的段数目。 这样做的意图是减少段的数量(通常减少到一个),来提升搜索性能。使用命令如下

POST /index/_optimize?max_num_segments=1

  特定情况下,使用 optimize API 颇有益处。例如在日志这种用例下,每天、每周、每月的日志被存储在一个索引中。 老的索引实质上是只读的;它们也并不太可能会发生变化。在这种情况下,使用optimize优化老的索引,将每一个分片合并为一个单独的段就很有用了;这样既可以节省资源,也可以使搜索更加快速:

注意:optimize API 触发段合并的操作不会受到任何资源上的限制。这可能会消耗掉你节点上全部的I/O资源, 使其没有其他资源来处理搜索请求,从而有可能使集群失去响应。如果你想要对索引执行 optimize,你需要先使用分片分配(查看 迁移旧索引)把索引移到一个安全的节点,再执行。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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