三、 突破单点——从集中式到非集中式网络
1、数据分片
前面的Raft算法,是一个实现了强一致性的主从结构,逻辑上相当于是一个单点(当然,是一个高可用的单点),而单点的性能就会有上限,此时就需要使用数据分片等技术,将这些逻辑上的高可用单点再组成一个集群来提升性能。
分片与分片存储的数据是不一致的,但为了高可靠,每个分片不能只存一份,需要若干个位于不同节点上的副本,此时分片与副本并存,如下是一个三节点三副本的集群(节点数可以不等于副本数,参见第四章笔记的Quorum NWR算法):
多个逻辑上独立的高可用节点之间在组成一个对等式的分布式网络,此时就需要负载均衡了。数据上的负载均衡算法主要是哈希和一致性哈希。
在分布式数据存储系统中,存储方案选型时,通常会考虑数据均匀、数据稳定和节点异构性这三个维度。
1.1、哈希
哈希是一种非常常用的数据分布方法,其核心思想是,首先确定一个哈希函数,然后通过计算得到对应的存储节点。
哈希方法适用于同类型节点且节点数量比较固定的场景。目前,Redis 就使用了哈希方法。
1.2、一致性哈希
一致性哈希是指将存储节点和数据都映射到一个首尾相连的哈希环上,存储节点可以根据 IP 地址进行哈希,数据通常通过顺时针方向寻找的方式,来确定自己所属的存储节点,即从数据映射在环上的位置开始,顺时针方向找到的第一个存储节点。
一致性哈希方法比较适合同类型节点、节点规模会发生变化的场景。目前,Cassandra 就使用了一致性哈希方法。
2、通讯
在非集中式网络中,由于没有了主节点,各个节点间就需要一种算法可以完成通讯。这里记录Gossip协议。Gossip协议是为了节点间的一致性,或更准确的说是为了维护副本间的一致性。当然,不同的副本之间是可以构成分片的,如下(节点数可以不等于副本数,参见第四章笔记的Quorum NWR算法)
此时,一致性的目标是确保每个 DATA 节点拥有元信息指定的分片,而且不同节点上,同一分片组中的分片都没有差异。
Gossip 的三板斧分别是:直接邮寄(Direct Mail)、反熵(Anti-entropy)和谣言传播(Rumor mongering)。
- 直接邮寄。
就是直接发送更新数据,当数据发送失败时,将数据缓存下来,然后重传。这种方法的要点就是失败重试,所以需要支持操作的幂等性。此时各个节点间一般会使用队列存放收到的消息(否则发送至就会阻塞直至超时,影响性能),可能会因为缓存队列满了而丢数据。也就是说,只采用直接邮寄是无法实现最终一致性的。
- 反熵(实现最终一致性)。
本质上,反熵是一种通过异步修复(所谓异步修复就是定时的数据对账)实现最终一致性的方法。
集群中的节点,每隔段时间就随机选择某个其他节点,然后通过互相交换自己的所有数据来消除两者之间的差异,实现数据的最终一致性:
可以看出,反熵就是节点间两两交换数据,谁来发起交换呢?主要有推、拉和推拉三种方式。反熵需要节点两两交换和比对自己所有的数据,执行反熵时通讯成本会很高。
但是实现数据副本最终一致性,最常用的方法就是反熵(比如 Dynamo、InfluxDB、Cassandra)。在实际实现时,不能随机选择两个节点(更准确地说,是副本),而是要按照一定的顺序,比如下图,数据修复是按照顺时针顺序,循环修复的(为了方便演示,假设 Shard1、Shard2 在各节点上是不一致的):
- 谣言传播
执行反熵时,相关的节点都是已知的,而且节点数量不能太多,如果是一个动态变化或节点数比较多的分布式环境,这时反熵就不适用了。那么当你面临这个情况要怎样实现最终一致性呢?答案就是谣言传播。
谣言传播,广泛地散播谣言,它指的是当一个节点有了新数据后,这个节点变成活跃状态,并周期性地联系其他节点向其发送新数据,直到所有的节点都存储了该新数据: