Elasticsearch 技术分析(九):Elasticsearch的使用和原理总结 (7)

并发将数据复制到两个副本分片R0上,其中通过乐观并发控制数据的冲突。一旦所有的副本分片都报告成功,则节点ES3将向协调节点报告成功,协调节点向客户端报告成功。

存储原理

上面介绍了在ES内部索引的写处理流程,这个流程是在ES的内存中执行的,数据被分配到特定的分片和副本上之后,最终是存储到磁盘上的,这样在断电的时候就不会丢失数据。具体的存储路径可在配置文件../config/elasticsearch.yml中进行设置,默认存储在安装目录的data文件夹下。建议不要使用默认值,因为若ES进行了升级,则有可能导致数据全部丢失。

path.data: /path/to/data //索引数据 path.logs: /path/to/logs //日志记录 分段存储

索引文档以段的形式存储在磁盘上,何为?索引文件被拆分为多个子文件,则每个子文件叫作, 每一个段本身都是一个倒排索引,并且段具有不变性,一旦索引的数据被写入硬盘,就不可再修改。在底层采用了分段的存储模式,使它在读写时几乎完全避免了锁的出现,大大提升了读写性能。

段被写入到磁盘后会生成一个提交点,提交点是一个用来记录所有提交后段信息的文件。一个段一旦拥有了提交点,就说明这个段只有读的权限,失去了写的权限。相反,当段在内存中时,就只有写的权限,而不具备读数据的权限,意味着不能被检索。

的概念提出主要是因为:在早期全文检索中为整个文档集合建立了一个很大的倒排索引,并将其写入磁盘中。如果索引有更新,就需要重新全量创建一个索引来替换原来的索引。这种方式在数据量很大时效率很低,并且由于创建一次索引的成本很高,所以对数据的更新不能过于频繁,也就不能保证时效性。

索引文件分段存储并且不可修改,那么新增、更新和删除如何处理呢?

新增,新增很好处理,由于数据是新的,所以只需要对当前文档新增一个段就可以了。

删除,由于不可修改,所以对于删除操作,不会把文档从旧的段中移除而是通过新增一个.del文件,文件中会列出这些被删除文档的段信息。这个被标记删除的文档仍然可以被查询匹配到, 但它会在最终结果被返回前从结果集中移除。

更新,不能修改旧的段来进行反映文档的更新,其实更新相当于是删除和新增这两个动作组成。会将旧的文档在.del文件中标记删除,然后文档的新版本被索引到一个新的段中。可能两个版本的文档都会被一个查询匹配到,但被删除的那个旧版本文档在结果集返回前就会被移除。

段被设定为不可修改具有一定的优势也有一定的缺点,优势主要表现在:

不需要锁。如果你从来不更新索引,你就不需要担心多进程同时修改数据的问题。

一旦索引被读入内核的文件系统缓存,便会留在哪里,由于其不变性。只要文件系统缓存中还有足够的空间,那么大部分读请求会直接请求内存,而不会命中磁盘。这提供了很大的性能提升。

其它缓存(像filter缓存),在索引的生命周期内始终有效。它们不需要在每次数据改变时被重建,因为数据不会变化。

写入单个大的倒排索引允许数据被压缩,减少磁盘 I/O 和 需要被缓存到内存的索引的使用量。

段的不变性的缺点如下:

当对旧数据进行删除时,旧数据不会马上被删除,而是在.del文件中被标记为删除。而旧数据只能等到段更新时才能被移除,这样会造成大量的空间浪费。

若有一条数据频繁的更新,每次更新都是新增新的标记旧的,则会有大量的空间浪费。

每次新增数据时都需要新增一个段来存储数据。当段的数量太多时,对服务器的资源例如文件句柄的消耗会非常大。

在查询的结果中包含所有的结果集,需要排除被标记删除的旧数据,这增加了查询的负担。

延迟写策略

介绍完了存储的形式,那么索引是写入到磁盘的过程是这怎样的?是否是直接调 fsync 物理性地写入磁盘?

答案是显而易见的,如果是直接写入到磁盘上,磁盘的I/O消耗上会严重影响性能,那么当写数据量大的时候会造成ES停顿卡死,查询也无法做到快速响应。如果真是这样ES也就不会称之为近实时全文搜索引擎了。

为了提升写的性能,ES并没有每新增一条数据就增加一个段到磁盘上,而是采用延迟写的策略。

每当有新增的数据时,就将其先写入到内存中,在内存和磁盘之间是文件系统缓存,当达到默认的时间(1秒钟)或者内存的数据达到一定量时,会触发一次刷新(Refresh),将内存中的数据生成到一个新的段上并缓存到文件缓存系统 上,稍后再被刷新到磁盘中并生成提交点

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpxjgp.html