ES 文档索引流程

Elasticsearch 是一个分布式搜索和分析引擎,涉及多个流程来确保数据的可靠性、一致性和高性能。这里将深入讲解 Elasticsearch 索引数据的底层实现,包括刷盘、Translog、主从分片复制、路由等过程。

1. 索引数据的基本流程

  • 客户端请求:当客户端发送一个索引请求时,Elasticsearch 首先需要确定将数据写入到哪个节点和哪个分片上。
  • 路由(Routing):Elasticsearch 根据文档的 ID 和索引的分片数量,通过哈希算法决定将文档分配到哪个主分片上。路由公式为:scssCopy codeshard = hash(document_id) % number_of_primary_shards
  • 这保证了数据在不同分片上的均匀分布。

2. 主分片写入

  • 数据写入主分片:一旦路由确定了主分片,文档首先被写入到主分片上。
  • 写入内存缓冲区(Buffer):文档会先写入一个内存缓冲区,这个缓冲区是一个内存中的数据结构,用于暂存写入数据。
  • 写入 Translog:同时,数据也会被写入到 Translog(事务日志),以确保数据的持久性。即使系统在数据写入内存缓冲区后崩溃,仍然可以通过 Translog 恢复数据。

3. Translog 机制

  • Translog 是什么?
    • Translog 是一个顺序追加的日志文件,记录每次的写操作(包括创建、删除、更新等)。
    • 它的作用是确保数据不丢失,即使节点在数据写入内存后发生故障,也能通过 Translog 恢复未刷盘的数据。
  • 刷盘策略(Flush Policy)
    • 默认情况下,Elasticsearch 会每隔 5 秒将内存缓冲区中的数据刷新到文件系统缓存中,同时重置 Translog 文件。
    • 当 Translog 达到一定的大小(默认 512 MB)时,也会触发刷盘。
  • 刷盘(Flush)和刷写(Fsync)
    • Flush:将内存中的数据和 Translog 刷新到磁盘,并创建一个新的段文件。
    • Fsync:将 Translog 文件同步到磁盘以确保持久性,即将 Translog 写入磁盘。

4. 主从分片复制

  • 在数据被写入主分片后,Elasticsearch 会将写操作转发给副本分片(Replica Shards)。
  • 副本分片在接收到写请求后,重复主分片的写入过程,包括写入内存缓冲区和 Translog。
  • 一致性检查(Quorum Write)
    • 默认情况下,写操作必须在主分片和至少一个副本分片上成功后才会被认为是成功的。
    • 可以通过 wait_for_active_shards 参数配置写操作需要等待的活动分片数。

5. 段文件合并(Segment Merging)

  • 段文件(Segments) 是 Lucene 存储数据的最小单位,每次刷盘会生成一个新的段文件。
  • 合并策略:随着段文件的增多,Elasticsearch 会定期进行段文件合并,以减少段文件数量和提高查询效率。
  • 合并过程:合并过程在后台进行,将多个小的段文件合并成一个大的段文件,同时清理已删除的文档(即标记为删除但仍占用空间的文档)。

6. 路由和分片的扩展性

  • 在初始化索引时,可以指定索引的主分片数量。这是一个固定的值,后期不可更改。
  • 每个主分片可以有多个副本分片,副本分片的数量可以动态调整。
  • 这种设计使得 Elasticsearch 能够在分布式环境中保持高扩展性,同时保证数据的冗余和可用性。

7. 数据一致性和冲突处理

  • 写操作冲突处理:Elasticsearch 使用版本号(Versioning)机制来处理写操作的冲突。当多个写请求同时修改同一个文档时,Elasticsearch 会根据版本号来判断哪个修改是最新的,以确保数据一致性。
  • 读写一致性:Elasticsearch 默认提供 最终一致性,在主分片成功写入数据后,副本分片会进行同步更新。

8. 刷盘和数据安全性

  • 异步刷盘:Elasticsearch 的刷盘是异步的,这意味着数据在内存缓冲区和 Translog 中提交后,写操作会立即返回,但数据并未完全写入磁盘。
  • 数据丢失风险:在异步刷盘的过程中,如果节点崩溃,可能会丢失部分未刷盘的数据。但通过 Translog 恢复机制,可以最大限度地减少这种丢失。

