ES索引刷新-近实时搜索
零、省流版本
ES的数据更新依赖于被刷新到磁盘的段,每个段都会记录自上一次提交以来记录的文档的删除以及修改,并最终在写入磁盘时生效。为减少段的数量,ES会定期进行段合并。
这意味着,ES只有当内存中的段被持久化到磁盘上并产生提交点时,这部分数据才能被检索到。当刷新操作产生时,段将会被提交,索引会定期自动刷新,同时也可以通过命令手动触发。
一、分片与分段
我们在创建一个ES索引的时候通常会根据需要设置索引的分片数以及分片的副本数,其中,分片数表示这个索引的数据将会被水平拆分成几部分,副本数则表示这个分片会同时有几个备份。需要注意的是,分片的副本在检索时会起到与主分片完全相同的作用,也就是说,分片的副本数越多,这个索引能承担的搜索并行度也就越多,但是副本数的增多也会提高对网络带宽以及存储的消耗,实际设置时需要自行取舍。
索引与分片的比较
被混淆的概念是,一个 Lucene 索引我们在 Elasticsearch 称作 分片。 一个 Elasticsearch 索引 是分片的集合。 当 Elasticsearch 在索引中搜索的时候, 他发送查询到每一个属于索引的分片(Lucene 索引),然后像 执行分布式检索 提到的那样,合并每个分片的结果到一个全局的结果集。
分片数仅可以在创建索引时设置,副本数则可以动态调整。
例如,下图是一个3分片2副本的ES索引,它建立在一个3节点的集群中。
我们知道倒排索引是不可变的,不可变当然有很多好处,例如:
- 不需要考虑并发问题,也就不需要锁。
- 由于索引不会改变,所以一旦缓存就能够保证后续请求到索引的数据不会查询磁盘,提高性能。
- 不需要重建缓存,因为数据不会发生变化。
但是不可变会有很多缺点,比如最重要的是对文档的更新或者删除如何体现到倒排索引中?ES的解决方案是,用更多的索引,通过新的索引来补充最近的修改,每一个倒排索引都是分片中的段。
二、更新不可变的数据-追加索引
ES对改变的策略是用新的索引来补充数据的变化,当数据的检索发生的时候,每一个倒排索引都会被检索并返回自己保存的结果,数据的变化则是会在结果合并时被体现。
增加文档
新的文档会首先被存储在内存的段中,此时这个文档对检索是不可见的,内存中的段会不定时的被提交,此时这个段会被写入到磁盘,同时可以被检索到。
删除文档
当我们进行删除文档的操作时,这个文档并不会被立即删除,而是在.del文件中将这个文档标记为已删除,也就是说在进行检索的时候,这个文档仍然会被检索到,只是在分片进行数据合并时会过滤掉这个数据,数据真正的删除发生在段合并的时期。
更新文档
文档的更新会使用版本的概念,当更新请求到达时,ES会根据新的内容创建一个新的文档,然后更新版本号,随后旧的文档将会被标记为删除,新的文档被加入到索引当中。在段合并发生之前,进行检索时仍然会检索到旧的文档,就是新旧文档会同时在段中被搜索到,分片进行数据合并时会过滤掉旧的文档。
段的提交与创建
段的提交流程大致如下所示:
- 新的段被写入磁盘
- 包含新的段的名字的提交点被写入磁盘
- 磁盘进行同步,将文件系统缓存的数据刷入磁盘
段创建的时机与索引刷新以及配置相关:
- 基于段合并:当触发了段合并的操作时,ES会创建一个相对较大的段来合并小段。
- 基于索引刷新:当索引刷新时,会将旧的段提交并写入到文件系统的缓存,同时在内存中创建一个新的段用于存储新增的数据。
段和提交点的关系如下图所示,提交点中包含了所有已提交的段的信息,以及文档的更新删除等信息
段的作用
如果每个分片只有一个索引,那么每当修改(添加,更新,删除)产生时,就需要重建整个索引,这样从修改产生到能被检索到修改的过程就会比较长。
分段使得每个段都是完成的倒排索引,修改文档时就不需要对旧的索引进行更新,极大的缩短了修改产生到可以被检索到的时间。只要段完成了提交,就可以被检索到。
三、近实时搜索
轻量级提交
通过对分片中的数据进行分段,进一步水平拆分数据,使得从添加数据到数据能被检索到的延迟进一步被降低了,但是还不够快,因为段的提交的最后一步:磁盘同步仍然是一个很重的操作,如果在每次索引一个新的文档的时候就执行一次磁盘同步会对性能造成很大的损失。
为了解决这个问题,ES使用了更轻量级的解决方案,先把数据写入到文件系统缓冲区中,此时虽然还没有同步到磁盘中,但是已经可以被打开和读取数据了。
Lucence允许在一次完整的提交尚未完成时就对搜索可见,也就是在文件被写入缓冲区时就能被检索到,同时文件写入到缓冲区是一个轻量级操作,它的代价比同步到磁盘小的多,可以被频繁的执行。
刷新API
通过轻量级操作写入和打开一个段的过程叫做刷新,默认情况下分片会每秒自动刷新一次,这使得文档的变化在一秒内会变为可见,但并不是立即可见的。
除去配置的自动刷新以外,还可以通过下面的API手动刷新索引的数据。尽管刷新是比提交轻量的操作,它仍然有性能的开销,因此在生产环境应当避免手动刷新,尽量通过合理的自动刷新配置来进行。
这是ES近实时搜索的特性,应当理解并接受它,而不是强迫它成为实时的。
POST /_refresh 刷新所有的索引
POST /index/_refresh 只刷新目标索引