​ Master选举是一个在分布式系统中非常常见的应用场景。分布式最核心的特性就是能够将具有独立计算能力的系统单元部署在不同的机器上,构成一个完整的分布式系统。而与此同时,实际场景中往往也需要在这些分布在不同机器上的独力系统单元中选出一个所谓的“老大”,在计算机中,我们称之为Master。

选举Master

方式一:数据库

​ 我们可以选择常见的关系型数据库中的主键特性来实现:集群中的所有机器都向数据库中插入一条相同主键 ID的记录,数据库会帮助我们自动进行主键冲突检查,也就是说,所有进行插入操作的客户端机器中,只有一台机器能够成功——那么,我们就认为向数据库中成功插成功数据的客户端机器成为Master。

​ 弊端:当前选举出的Master挂了,如何处理?,甚至谁来告诉我Master挂了?

方式二:zookeeper一致性&事件通知

​ 利用ZooKeeper的强一致性,能够很好保证在分布式高并发情况下节点的创建一定能够保证全局唯一性,即ZooKeeper将会保证客户端无法重复创建一个已经存在的数据节点。也就是说,如果同时有多个客户端请求创建同一个节点,那么最终一定只有一个客户端请求能够创建成功。利用这个特性,就能很容易地在分布式环境中进行Master选举了。

​ 我们可以所有的client去申请向zookeeper创建一个相同的临时节点,最终只会有一个成功,成功即为Master。然后其他client监听这个节点,如果下面发生值变化(删除),其余的client继续申请创建,即重新选取Master。这样可以快速的选举出Master,也可以在选举过程中添加权重等,偏向于某些客户端。

使用curator框架来实现

public class Recipes_MasterSelect {
    static String master_path = "/curator_recipes_master_path";
    static CuratorFramework client = CuratorFrameworkFactory.builder().connectString("127.0.0.1:2181")
            .retryPolicy(new ExponentialBackoffRetry(1000, 3)).build();

    public static void main(String[] args) throws Exception {
        client.start();
        LeaderSelector selector = new LeaderSelector(client, master_path, new LeaderSelectorListenerAdapter() {
            public void takeLeadership(CuratorFramework client) throws Exception {
                System.out.println("成为Master角色");
                Thread.sleep(3000);
                System.out.println("完成Master操作,释放Master权利");
            }
        });
        selector.autoRequeue();
        selector.start();
        Thread.sleep(Integer.MAX_VALUE);
    }
}

  运行结果:

成为Master角色
完成Master操作,释放Master权利
成为Master角色

​ 以上结果会反复循环,并且当一个应用程序完成Master逻辑后,另外一个应用程序的相应方法才会被调用,即当一个应用实例成为Master后,其他应用实例会进入等待,直到当前Master挂了或者推出后才会开始选举Master。