9. 主从复制的分片恢复

  • 复制(Replication):主分片在写操作完成后,会向所有的副本分片发送写入请求。副本分片成功写入后,主分片才会返回成功。
  • 分片恢复(Shard Recovery):当某个节点发生故障后,Elasticsearch 会自动将分片恢复到其他节点上,副本分片可以被提升为新的主分片,确保数据的高可用性。

总结

  • 路由:通过哈希算法确定分片位置,保证数据均匀分布。
  • 主从分片复制:保证数据冗余和高可用,使用副本分片的同步更新机制。
  • 刷盘和 Translog:通过 Translog 记录和刷盘机制确保数据的持久性和一致性。
  • 段合并:定期合并段文件以提升查询性能。

Elasticsearch 的设计思路是通过分布式存储、异步写入、事务日志等机制,确保数据高可用、高性能和最终一致性。

默认情况下,Elasticsearch 会在 1秒 内自动刷新(flush)内存缓冲区中的数据到新的段文件,并且使其可被搜索。这个过程被称为 自动刷新(Auto Refresh)

1. 自动刷新间隔是 1 秒

  • Elasticsearch 的默认刷新时间间隔 (index.refresh_interval) 为 1 秒
  • 这意味着在数据写入索引成功后,Elasticsearch 内存缓冲区中的数据会在 1 秒内写入新的 Lucene 段,并标记这些段为可搜索。

2. 索引到可搜索的 1 秒延迟

  • 默认情况下,从文档写入成功到文档变得可被搜索之间存在 1 秒的延迟。这是因为在刷新之前,数据仍然存在于内存缓冲区和 Translog 中,尚未写入 Lucene 段。
  • 刷新之后,内存缓冲区中的数据会被提交为新的段文件,使得这些数据可以被查询。

3. 为什么会有延迟?

  • 批量写入优化:Elasticsearch 为了提高写入性能,并不会在每次写入操作后立即将数据刷到磁盘。这是为了避免频繁的磁盘 I/O 开销,提高写入效率。
  • 段合并的性能考量:频繁的刷新会导致大量小段文件的生成,这会增加 Lucene 的段合并压力,降低系统性能。
  • 最终一致性设计:Elasticsearch 采用最终一致性模型,而不是强一致性模型,因此允许这种 1 秒的延迟来平衡写入和查询的性能。

