数据复制

110 阅读4分钟

元数据也是数据,但特别之处在于每一个请求都要访问它,所以元数据的存储很容易成为整个系统的性能瓶颈和高可靠性的短板。如果系统支持动态分片,那么分片要自动地分拆、合并,还会在节点间来回移动。这样,元数据就处在不断变化中,又带来了多副本一致性(Consensus)的问题。

静态分片

忽略元数据变动问题,只要把元数据复制多份放在对应的工作节点上就可以了,这样同时兼顾了性能和高可靠。TBase 大致就是这个思路,直接将元数据存储在协调节点上。

TiDB:无服务状态

在 TiDB 架构中,TiKV 节点是实际存储分片数据的节点,而元数据则由 Placement Driver 节点管理,简称PD。

TiKV 节点定期主动向 PD 报送心跳,分片的元数据信息也就随着心跳一起报送,而 PD 会将分片调度指令放在心跳的返回信息中。

由于每次 TiKV 的心跳中包含了全量的分片元数据,PD 甚至可以不落盘任何分片元数据,完全做成一个无状态服务。这样的好处是,PD 宕机后选举出的新主根本不用处理与旧主的状态衔接,在一个心跳周期后就可以工作了。当然,在具体实现上,PD 仍然会做部分信息的持久化,这可以认为是一种缓存。

image.png

虽然无状态服务有很大的优势,但 PD 仍然是一个单点,也就是说这个方案还是一个中心化的设计思路,可能存在性能方面的问题。

CockroachDB:去中心化

CockroachDB 的解决方案是使用 Gossip 协议。

为什么不用 Paxos 协议呢?Paxos 协议本质上是一种广播机制,也就是由一个中心节点向其他节点发送消息。当节点数量较多时,通讯成本就很高。

而 Gossip 协议的原理是谣言传播机制,每一次谣言都在几个人的小范围内传播,但最终会成为众人皆知的谣言。这种方式达成的数据一致性是 “最终一致性”,即执行数据更新操作后,经过一定的时间,集群内各个节点所存储的数据最终会达成一致。

CockroachDB 在寻址过程中会不断地更新分片元数据,促成各节点元数据达成一致。

image.png

复制协议的选择和数据副本数量有很大关系:如果副本少,参与节点少,可以采用广播方式,也就是 Paxos、Raft 等协议;如果副本多,节点多,那就更适合采用 Gossip 协议。

Raft 的性能优化方法(TiDB)

Raft 的顺序投票是一种设计上的权衡,虽然性能有些影响,但是节点间日志比对会非常简单。在两个节点上,只要找到一条日志是一致的,那么在这条日志之前的所有日志就都是一致的。这使得选举出的 Leader 与 Follower 同步数据非常便捷,开放 Follower 读操作也更加容易。

优化:

  1. 批操作(Batch)。Leader 缓存多个客户端请求,然后将这一批日志批量发送给 Follower。Batch 的好处是减少的通讯成本。
  2. 流水线(Pipeline)。Leader 本地增加一个变量(称为 NextIndex),每次发送一个 Batch 后,更新 NextIndex 记录下一个 Batch 的位置,然后不等待 Follower 返回,马上发送下一个 Batch。如果网络出现问题,Leader 重新调整 NextIndex,再次发送 Batch。当然,这个优化策略的前提是网络基本稳定。
  3. 并行追加日志(Append Log Parallelly)。Leader 将 Batch 发送给 Follower 的同时,并发执行本地的 Append 操作。因为 Append 是磁盘操作,开销相对较大,而标准流程中 Follower 与 Leader 的 Append 是先后执行的,当然耗时更长。改为并行就可以减少部分开销。当然,这时 Committed Entry 的判断规则也要调整。在并行操作下,即使 Leader 没有 Append 成功,只要有半数以上的 Follower 节点 Append 成功,那就依然可以视为一个 Committed Entry,Entry 可以被 Apply。
  4. 异步应用日志(Asynchronous Apply)。Apply 并不是提交成功的必要条件,任何处于 Committed 状态的 Log Entry 都确保是不会丢失的。Apply 仅仅是为了保证状态能够在下次被正确地读取到,但多数情况下,提交的数据不会马上就被读取。因此,Apply 是可以转为异步执行的,同时读操作配合改造。

选择 Raft 就是因为 etcd 提供了可靠的工程实现,而 Paxos 则没有同样可靠的工程实现。


此文章为6月Day9学习笔记,内容来源于极客时间《分布式数据库30讲》