ElasticSearch内核原理

1. 倒排索引组成结构以及其索引不可变原因

1.1 倒排索引的结构

  1. 包含这个关键词的document list
  2. 包含这个关键词的所有document的数量: 【IDF】
  3. 这个关键词在每个document中出现的次数: 【TF】
  4. 这个关键词在这个document中的次序
  5. 每个document的长度: 【length norm】
  6. 包含这个关键词的所有document的平均长度

1.2 倒排索引不可变的好处

  1. 不需要锁,提升并发能力,避免锁问题
  2. 数据不变,一致保存在os cache中
  3. filter cache一直留在内存
  4. 可以压缩,节省cpu和io开销
  5. 坏处:每次都要重新构建整个索引

2. Document写入原理

  • 关键词
    • buffer
    • commit
    • segment
    • os cache
    • os disk

2.1 写入过程

  1. 数据写入buffer
  2. commit point
  3. buffer中的数据写入新的index segment
  4. 等待在os cache中的index segment被fsync强制刷到磁盘os disk上
  5. 新的index segment被打开,供search使用
  6. buffer被清空

2.2 删除过程

  1. 每次commit时会生成del文件
  2. 表明哪个index segment中的哪个document被删除了
  3. 假设 del中,doc id=1被删除了
  4. 搜索请求过来,在index segment中,匹配到了id=1的doc,此时会发现在del文件中已经被标识为deleted了,这种数据就会被过滤掉

2.3更新过程

  1. 将现有的doc标记为deleted
  2. 然后将新的document写入新的index segment中
  3. 下次search过来时,将匹配到一个document的多个版本
  4. 但之前的版本已经标记为deleted了
  5. 最终只返回最新版本的doc

3. 优化写入流程实现NRT

  • 关键词

    • filesystem
    • cache
    • refresh
  • 问题:每次等待fsync 写到磁盘才可以写入,中间等待写磁盘很慢,所以以上写入流程有问题

3.1 改进版-写入流程

  1. 数据写入buffer中
  2. 每隔一段时间(1s),将buffer写入新的index segment
    1. 每秒都会产生新的index segment
  3. index segment立即被刷到os cache中
  4. 立刻就可以被打开搜索
  • 数据写入os cache,并被打开供搜索的过程,叫做refresh
  • 手动refresh post /my_index/_refresh
  • 如果时效性比较低,只要求一条数据写入es,一分钟后才被搜索可以调整
#PUT /index
{
    "settings":{
        "refresh_interval":"30s"
    }
}

4. 写入流程实现durability可靠存储

  • 关键词
    • translog
    • flush
  • 问题:以上优化版本仅仅将数据写到了os cache中,如果机器宕机将使es变得不可靠

4.1 改进版-写入流程

  1. document将数据写入buffer中,同时将document写入translog日志文件中
  2. 每秒写入一个新的index segment file中
  3. 立即将index segment file 写入 os cache,并打开供搜索
  4. 将buffer清空
  5. 此时,os cache、translog会不断累积变大
  6. 当累积到一定程度,触发commit
  7. 将会写一个commit point文件到磁盘上,标明有哪些index segment
  8. 然后将os cache刷到os disk中去
  9. 清空os cache、translog日志文件
  • fsync+清空translog,就是flush,默认每隔30分钟flush一次,或者当translog过大时也会flush

4.2 基于translog和commit point进行数据恢复

  1. os disk中存放了上一次 commit point位置,所有segment file都fsync到磁盘中
  2. 机器被重启,disk总数居没有丢失
  3. 此时会见translog文件中的变更记录进行回访,重新执行之前的各种操作,在buffer中执行
  4. 重新写入一个个的segment
  5. 等待下一次commit即可

4.2.1 translog的存储方式

  1. translog每个5秒被fsync一次到磁盘上
  2. 再一次增删改操作之后,当fsync在primary shard和replica shard都成功之后,那次增删改才会成功
  3. 这种一次增删改强行fsync translog可能会导致部分操作比较耗时
  4. 如果可以容忍5秒数据丢失即可设置:
  5. 可以通过设置异步fsync translog
PUT /index/_settings
{
    "index.translog.durability":"async",
    "index.translog.sync_interval":"5s"
}

5.最后优化写入流程实现海量磁盘文件合并

  • 关键词
    • segment merge
    • optimize

5.1 合并过程

  1. 选择大小相似的segment进行合并成一个大的
  2. 将合并的segment flush到磁盘上去
  3. 写入新的commit point,包括了新的segment,并且排除旧的那些segment
  4. 将新的segment打开供搜索
  5. 将旧的segment进行物理删除
  • 手动执行合并 POST /index/_optimize?max_num_segments=1
发布了5 篇原创文章 · 获赞 1 · 访问量 216

猜你喜欢

转载自blog.csdn.net/drama_CJL/article/details/102675180