ElasticSearch 的写索引逻辑涉及多个步骤,从数据写入到内存缓冲区(buffer),再到刷新到磁盘,最后进行段合并(segment merging)。
写入索引的详细流程
接收文档:
- 当一个文档被写入 ElasticSearch 时,首先通过 REST API 接收这个文档。
分片选择(Primary Shard Selection):
- ElasticSearch 集群中的每个索引被分成多个分片(shards),每个分片有一个主分片(primary
shard)和多个副本分片(replica shards)。文档根据文档 ID 通过哈希函数分配到一个主分片。
写入内存缓冲区(Buffer):
- 文档被写入内存缓冲区(buffer)和事务日志(translog)。内存缓冲区用于暂存数据,而事务日志用于确保数据持久性,防止在系统崩溃时数据丢失。
刷新到磁盘(Refresh):
- 内存缓冲区中的数据在一定时间间隔(默认1秒)或达到一定大小时,会被刷新到磁盘。这一过程会生成一个新的段(segment)。段是一种不可变的倒排索引,包含文档数据、倒排索引和其他元数据。
- 刷新操作会清空内存缓冲区,但事务日志不会立即清空,以确保数据的安全性。
提交和清空事务日志(Commit and Translog Truncation):
- 定期(默认30秒)或在事务日志达到一定大小时,ElasticSearch 会执行提交操作,将内存缓冲区中的所有数据持久化到磁盘,并清空事务日志。提交操作会生成一个 commit point,标识当前所有段的状态,确保数据的一致性和持久性。
段合并(Segment Merging):
-
随着时间推移,ElasticSearch 会生成越来越多的小段。为了优化查询性能,ElasticSearch 会周期性地将多个小段合并成一个大段。这一过程称为段合并(segment merging)。
-
段合并过程中,已删除的文档和重复数据会被清理,优化存储空间和查询效率。段合并的策略涉及段的大小、段的数量和删除标记的比例等因素。
写入流程示例
假设有一个索引 my_index,该索引包含两个分片 shard1 和 shard2。以下是一个文档写入过程的详细示例:
接收写入请求:
- 文档 {“user”: “Alice”, “message”: “Hello, ElasticSearch!”} 被写入索引 my_index。
选择主分片:
- 通过哈希函数计算文档 ID,决定该文档被分配到 shard1。
写入内存缓冲区和事务日志:
- 文档被写入 shard1 的内存缓冲区和事务日志。
刷新操作:
- 在定期刷新或缓冲区满时,shard1 的内存缓冲区数据被刷新到磁盘,生成一个新的段 segmentA。
提交和清空事务日志:
- 定期或在事务日志达到一定大小时,执行提交操作,将所有段的状态持久化,并清空事务日志。
段合并:
- 随着 shard1 中段的数量增加,ElasticSearch 会将多个小段 segmentA、segmentB、segmentC
合并成一个大段 segmentD,清理已删除的文档和重复数据。
写入过程中涉及的组件
内存缓冲区(Buffer):
- 用于暂存新写入的文档,提供快速写入能力。
事务日志(Translog):
- 确保数据的持久性,防止系统崩溃时数据丢失。
段(Segment):
- 不可变的倒排索引,包含文档数据、倒排索引和元数据。
主分片和副本分片(Primary and Replica Shards):
- 主分片接收和处理写入请求,副本分片用于数据冗余和故障恢复。
解释
- 主分片(Primary Shard):负责存储数据和处理写操作。每个索引在创建时会指定主分片的数量。
- 副本分片(Replica Shard):主分片的复制品,用于提供数据冗余和故障恢复。副本分片还可以分担查询负载,提高查询性能。副本分片的数量可以动态调整。
- 索引:在一个 ElasticSearch 集群中,可以创建多个索引,每个索引存储不同类型的数据。例如,可以有一个索引用于存储用户数据(users_index),另一个索引用于存储日志数据(logs_index)。
- 分片:是索引的子集,用于将数据分布在多个节点上。每个索引可以包含多个分片。
- 段:是分片的子集,用于存储具体的文档数据。每个分片可以包含多个段。