1. 倒排索引组成结构以及其索引不可变原因
1.1 倒排索引的结构
- 包含这个关键词的document list
- 包含这个关键词的所有document的数量: 【IDF】
- 这个关键词在每个document中出现的次数: 【TF】
- 这个关键词在这个document中的次序
- 每个document的长度: 【length norm】
- 包含这个关键词的所有document的平均长度
1.2 倒排索引不可变的好处
- 不需要锁,提升并发能力,避免锁问题
- 数据不变,一致保存在os cache中
- filter cache一直留在内存
- 可以压缩,节省cpu和io开销
- 坏处:每次都要重新构建整个索引
2. Document写入原理
- 关键词
- buffer
- commit
- segment
- os cache
- os disk
2.1 写入过程
- 数据写入buffer
- commit point
- buffer中的数据写入新的index segment
- 等待在os cache中的index segment被fsync强制刷到磁盘os disk上
- 新的index segment被打开,供search使用
- buffer被清空
2.2 删除过程
- 每次commit时会生成del文件
- 表明哪个index segment中的哪个document被删除了
- 假设 del中,doc id=1被删除了
- 搜索请求过来,在index segment中,匹配到了id=1的doc,此时会发现在del文件中已经被标识为deleted了,这种数据就会被过滤掉
2.3更新过程
- 将现有的doc标记为deleted
- 然后将新的document写入新的index segment中
- 下次search过来时,将匹配到一个document的多个版本
- 但之前的版本已经标记为deleted了
- 最终只返回最新版本的doc
3. 优化写入流程实现NRT
-
关键词
- filesystem
- cache
- refresh
-
问题:每次等待fsync 写到磁盘才可以写入,中间等待写磁盘很慢,所以以上写入流程有问题
3.1 改进版-写入流程
- 数据写入buffer中
- 每隔一段时间(1s),将buffer写入新的index segment
- 每秒都会产生新的index segment
- index segment立即被刷到os cache中
- 立刻就可以被打开搜索
- 数据写入os cache,并被打开供搜索的过程,叫做refresh
- 手动refresh
post /my_index/_refresh
- 如果时效性比较低,只要求一条数据写入es,一分钟后才被搜索可以调整
#PUT /index
{
"settings":{
"refresh_interval":"30s"
}
}
4. 写入流程实现durability可靠存储
- 关键词
- translog
- flush
- 问题:以上优化版本仅仅将数据写到了os cache中,如果机器宕机将使es变得不可靠
4.1 改进版-写入流程
- document将数据写入buffer中,同时将document写入translog日志文件中
- 每秒写入一个新的index segment file中
- 立即将index segment file 写入 os cache,并打开供搜索
- 将buffer清空
- 此时,os cache、translog会不断累积变大
- 当累积到一定程度,触发commit
- 将会写一个commit point文件到磁盘上,标明有哪些index segment
- 然后将os cache刷到os disk中去
- 清空os cache、translog日志文件
- fsync+清空translog,就是flush,默认每隔30分钟flush一次,或者当translog过大时也会flush
4.2 基于translog和commit point进行数据恢复
- os disk中存放了上一次 commit point位置,所有segment file都fsync到磁盘中
- 机器被重启,disk总数居没有丢失
- 此时会见translog文件中的变更记录进行回访,重新执行之前的各种操作,在buffer中执行
- 重新写入一个个的segment
- 等待下一次commit即可
4.2.1 translog的存储方式
- translog每个5秒被fsync一次到磁盘上
- 再一次增删改操作之后,当fsync在primary shard和replica shard都成功之后,那次增删改才会成功
- 这种一次增删改强行fsync translog可能会导致部分操作比较耗时
- 如果可以容忍5秒数据丢失即可设置:
- 可以通过设置异步fsync translog
PUT /index/_settings
{
"index.translog.durability":"async",
"index.translog.sync_interval":"5s"
}
5.最后优化写入流程实现海量磁盘文件合并
- 关键词
- segment merge
- optimize
5.1 合并过程
- 选择大小相似的segment进行合并成一个大的
- 将合并的segment flush到磁盘上去
- 写入新的commit point,包括了新的segment,并且排除旧的那些segment
- 将新的segment打开供搜索
- 将旧的segment进行物理删除
- 手动执行合并
POST /index/_optimize?max_num_segments=1