技术文章:分布式系统模式之Consistent Core
java达人维护较小的集群可提供更强的一致性,以允许大型数据集群协调服务器活动,而无需实现基于 quorum 的算法。
问题
线性化是最强的一致性保证,可以保证所有客户端都能看到最新提交的数据更新。提供线性化以及容错功能需要在服务器上实现共识算法,例如 Raft,Zab 或Paxos。
尽管共识算法是实现 Consistent Core 的基本要求,但客户端交互的各个方面(例如客户端如何找到leader,重复请求的处理方式等)都是重要的实现决策。关于安全性和活跃性,还有一些重要的实现注意事项。Paxos 仅定义共识算法,但是 Paxos 文献中没有很好地记录其他实现方面的内容。Raft非常清楚地记录了各种实现方面以及参考实现,因此是当今使用最广泛的算法。
当集群需要处理大量数据时,它需要越来越多的服务器。对于服务器集群,存在一些共同的要求,例如选择特定的服务器作为特定任务的 master ,管理组成员信息,将数据分区映射到服务器等。这些要求需要强大的一致性保证,即线性化 。实现也必须是容错的。一种常见的方法是使用基于 Quorum 的容错共识算法。但是在基于 Quorum 的系统中,吞吐量会随着集群的大小而降低。
解决方案
实现一个较小的3到5个节点的集群,该集群可提供线性化保证和容错能力。单独的数据集群可以使用小型一致性集群来管理元数据,并使用诸如 Lease 之类的机制来进行集群范围的决策。这样,数据集群可以扩展大量的服务器,但是仍然可以使用较小的元数据集群执行某些需要强一致性保证的操作。
Figure 1: Consistent Core
一个典型的consistent core接口是这样的:
public interface ConsistentCore {
CompletableFuture put(String key, String value);
List
Consistent Core至少提供了一种简单的键值存储机制。它用于存储元数据。
元数据存储
使用诸如Raft之类的共识算法来实现存储。它是“Replicated Write Ahead Log”实现的示例,其中复制由Leader and Followers处理,High-Water Mark用于跟踪通过Quorum进行的成功复制。
支持分层存储
Consistent Core通常用于存储数据,例如:组成员身份或跨服务器的任务分配。一种常见的使用模式是使用前缀来限制元数据的类型。例如 对于组成员身份,keys 将全部存储为/servers/ 1,server/2等。对于分配给服务器的任务,keys可以为/tasks/task1,/tasks/task2。通常使用特定前缀读取所有键数据。例如,要获取有关集群中所有服务器的信息,将读取所有带有前缀/servers 的 keys。
用法示例如下:
服务器可以通过使用前缀/servers 创建自己的 key 来向 Consistent Core 注册自己。
client1.setValue("/servers/1", "{address:192.168.199.10, port:8000}");
client2.setValue("/servers/2", "{address:192.168.199.11, port:8000}");
client3.setValue("/servers/3", "{address:192.168.199.12, port:8000}");
然后,客户端可以通过读取key前缀 /servers 来了解集群中的所有服务器,如下所示:
assertEquals(client1.getValue("/servers"), Arrays.asList("{address:192.168.199.12, port:8000}",
"{address:192.168.199.11, port:8000}",
"{address:192.168.199.10, port:8000}"));
由于数据存储的这种分层性质,[zookeeper],[chubby]之类的产品提供了类似于接口的文件系统,用户可以在其中创建具有父节点和子节点概念的目录、文件或节点。[etcd3]具有扁平化的键空间,可以获取一系列键。
处理客户端交互
Consistent Core功能的关键要求之一是客户端如何与 Consistent Core 交互。以下方面对于客户端使用 Consistent Core至关重要。
1 2 下一页>