背景
现状大部分业务系统一般采用集群方式部署,当执行一些分布式任务时,比如刷新配置数据、后台定时任务等,只能由集群中一个实例去完成,此时需要解决分布式一致性的问题。 虽然已经有一些比较成熟的开源分布式应用程序可以开箱即用,但是引入第三方程序都需要额外的主机资源开销以及维护工作,考虑到大部分业务系统只与数据库才是强耦合的关系,所以直接利用数据库来解决集群主备一致性的问题。
目的
实现一套简易的集群分布式系统,通过选举,保证集群中有且只有一个leader,并让其他实例(follower)对选举的结果达成共识。当leader状态异常时,能自动将其中一个follower切换成leader,进而能继续完成分布式相关任务。
技术方案
前言
本方法使用Mysql数据库来描述本方法,是因为利用其主键自增的性质,其他能保证事务、主键自增且唯一的数据库同样也适用本方法。 如果Mysql也是集群部署的方式,本方案需要集群的Mysql开启开启主从复制功能。
方案描述
根据实例与数据库(注册中心)连接是否正常来判断实例状态是否正常;集群中只要还有一个实例状态正常则集群就可用。
注册中心
在Mysql数据库中存在这样一张表,表字段如下:
/**mysql ,table name : cluster_node**/
id 主键,自增
node_name 集群中实例
node_status 实例状态:是leader还是follower
heart_timestamp 实例的心跳时间
将该表就作为集群的注册中心,集群中的实例启动后均会注册到注册中心,即将自己的信息写入到该表中。
-
id 实例注册时,该字段由数据库自动分配;
-
node_name 用来唯一标识集群中一个实例,比如实例的ip地址;
-
node_status 表示实例的状态:leader或follower;
-
heart_timestamp 用来记录实例的心跳时间,各个实例会定期更新该字段,可以用该字段判断实例状态是否正常;该字段是一个时间戳,以注册中心Mysql的当前时间戳为准。
实例注册
实例启动后,如果注册中心没有自己的信息,会先自己的信息(node_name)写入到注册中心,实例默认的状态是“follower”。
注册的过程就是数据库的insert语句:
INSERT INTO cluster_node (node_name, node_status)
VALUES
(?, ?)
(注:执行sql语句必须保证在一个事务内执行,下同)
只需要先插入node_name,node_status这两个字段,id由数据库自动分配。heart_timestamp等后面选举完leader再更新;
选举leader
leader选举操作很简单:直接将id值最小的实例设置成leader。如:
UPDATE
cluster_node
SET
node_status = ‘leader’
WHERE id IN
(SELECT
a.id
FROM
(SELECT
MIN(id) id
FROM
cluster_node) a)
集群启动时leader选举
集群启动后,实例会先从注册中心检查自己的状态(如果没有先注册)。
如果自己的状态是Leader,直接更新heart_timestamp字段。
UPDATE
cluster_node
SET
heart_timestamp = UNIX_TIMESTAMP(SYSDATE())
WHERE node_name = ?
如果自己的状态是follower,会先等待一个周期,然后再从注册中心获取leader的信息。如果注册中心没有leader,那么就开始选举leader。
集群运行时leader选举
每个follower保存着一个leader的最大过期时间。follower在运行时,会定期将Leader的heart_timestamp与注册中心当前时间进行差值运算,如:
SELECT
node_name,
(
UNIX_TIMESTAMP(SYSDATE()) - heart_timestamp
) AS th
FROM
bcoc_cluster_node
WHERE node_status = 'leader'
如果差值大于最大过期时间,那么表名该leader过期了,此时该follower根据leader的node_name将leader从注册中心删除掉,然后再进入选举过程。
整体流程:
实例启动后,会启用一个定时任务,也就是上面所说的一个周期,来执行与集群相关的以下操作:
-
将实例的信息注册到注册中心;
-
先判断自己是否就是leader,如果是,直接更新心跳时间,然后进入下一个周期;
-
如果自己不是leader,先等待一个周期;
-
从注册中心获取leader信息;
-
如果注册中心没有leader,进行leader选举;
-
如果Leader过期,根据leader名直接将其删除,再进行leader选举;
-
判断选举后的leader是否就是自己;
-
更新心跳时间,进入下一个周期;
效果
本方案原理简单,容易理解、容易实现。
根据CAP理论,只能实现三者其二。本方案实现了AP,保证了分区容忍性(P)和可用性(A):集群中各个实例节点都是平等的,集群中有一个实例状态正常就可用。
发表评论