分布式同步原语控制的资源或编排的任务分布在不同的进程、不同的机器上。
分布式同步原语的实现更加复杂,因为在分布式环境中,网络状况、服务状态等都是不可控的。还好,有相应的软件系统来做这些事情,这些软件系统会专门处理节点之间的协调和异常情况,并保证数据的一致性。我们要做的就是在它们的基础上实现业务。
通常用来做协调工作的软件系统有 Zookeeper、Consul、etcd 等,其中 Zookeeper 为 Java 生态群提供了丰富的分布式同步原语(通过 Curator 库),但是缺少与 Go 相关的同步原语库;Consul 在提供分布式同步原语这件事上不是很积极;etcd 则提供了非常好的分布式同步原语,比如分布式互斥锁、分布式读写锁、Leader 选举等。
既然依赖 etcd,那么在生产环境中就要有一个 etcd 集群,而且应该保证这个 etcd 集群是 7x24 小时工作的。
1. Leader 选举
Leader 选举常常被应用在主从架构的系统中。主从架构中的服务节点分为主(Leader、Master)和 从(Follower、Slave)两种角色,实际节点包括 1 主 n从,一共是 n+1 个节点。
主节点常常执行写操作,从节点常常执行读操作。如果读/写都在主节点上,从节点只是提供一个备份功能,那么主从架构就会退化成主备模式架构。
在主从架构中,最重要的是如何确定节点的角色,也就是到底哪个节点是主节点,哪个节点是从节点?
在同一时刻,系统中不能有两个主节点;如果有两个主节点,它们都执行写操作,就有可能出现数据不一致的情况。所以,我们需要一种选主机制,选择一个节点作为主节点,这个过程就是 Leader 选举。
当主节点宕机或者不可用时,就需要进行新一轮的选举,从其他的从节点中选择一个节点,让它作为新的主节点,宕机的原主节点恢复后,可以变为从节点,或者被摘掉。
我们可以通过 etcd 基础服务来实现 Leader 选举。具体来说,就是将 Leader 选举的逻辑交给 etcd 基础服务,我们只需要把重心放在业务开发上。 etcd 基础服务可以通过多节点的方式保证 7 x 24小时服务,所以我们也不用担心 Leader 选举不可用的问题,如下图所示:
接下来,我们将介绍在业务开发中与 Leader 选举相关的选举、查询、主节点变化监控等功能。
这里需要提醒的是,如果你想运行下面的测试程序,则要先部署一个 etcd 集群,或者部署一个 etcd 节点做测试。
我们先来实现一个测试分布式程序的框架:它会先从命令行读取命令,然后执行相应的命令。
打开两个窗口,模拟不同的节点,分别执行不同的命令。测试程序如下:
这个程序创建了一个 etcd 的 client,并基于它创建了 concurrency.Session,代表和 Redis 的会话,然后在这个会话的基础上创建了 Election。
Election 从命令行接收命令,并执行相应的分布式选举命令,比如竞选主节点、退出主节点,监控主节点的变化、查询当前的主节点等命令,每个命令对应一个方法。
1.1 选举
如果你的业务集群中还没有主节点,或者主节点宕机了,那么就需要发起新一轮的选主操作,主要会用到 Campaign 和 Proclaim 方法。如果你需要主节点放弃主的角色,让其他节点有机会成为主节点,