"这就是 Elasticsearch 脱颖而出的地方:Elasticsearch 鼓励你去探索与利用数据,而不是因为查询数据太困难,就让它们烂在数据仓库里面。 Elasticsearch 将成为你最好的朋友。"
事务日志
上次我们说到,数据会暂时缓存在内存中,在达到一定的条件下一次性写入硬盘中,这种做法可以大大提升数据写入的速度。但是由于,由于数据暂时被缓存在内存当中,并没有真正持久化到硬盘内。这时如果出现断电等不可控的情况,就会丢失数据。为此,ElasticSearch添加了事务日志来解决这个问题。
首先,ES的写索引的具体过程如下:
当有数据写入时,为了提升写入的速度,并没有把数据写在硬盘上,而是先写入到内存中,但是为了防止数据的丢失,会追加一份到事务日志中。

然后,当到达默认刷新时间或者内存数据达到一定的数量时,会触发一次刷新。
刷新的主要步骤如下:
-
将内存中的数据刷新到一个新的段中,但是该段并没有持久化到硬盘中,而是缓存在操作系统的文件系统中。
重点:虽然数据还在内存中,但是内存中的数据与文件系统缓存的数据有以下区别:
- 内存使用的是es-jvm的内存,而文件系统缓存使用的是操作系统的内存。(重要)
- 内存的数据不是以“段”的形式存储的,并且可以继续向内存里写数据。文件系统缓存中的数据是以段的形式存在的,所以只能读,不能写。
- 内存中的数据是搜索不到的,文件系统的数据可以被搜索到。(所以ES不是实时搜索,而是准实时搜索,需要等待内存中的数据被刷新到文件系统缓存后,数据才能被检索到)
- 打开保存文件系统中缓存的段,使其可被搜索。
- 清空内存中的数据,准备接受新的数据。事务日志不做清空处理

其后,会继续重复这个过程

最后,当日志数据超过512MB或者时间超过30分钟(默认),需要触发一次刷新。
与此前不同的是,这次刷新会调用fsync函数将文件系统缓存的数据刷新到硬盘上,并清空事务日志。

小结
由上面的索引创建步骤可知,索引在写入时并没有直接写入硬盘,而是先缓存到操作系统的文件系统缓存中去。同时使用事务日志来防止ES服务挂掉后重新启动后的在缓存数据的重新索引:事务日志提供所有还没有被刷到磁盘的操作的一个持久化纪录。当 Elasticsearch 启动的时候, 它会从磁盘中使用最后一个提交点去恢复已知的段,并且会重放 事务日志 中所有在最后一次提交后发生的变更操作。
相关调优
由上文可知,ES在使用过程中,除了使用自身的JVM内存,还需要使用大量文件系统的缓存内存。
- 调优1:部署ES的机器上,除了需要有足够的jvm内存,还需要留有足够的操作系统可用内存。根据经验,最好ES使用只占机器总内存一半。
往 es 里写的数据,实际上都写到磁盘文件里去了,查询的时候,操作系统会将磁盘文件里的数据自动缓存到 filesystem cache 里面去。 es 的搜索引擎严重依赖于底层的 filesystem cache,你如果给 filesystem cache 更多的内存,尽量让内存可以容纳所有的 idx segment file 索引数据文件,那么你搜索的时候就基本都是走内存的,性能会非常高。
- 调优2:ES索引文档的字段尽可能少。
比如说你现在有一行数据。id,name,age .... 30 个字段。但是你现在搜索,只需要根据 id,name,age 三个字段来搜索。如果你傻乎乎往 es 里写入一行数据所有的字段,就会导致说 90%的数据是不用来搜索的,结果硬是占据了 es 机器上的 filesystem cache 的空间,单条数据的数据量越大,就会导致 filesystem cahce 能缓存的数据就越少。其实,仅仅写入 es 中要用来检索的少数几个字段就可以了,比如说就写入 es id,name,age 三个字段,然后你可以把其他的字段数据存在 mysql/hbase 里,我们一般是建议用 es + hbase 这么一个架构。