📣 极限科技诚招搜索运维工程师(Elasticsearch/Easysearch)- 全职/北京 👉 : 立即申请加入

在构建企业级搜索平台时,我们不仅关注“快”,更关注“准”和“稳”。Easysearch 作为一个分布式的 Near Real-Time(近实时)搜索引擎,其核心架构设计解决的最根本问题是:在不可靠的网络和硬件之上,构建一个可靠的数据系统。

本文将深入剖析 Easysearch 分布式架构的三大基石:集群协调模型数据复制模型以及并发控制机制

一、 集群协调:去中心化与共识算法 #

Easysearch 采用的是 P2P(Peer-to-Peer)网络架构,但在元数据管理上采用了 主节点(Master) 负责制的混合模式。这种设计既保证了数据传输的高吞吐,又确保了集群状态的一致性。

1. 选主与脑裂防护(Zen Discovery) #

Easysearch 内部运行着一套名为 Zen Discovery(在较新版本中演进为基于 Quorum 的协调层)的模块,负责节点发现和 Master 选举。

  • 选举机制:集群启动时,各个 master-eligible 节点会相互“Ping”。如果发现没有 Master,它们会根据 Node ID 和配置权重进行投票。只有获得 法定票数(Quorum) 的节点才能当选 Master。
  • 脑裂(Split-Brain)防护
  • 在分布式系统中,网络分区可能导致集群分裂成两个子集群,各自选出 Master,导致数据分叉。
  • Easysearch 严格遵循 minimum_master_nodes(或新版的自动引导机制)原则,要求 N/2 + 1 个节点存活才能进行元数据变更。这从算法层面杜绝了脑裂的发生。

2. Cluster State 的原子性广播 #

Cluster State 是集群的“唯一真理”,包含 Mapping、Settings、路由表等。为了在千节点规模下高效同步状态,Easysearch 做了如下设计:

  • Diff(增量)同步:Master 节点不会每次都广播几 MB 的全量 Cluster State。它会计算当前版本与上一版本的差异(Delta),仅将几 KB 的 Diff 数据发送给其他节点。
  • 两阶段提交(2PC)
  1. Publish:Master 将状态变更发送给所有节点。
  2. Commit:当 Master 收到半数以上节点的 Ack 后,发送 Commit 指令,所有节点同时应用变更。

二、 数据模型:分片、路由与不可变性 #

1. 分片(Shard)即 Lucene 索引 #

Easysearch 的一个 Shard 本质上就是一个 Apache Lucene 索引实例

  • 资源隔离:每个 Shard 是一个独立的搜索引擎,拥有独立的倒排索引、词典和缓存。
  • 限制:由于 Lucene 的设计,一个 Shard 内的文档数有上限(约 21 亿,Integer.MAX_VALUE),且 Shard 越多,元数据开销越大。因此合理的分片规划(如单分片 30GB-50GB)是性能调优的关键。

2. 确定性路由算法 #

文档存放在哪个分片,由以下公式决定:
shard = hash(routing) % number_of_primary_shards

  • routing:默认是文档 ID,也可以自定义(如按 UserID 路由)。
  • 不可变性:这就是为什么索引创建后,主分片数量不能修改的原因。一旦修改,取模公式的结果就会改变,已存的数据就“找不到了”。(注:Easysearch 支持 Split API 裂变分片,但本质是重新创建索引)。

三、 数据复制与一致性模型(Replication & Consistency) #

这是分布式数据库最核心的部分。Easysearch 采用 Primary-Backup(主备) 复制模型。

1. 写入一致性流程 #

不同于 Cassandra 的最终一致性,Easysearch 倾向于保证强一致性(或顺序一致性):

  1. Request:请求到达协调节点。
  2. Primary:请求转发到主分片。主分片验证请求,执行写入,并生成 Sequence ID
  3. Replicas:主分片并发地将操作转发给所有副本分片(In-sync Replicas)。
  4. Ack:一旦所有活跃的副本都执行成功,主分片向协调节点确认,协调节点向客户端返回成功。

2. Sequence IDs 与快速恢复 #

早期的 ES 依赖版本号(Version)来做并发控制,但在故障恢复时效率极低。Easysearch 引入了更先进的 Sequence IDs 机制:

  • _seq_no:每个操作(Index, Delete)在分片级别都会被分配一个严格递增的序列号。
  • _primary_term:主分片的任期号。每次主分片发生切换(Failover),Term + 1。
  • Global/Local Checkpoint
  • 每个分片维护一个“检查点”,表示“在此序列号之前的所有操作都已持久化且一致”。
  • 快速恢复(Peer Recovery):当一个副本节点离线重启后,它不需要从主分片拷贝全量数据。它只需对比 Checkpoint,向主分片请求 重放(Replay) 丢失的那一小段操作(Operations)。这使得 TB 级数据的恢复时间从小时级缩短到秒级。

四、 并发控制(Concurrency Control) #

在分布式高并发写入场景下,如何防止“旧数据覆盖新数据”?Easysearch 提供了完善的乐观锁机制。

1. 乐观并发控制(OCC) #

Easysearch 不使用悲观锁(会阻塞性能),而是利用元数据进行检测:

  • 基于 VersionPUT /index/_doc/1?version=5。如果当前版本不是 5,报错。
  • 基于 Sequence ID(推荐)
    PUT /index/_doc/1?if_seq_no=1023&if_primary_term=2
    这是 CAS(Compare-And-Swap)操作的基础。它确保了只有在你知道数据的当前状态时,才能修改它。

五、 数据持久性(Durability)与 Translog #

内存写入虽然快,但掉电即失。Easysearch 通过 Translog(事务日志) 保证数据不丢。

1. Write Ahead Log (WAL) 机制 #

  • 每次写入请求,除了写入内存 Buffer(用于生成可搜索的 Segment),还会顺序追加到磁盘上的 Translog 文件。
  • Fsync 策略
  • index.translog.durability: request(默认):每次请求都强制刷盘。最安全,但制约 IOPS。
  • index.translog.durability: async:异步刷盘(默认 5秒)。性能极高,但风险是节点宕机时可能丢失最近 5秒的数据。

2. 崩溃恢复 #

重启时,Easysearch 会重放 Translog 中的操作,将那些还在内存 Buffer 中未落盘的数据恢复回来。

六、 总结 #

Easysearch 的分布式架构设计,是在性能一致性可用性之间寻找完美的平衡点:

  1. Cluster State Diff 解决了大规模集群的元数据同步风暴问题。
  2. Sequence IDs + Checkpoints 解决了分布式环境下的数据一致性和快速恢复问题。
  3. Translog + Segment 的组合,既实现了近实时搜索,又保证了数据的持久性。

理解这些核心设计,有助于我们在生产环境中更好地进行容量规划、性能调优和故障排查,充分释放 Easysearch 作为企业级搜索底座的潜力。