Elasticsearch Document写入原理

Document写入原理

一. Document写入原理

ES为了实现进实时搜索,在写入Document时利用了Buffer(内存),OS Cache(系统缓存,属于系统内存的一部分),Disk(磁盘)三种存储方式,尽可能的提升搜索的能力。ES的底层lucene实现的,在 luncene中一个index会被分为若干个数据段segment,每一个segment都会存放index的部分document。从流程上讲,ES会先把一个index中的document分散存储在若干个shard(指的是主分片)上,在shard中,使用若干个segment来存储具体的数据。
ES写入数据的流程大致如下:
在这里插入图片描述

  1. 客户端发起请求(增、删、改)到ES中。
  2. ES将本次请求要操作的document写入到buffer中。ES为了保证搜索的近实时(Near Real Time 简称 NRT),默认每秒刷新一次buffer,这个刷新时间间隔可以手动修改,也可以通过命令触发buffer的刷新。建议刷新时间间隔设置在1秒左右,好处使在服务器宕机后,只会丢失1秒左右的数据。
POST /index_name/_refresh

PUT index_name
{
  "settings": {
    "number_of_shards": 5,
    "number_of_replicas": 1,
    "refresh_interval": "1s"
  }
}
  1. ES在将document写入到缓存的同时,也会将本次操作的具体内容写入到translog文件中,这份文件存在的意义在于即便ES宕机了,也能尽可能的减少丢失的数据(简单来说,就是把translog中的记录重新执行一遍),当然translog也不能保证数据绝对不丢失,其原因在第6点详细的讲出了。由于translog存储在磁盘Disk中,因此为了提高访问效率,ES与translog文件之间会建立并保持一个长连接(不然每次访问都要获取和释放文件流)。
  2. 步骤2中提到过ES每隔一段时间就会刷新buffer,这个刷新的动作会在内存中创建一个全新的index segment,并将buffer中的document数据全部到这个新的index segment中。值得注意的是,index segment同样是文件,只不过我们目前访问的是内存中的File(ES底层使用java开发,new File()后文件会被读取到内存当中)。
    segment中存储的是buffer指定时间间隔内接收到的document写操作数据(因为Disk与内存有速度差,为了让数据持久化落盘的速度适应数据写入内存的速度,我们使用了buffer,index segment,比如数据写入了10秒,默认每秒刷新一次buffer,则产生10个index segment,而来得及写入Disk的index segment可能只有2个)。此外 ,index segment已经是新增数据被处理成倒排索引后的数据结果了。
  3. 在index segment被创建并写入了来自buffer的数据后,ES会立刻将index segment对应的File写入到系统缓存OS Cache中并打开,这样就可以立刻为客户端提供最新数据的请求服务,而不必等待index semeng写入到磁盘后,再打开index segment。毕竟IO操作是一个重量级的操作,非常费时,一定会影响ES的近实时搜索能力。
  4. 前面说了,translog中记录的是ES操作的过程,万一遇到系统宕机,在系统重启后,ES会重新读取磁盘Disk中保存的数据(一份份的 index segment文件)至系统缓存,接着读取translog中的操作日志,并逐条执行,以此来达到恢复数据的目的。ES默认每隔5秒执行一次translog文件的持久化。如果在持久化的过程中恰好ES在做document写操作,那么本次持久化操作将暂停,直到写操作彻底完成后,才继续执行。translog的持久化方式默认同步,如果修改成异步,那么在translog持久化的过程中新执行的写操作对应的日志就会丢失,如果恰好此时ES所在的服务器宕机,那么这段时间还没来得及持久化到Disk,仅位于内存中index segment或OS Cache缓存中的数据便无法恢复,永久丢失。
PUT index_name
{
  "settings": {
    "number_of_shards": 5,
    "number_of_replicas": 1,
    "index.translog.durability" : "async",
    "index.translog.sync_interval" : "5s"
  }
}
  1. 随着时间的推移,translog文件会不断的增大,在内存中积压的数量众多的index segment file的文件流也在不断的增大,当translog文件大到一定程度或默认30分钟执行一次,ES会自动触发commit操作。commit操作的具体内容有:
    1. 将buffer中的数据刷新到一个新的index segment中;
    2. 将index segment写入到OS Cache并打开index segment为搜索提供服务;
    3. 执行一个commit point操作,将OS Cache中所有的index segment标识记录在这个commit point中,并持久化到系统磁盘Disk;
    4. commit point操作会触发fsync操作(file sync),将内存中已经写入数据的index segment落盘到Disk,持久化成文件。
    5. 清空本次持久化的index segment对应在translog中的日志。
  2. 按照上述的流程来看,每1秒会生成一个index segment文件,每30分钟会将index segment文件流持久化到磁盘,照这样来看,磁盘中的index segment文件会非常多,从而需要处于开启状态的index segment也非常多,在执行搜索操作时,找到数据对应的index segment就会比较费时了。为了解决这个问题,ES会自动的执行segment merge操作,merge时,被标记为deleted状态的document会被物理删除。
    merge的大致流程如下:
    1. ES会选取一些大小相近的segment文件流,合并成一个大的segment文件流(注意: segment可能是尚未持久化到磁盘的segment file,也可能是已经持久化到磁盘的segment file)。
    2. 执行commit操作,在Disk中记录commit point,这个commit point不仅包含新增的segment,还包含合并后,需要被删除的segment源文件的标识。
    3. commit操作结束后,ES会将merge后的segment文件重新打开,为搜索提供服务,而那些旧的需要被删除的segment文件则进行关闭并物理删除。

此外,ES在执行search搜索时,目标数据可能位于不同的index segment上,因此ES会扫描所有已经开打的index segment文件并找到目标数据。文件打开指的是将数据读到了OS Cache系统缓存,而不是内存中。

对index执行document的删除和更新操作都不会立刻生效,而是标记成deleted状态。当ES空闲(比如每隔30分钟执行一次commit)或Disk存储空间不足,ES就会物理删除这些待删除的数据。(猜测在内存不足时,也会执行删除操作,因为总不能让尚未落盘的index segment大量的占用内存吧)

在buffer数据写入到segment的同时,会生成一个.del文件专门记录哪一个index segment中哪一条document是deleted状态(在merge后,这个.del文件会被更新)。因此ES搜索时,如果在多个index segment中查到了不同版本(version)的相同id值的document时,会根据.del文件中的记录来继续过滤,保证搜索结果的唯一性和正确性(比如segment1中包含一条document version=1,对应新增状态;而segment2中包含相同id的document version=2,对应更新状态。由于后者的版本号更新,因此在.del中,version1被视作旧document,会被标记成deleted状态,从而在搜索时就会得到segment2中包含的version=2的数据了)。

注意:

  1. buffer和尚未写入系统缓存的index segment(就是一段倒排索引)存储在堆内存,受jvm参数控制。
  2. 系统缓存 OScache在这里可以被看做是"文件系统缓存",用于缓存打开后的segment file(段文件),存储在非堆内存,受操作系统控制。

非堆内存越大,能够打开并缓存的segment file(段文件)就越多,搜索和聚合时,能够直接从内存中获取的热数据也就越多(不需要通过IO,在磁盘中找到尚未打开的segment file,读取文件内容)。

搜索数据时,首先在OS Cache中进行搜索,如果找不到数据,则在磁盘中找到对应的index segment文件并打开,读取数据至堆内存中(ES由java开发,因此一定是读取到堆内存,而不是OS Cache),接着,在堆内存中对数据进行聚合、排序等操作,最后把数据返回给协调节点,最终交给调用方。此外,新读取到堆内存的segment file会被Lucense缓存至OS Cache中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章