一:近实时搜索原理
先认识几个基本概念:
1、segment
es基本存储单元是shard,index分散在多个shard上。 而每个shard由多个段-segment组成,每次创建一个新Document(一条新数据),就会归属于一个新的segment。 删除数据时,也不会直接删除当前segment,只是标记为已删除状态,后续在合适时机删除。
2、translog
操作日志,用来记录操作动作,防止数据丢失。 每个shard中对应一个translog文件。
3、commit
提交,意味着将多个segment,合并成新的更大的segment,并刷入磁盘。
4、refresh
es索引数据时,先是写入到内存buffer中,默认1s执行一次refresh操作,刷新到一个新的segment中,在segment中数据才具备被检索的结构,才能被查询。当写入segment后,会清空内存buffer。 所以近实时搜索通常指的是: 写入数据1s后才能被检索。
当然,可以改变默认时长(时长为-1代表关闭刷新):
PUT /mytest/_settings
{
"refresh_interval": "20s"
}或者直接调用refresh的api:
POST /_refresh 刷新所有索引
POST /mytest/_refresh 刷新某个索引
PUT /mytest/_doc/1?refresh=true //刷新具体文档数据
{
"test": "test"
}5、flush
数据清洗,将内存缓冲区、segments中、translog等全部刷盘,成功后清空原数据和translog。
默认每30分钟执行一次,或者translog变大超过设定值后触发。
commit需要一个fsync同步操作来保证数据物理的被成功刷盘,假如每一个写操作都这样,那么性能会大大下降。 es在内存buffer与磁盘之间,引入了文件系统缓存。 refresh将数据刷到新的segment,这些segment其实是先存在于文件系统缓存,后续再刷盘。
整体流程:
当es收到写请求后,数据暂时写入内存buffer,并添加translog。默认1s后,refresh数据到file system cache,并清空内存buffer。 30分钟后,执行flush刷数据到磁盘(tanslog大小超过设定阈值也会执行flush)。
分片默认会30分钟执行一次flush,也可手动调用api:
POST /mytest/_flush 刷新某一个索引
POST /_flush?wait_for_ongoin 刷新所有索引直到成功后返回(手动调用flush情况很少,不过要关闭索引或者重启节点时,最好执行一下。因为es恢复索引或者重新打开索引时,它必须要先把translog里面的所有操作给恢复,所以也就是说translog越小,recovery恢复操作就越快)
上面说了数据的流程,现在看看translog是如何工作的?
当数据被refresh期间,新的操作日志会继续追加到translog,默认每次写请求(如 index, delete, update, bulk)都会刷盘。 这样会有很大的性能问题,所以如果能容忍5s内的数据丢失情况,还是使用每5s异步刷盘的方式。
配置如下:
PUT /mytest/_settings
{
"index.translog.durability": "async",
"index.translog.sync_interval": "5s"
}要保证完全可靠,还是使用默认配置:
PUT /mytest/_settings
{
"index.translog.durability": "request"
}
流程图:
二: 段合并机制
在索引数据过程中,每一次的refresh都会创建新的segment,数量会越来越多,影响内存和CPU运行,查询也会在多个段中,影响性能。
所以,es会使用