4. 如何调整刷新频率

  • 你可以通过设置 index.refresh_interval 参数来调整刷新频率,例如:bashCopy codePUT /index_name/_settings { "index": { "refresh_interval": "5s" // 将刷新间隔设为5秒 } }
  • 如果设为 -1,则会禁用自动刷新,这在批量写入时可以极大提升写入速度,但在禁用刷新期间,数据不会立即可搜索。

5. 手动刷新(Manual Refresh)

  • 在一些需要确保写入数据立即可见的场景下,可以手动调用 _refresh API 来强制刷新数据。
  • 例如,在测试环境或者某些需要实时搜索的情况下,手动刷新可以确保数据的即时可见性,但会增加 I/O 开销。

6. Translog 和持久化

  • 数据写入后,首先会记录到 Translog(事务日志),Translog 是同步刷到磁盘的,这保证了数据的持久性。
  • 刷新过程并不会清空 Translog,它主要是将数据从内存写入到 Lucene 段,只有在执行完全的 flush 操作时才会清空 Translog。

总结

  • 默认刷新时间是 1 秒,这导致了索引成功到数据可搜索之间可能有 1 秒的延迟。
  • 该延迟是为了优化写入性能,同时减少频繁刷新的 I/O 负担。
  • 可以通过调整 index.refresh_interval 参数来平衡写入性能和数据的可见性。

在 Elasticsearch 中,数据的写入到持久化存储的过程涉及多个步骤,包括写入内存缓冲区、写入事务日志(Translog)、刷新到 Lucene 段(segment)等。下面详细讲解这些步骤的执行顺序和原理。

1. 写入内存缓冲区和 Translog

  • 当客户端发送一个写入请求(如 indexupdate 操作)时,Elasticsearch 首先会将数据写入到 内存缓冲区Translog
  • 内存缓冲区:这是一个内存中的数据结构,用于暂存写入的数据。
  • Translog(事务日志):是一个顺序追加的日志文件,用于记录每次的写操作。写入 Translog 是为了确保数据的持久性,即使系统崩溃,也能通过 Translog 恢复未刷盘的数据。
  • 在数据写入内存缓冲区和 Translog 后,写入操作被认为是成功的,并返回给客户端。

2. 刷盘(Flush)到 Lucene 段

  • 内存缓冲区中的数据需要刷新到 Lucene 段(segment) 中,段是 Lucene 存储和搜索的最小单元。
  • 刷盘(Flush)是将内存缓冲区中的数据持久化到磁盘的一种操作。Flush 并不是立即执行的,而是基于以下几种触发条件:
    • 自动刷新(Auto Refresh):默认每秒自动刷新一次(由 index.refresh_interval 控制),将内存缓冲区中的数据写入 Lucene 段。
    • 段合并(Segment Merging):段合并是后台的异步操作,将小段合并成更大的段,以减少段的数量,提高搜索效率。
    • Flush 操作:当 Translog 达到一定大小时(如默认 512MB),或者系统负载较高时,会触发一个完全的 Flush 操作,将所有内存缓冲区数据写入段,并清空 Translog。

3. 具体执行顺序

  1. 写入内存缓冲区和 Translog
    • 当数据写入时,Elasticsearch 会同时将数据写入内存缓冲区和 Translog。
    • 内存缓冲区存储的是当前未持久化的数据,而 Translog 用于日志恢复和持久化保障。
  2. 刷盘到 Lucene 段
    • 默认每秒会执行一次自动刷新,将内存缓冲区中的数据刷入新的 Lucene 段,并标记这些段为可搜索。
    • 此时,数据在内存缓冲区中被持久化到磁盘,形成新的 Lucene 段,这意味着它在崩溃恢复时不再依赖 Translog。
  3. 清空 Translog
    • 完全的 Flush 操作不仅将内存缓冲区的数据写入段,还会清空 Translog,以释放存储空间。
    • Flush 操作的触发条件可能是 Translog 达到一定大小或内存使用达到一定阈值。

4. 底层细节

  • 写入内存缓冲区和 Translog 的顺序
    • 内存缓冲区和 Translog 是并行写入的。Elasticsearch 使用多线程处理写操作,以保证高并发性能。
    • 写入 Translog 时,Elasticsearch 会使用 fsync 将数据写入磁盘,确保数据的持久性。
  • 自动刷新(Auto Refresh)
    • 每秒刷新一次,将内存缓冲区的数据写入 Lucene 段。这使得写入的数据在 1 秒内可被搜索。
    • 自动刷新不会清空 Translog,只是创建新的 Lucene 段文件,使数据可见。
  • Flush 和完全刷盘(Complete Flush)
    • 完全刷盘会写入所有内存缓冲区的数据到段,并重置 Translog。
    • 这在段文件合并或集群重启时尤为重要,可以保证持久化数据与日志数据的一致性。

5. 为什么存在延迟?

  • 默认的 1 秒自动刷新间隔是为了在性能和数据可见性之间取得平衡。如果每次写入都立即刷新,系统性能会大幅下降。
  • 延迟的原因主要是为了将更多的写入合并到一次刷新操作中,减少频繁写磁盘的开销,提高整体写入性能。

6. 总结

  • 写入顺序:先写入内存缓冲区和 Translog,再刷新到 Lucene 段,最后完全 Flush 清空 Translog。
  • 自动刷新间隔:默认 1 秒,导致索引成功到可搜索有 1 秒的延迟,这是为了优化写入性能。
  • 数据安全:即使在内存缓冲区的数据丢失时,仍可通过 Translog 恢复未刷盘的数据。

这种多步骤、多层次的数据写入和持久化机制,确保了 Elasticsearch 在高并发写入场景下,既能保证写入性能,又能提供较强的数据一致性和持久性。

0 0 投票数
Article Rating
订阅评论
提醒
guest
0 评论
最旧
最新 最多投票
内联反馈
查看所有评论
0
希望看到您的想法,请您发表评论x