ES 写入流程
ES是一个底层为Lucene的搜索框架,封装了Lucene的复杂性,写入到ES 的文当是近实时搜索的,原因是Lucene只支持归档的数据才能被搜索到。在ES的话术中搜索是按照段(segment)来搜索的,这样导致一个新的文档从索引到可被搜索的延迟显著降低了。新文档在几分钟之内即可被检索,但这样还是不够快。
磁盘在这里成为了瓶颈。提交(Commiting)一个新的段到磁盘需要一个 fsync 来确保段被物理性地写入磁盘,这样在断电的时候就不会丢失数据。 但是 fsync 操作代价很大; 如果每次索引一个文档都去执行一次的话会造成很大的性能问题。
但幸运的是Lucene支持内存缓存段(segment)。
1,将写入文档缓存
Elasticsearch和磁盘之间是文件系统缓存。 当文档进入之后,会先存放在内存中,这时内存中的文档是不能被search的。
2,将缓存文档写入memory segment
然后ES调用_refresh 将在内存索引缓冲区中的文档会被写入到一个新的或已存在的内存段中(segment)。 可以通过调节 index.refresh_interval 参数,改变ES集群的 _refresh 频率,默认是1s ,也就是说存入的document最晚一秒之后可以被搜索到。
这个进程继续工作,更多的文档被添加到内存缓冲区和追加到事务日志。
3,将memory segment 写入磁盘
如果没有用 fsync 把数据从文件系统缓存刷(flush)到硬盘,我们不能保证数据在断电甚至是程序正常退出之后依然存在。为了保证 Elasticsearch 的可靠性,需要确保数据变化被持久化到磁盘。
我们说一次完整的提交会将段刷到磁盘,并写入一个包含所有段列表的提交点。Elasticsearch 在启动或重新打开一个索引的过程中使用这个提交点来判断哪些段隶属于当前分片。
这个执行一个提交并且截断 translog 的行为在 Elasticsearch 被称作一次 flush 。
flush 的触发可以通过调用 _flush API ,ES内部使用的是translog 的配置改变flush的动作。
4,translog
上面流程中视而不见的一个元素就是Translog。Elasticsearch 增加了一个 translog ,或者叫事务日志,在每一次对 Elasticsearch 进行除read之外的操作时均进行了日志记录。
在文档flush 到磁盘之前,对应的操作保存在 translog上。translog 提供所有还没有被刷到磁盘的操作的一个持久化纪录。当 Elasticsearch 启动的时候, 它会从磁盘中使用最后一个提交点去恢复已知的段,并且会重放 translog 中所有在最后一次提交后发生的变更操作。translog 也被用来提供实时 CRUD 。当你试着通过ID查询、更新、删除一个文档,它会在尝试从相应的段中检索之前, 首先检查 translog 任何最近的变更。这意味着它总是能够实时地获取到文档的最新版本。
translog 的目的是保证操作不会丢失。这引出了这个问题: Translog 有多安全?
Translog 相关配置:
index.translog.durability :( request | async )
request : 默认配置,表示每一个除read操作的请求会将内容写入translog磁盘。
async: 忽略实际的API 操作,对内存的translog内容写入磁盘指定策略。
index.translog.sync_interval:5s
当 index.translog.durability 为async时,设置定时刷新的频率。
index.translog.flush_threshold_size:500mb
会触发 flush 操作,防止translog 过大。