关于 ElasticSearch 的一些问题
- 为什么 ElasticSearch 的搜索是近实时的(1s 后被搜索到)?
- ElasticSearch 如何保证在断电时数据也不会丢失?
- 为什么删除文档并不会立即释放空间?
倒排索引的不可变性
- 倒排索引采用了 Immutable Design 模式,一旦生成,不可更改;
不可变性带来的好处
- 无需考虑并发写文件的问题,避免了锁机制带来的性能问题;
- 一旦读入内核的文件系统缓存,便留在那里,只要文件系统有足够的空间,大部分请求就会直接请求内存,不会命中磁盘,提升了很大的性能;
- 缓存容易生成和维护,并且数据可以被压缩;
不可变性带来的挑战
- 如果需要让一个新的文档可以被搜索,需要重建整个索引;
Lucene Index
- 一个 ElasticSearch 中的 Shard 就是 Lucene 中的一个 Index;
- 在 Lucene 中,单个倒排索引文件被称为 Segment;Segment 是自包含的,不可变的;多个 Segment 汇总在一起,称为 Lucene 的 Index;
- 当有新文档写入时,会生成新 Segment;
- 查询时会同时查询所有的 Segments,并且对结果汇总;
- Lucene 中有一个文件,用来记录所有 Segment 信息,叫做 Commit Point;
- 删除的文档信息,保存在 .del 文件中;
什么是 ElasticSearch 中的 Refresh
- 将 Index Buffer 写入 Segment 的过程叫做 Refresh,Refresh 的时候不执行 fsync 操作;
- Refresh 频率:默认 1s 发生一次,可通过参数
index.refresh_interval
配置,Refresh 后,数据就可以被搜索到了;这也是为什么 ElasticSearch 被称为近实时搜索; - 如果系统有大量的数据写入,那就会产生很多 Segment;
- Index Buffer 被占满时,会触发 Refresh,Index Buffer 默认大小是 JVM 的 10%;
什么是 ElasticSearch 中的 Transaction Log
- Segment 写入磁盘的过程相对耗时,借助文件系统缓存,Refresh 的时候,先将 Segment 写入文件系统缓存,以开放查询;
- 为了保证数据不会丢失,在写入文档时,同时写入 Transaction Log,高版本开始,Transaction Log 默认落盘;
- 每个分片有一个 Transaction Log;
- 在 ES Refresh 的时候,Index Buffer 被清空,Transaction Log 不会清空;
- 所以在发生断电的时候,因为有 Transaction Log 的落盘,数据不会丢失;
什么是 ElasticSearch 的 Flash
当发生 Flash 的时候执行的动作
- 调用 Refresh,清空 Index Buffer;
- 调用 fsync,将文件系统缓存中的 Segment 写入磁盘;
- 清空 Transaction Log;
ElasticSearch 的 Flash 是比较重的操作,默认 30 分钟调用一次;另外当 Transaction Log 已经被写满的时候(默认 512M)会发生 Flash;
什么是 ElasticSearch 中的 Merge
随着时间的推移,磁盘中的 Segment 越来越多,需要被定期的合并;
Merge 操作可以做两件事
- 减少 Segment
- 删除已经删除的文档
ElasticSearch 和 Lucene 会自动的做 Merge 操作,如果需要人为的发起 Merge 操作,可以使用 API:POST my_index/_forcemerge
;