作者:幸运幸福摩天轮的世界 | 来源:互联网 | 2023-06-11 11:59
Elasticsearch学习笔记——索引过程索引不可变和动态索引
es的索引,在落盘之后是不可变,即不可对其进行二次修改,如果想要修改,必须先删除,后重建。但是,在实际应用中,索引的更新又是一个不可避免的问题,所以,es在索引不可变的基础上,又增加了动态索引的特性,来解决索引更新的问题。
先来看看,为什么es要把索引设计成不可变的?
我们知道,es是支持集群的。这就必然涉及到一个多线程多进程的问题。假如索引可变,就必须增加锁的机制。所以,索引不可变的前提了,就不再需要锁了。降低了系统的复杂度。
索引不可变的另一个好处是可以更有效的利用内存。由于索引不可变,当索引一旦被读入内存,它就可以在一直在那儿。只要系统有足够的内存空间,大量的读就可以直接通过访问内存来完成,极大提高系统的性能。
总结来说,不可变有两个好处,一是不用考虑锁,二是高效利用缓存。
但是,不可变也有问题,即每增加新文档的时候,都需要把旧索引全部删除,再重建。所以,es引入了动态索引。事实上,动态索引的本质就是多个索引,即新增文档时,直接生成一个新的索引,查询时,把每个索引的数据都查出来后,再进行聚合处理。这种方式,既保留了索引不可变的优势,又解决了更新的问题。
但是,这种动态索引又产生了一个新的问题,即当新建的索引越来越多时,会影响到聚合的效率,也就会影响到查询的效率。对于这种情况,我们可能会从业务角度来处理。即选择非热点时段,进行索引的重建和切换。当然,es也为这种情况准备了segment合并的策略。
segment
文档经过es处理后,会形成倒排索引,放到es的某个或某几个分片上。所以,es的每个分片上,往往会包含很多个倒排索引,我们把每一个倒排索引,称之为segment,即段。
在查询的时候,es会把所有的segment的查询结果合并汇总成最后的结果再返回。
索引不可变,事实上就是segment不可变。当segment不断增多时,合并汇总的压力会增大,此时,es会触发segment合并的线程,把许多小的segment合并成一个大的segment,并删除原来的小的segment。
translog
如果有了解过MySQL通过重做日志来实现事务的持久化的话,那么,translog对于es的作用,事实上和重做日志对于MySQL事务是一致的。对于es来说,文档也不是直接就放进文件中,而是先会在内存中进行处理,处理成索引信息后,会等到缓冲区满或显示提交时,才会保存到文件中。
那么,如果在保存之前es进程挂掉,如果没有其它机制,就肯定会丢数据。所以,translog来了。即在数据进行索引前,会先写translog日志,该日志是写在文件中的。当es进程出现问题,需要恢复数据时,就会基于translog进行重放日志。这样,就保证了数据的不丢失。
索引的过程
基于上图,我们可以完整整理出一个es对文档进行索引的基本过程,如下:
接收到客户端传过来的文档后,会首先写入translog日志和内存缓冲区。
每隔一秒,缓冲区中的内容会被刷新到filesystem cache中,成为一个新的segment。此时,该segment就会被打开,以便被搜索。这也是es能实现近实时性被搜索的关键。
每秒都有segment刷入,segment数量不断增长,就会触发合并,即将小的segment合并成大的,再合并成更大的,把较小的删除。
最后,把合并成的大的segment写入到磁盘上,就完成了整个文档的索引过程。
四个阶段可以整理成四个关键词:translog -> segment -> 合并 -> 写入。
近实时化搜索
近实时化搜索的含义指的是当写入一个文档后,该文档在很短时间内就可以被通过关键词搜索到。
前面提到,es之所以能达到近实时化搜索的关键是,只要缓存区的内容在filesystem cache中形成segment后,它就能被搜索了。对于于早期的lucene,只有当segment被写入磁盘才能被搜索,简直不要进步的太多。对比会发现,这中间,从开始创建到能被搜索,事实上省掉了磁盘IO。
commit point
直译为提交点,es用它来记录当前所有可用segment,以及被删除的segment。commit point在segment合并阶段,起到帮助合并且维持搜索的作用。每次合并都会通过记录commit point的方式,告诉前来的查询,哪些段是可用的,哪些段是已经被删除的。合并过程大致如下:
选择一些大小相似的segment合并成一个较大的segment。
将新的segment刷到磁盘上。
创建新的commit point,其中,记录了新的segment,并删除的旧的。
将新的segment打开供搜索。
删除掉的segment。
不断变大的translog和flush
回顾es索引文档的过程,你会发现一个问题:如果按些过程不断重复,translog会不断增大。那么,es解决此问题的方式就是——flush。
首先,我们要理解的一点是,translog是为了在es进程异常时,用于恢复尚未持久化的磁盘中的数据用的。也就是说,如果数据已经被持久化到了磁盘中,那么,translog也就没有存在的必要了。
所以,es制定的策略是,每隔30分钟将translog向磁盘中转移一次,转移完成会清空translog。该操作,称之为flush。当translog达到设定的最大值时,即使不到30分钟,也会进行flush。
可以通过配置修改flush的间隔时长以及触发的最大值等。如下:
index.translog.flush_threshold_ops:当发生多少次操作时进行一次flush。默认是 unlimited。
index.translog.flush_threshold_size:当translog的大小达到此值时会进行一次flush操作。默认是512mb。
index.translog.flush_threshold_period:在指定的时间间隔内如果没有进行flush操作,会进行一次强制flush操作。默认是30m。
index.translog.interval:多少时间间隔内会检查一次translog,来进行一次flush操作。es会随机的在这个值到这个值的2倍大小之间进行一次操作,默认是5s。