页面加载中...

一种基于Mysql分布式一致性解决方法

| 默认分类 | 0 条评论 | 830浏览

背景

现状大部分业务系统一般采用集群方式部署,当执行一些分布式任务时,比如刷新配置数据、后台定时任务等,只能由集群中一个实例去完成,此时需要解决分布式一致性的问题。 虽然已经有一些比较成熟的开源分布式应用程序可以开箱即用,但是引入第三方程序都需要额外的主机资源开销以及维护工作,考虑到大部分业务系统只与数据库才是强耦合的关系,所以直接利用数据库来解决集群主备一致性的问题。

目的

实现一套简易的集群分布式系统,通过选举,保证集群中有且只有一个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从注册中心删除掉,然后再进入选举过程。

整体流程:

实例启动后,会启用一个定时任务,也就是上面所说的一个周期,来执行与集群相关的以下操作:

  1. 将实例的信息注册到注册中心;

  2. 先判断自己是否就是leader,如果是,直接更新心跳时间,然后进入下一个周期;

  3. 如果自己不是leader,先等待一个周期;

  4. 从注册中心获取leader信息;

  5. 如果注册中心没有leader,进行leader选举;

  6. 如果Leader过期,根据leader名直接将其删除,再进行leader选举;

  7. 判断选举后的leader是否就是自己;

  8. 更新心跳时间,进入下一个周期;

效果

本方案原理简单,容易理解、容易实现。

根据CAP理论,只能实现三者其二。本方案实现了AP,保证了分区容忍性(P)和可用性(A):集群中各个实例节点都是平等的,集群中有一个实例状态正常就可用。

发表评论

最新评论

    来第一个评论吧!