实现原理

多个数据库实例同时访问、修改同一个数据库,必然会带来全局并发问题。

神通共享存储多主集群引入 PCM锁机制,提升数据在节点间的安全性。同时,通过缓存融合机制实现节点间内存共享,提升数据在节点间的传递效率。

仲裁盘功能

神通共享存储多主集群是一个由多个节点组成的集群系统,集群需要有一个主节点进行统一管理,仲裁盘负责在集群所有节点中挑选一个节点作为主节点管理整个集群,在节点发生故障时负责选出新的主节点以及通知主节点执行故障恢复操作。

../../../../_images/image21.png

仲裁盘优势

神通共享存储多主集群要支持2节点集群,基于网络的分布式一致性协议一般至少需要3个节点才能工作

若使用网络心跳的方式,如果收不到对方的心跳,无法准确判断对方的状态:有可能是对方挂掉了,也有可能是网络出现了问题。如果此时都切换为主,就会出现脑裂,如果此时都切换为备,会失去高可用的意义。

而使用仲裁盘方式,如果收不到对方的心跳,有以下几种情况:

  • 有可能是对方挂掉了。自己切换为主,没有问题。
  • 有可能一方和仲裁盘连接出现问题,一方和仲裁盘连接正常。自己和仲裁盘的连接是否正常是可以感知的,和仲裁盘连接正常的切换为主,和仲裁盘连接有问题的切换为备。
  • 有可能两方和仲裁盘连接都有问题。都切换为备,因为两方都和共享存储失联,切换为主也没有意义。

线程结构

  • 仲裁线程,负责读写仲裁盘心跳进行仲裁,决定哪个节点作为主机运行
  • 自我监测线程,负责监控当前节点心跳是否正常,加载/卸载资源是否超时
  • 资源操作线程,负责执行挂载资源、卸载资源以及检测资源是否正常等操作

心跳包内容

  • 选主纪元(term)
    • 这是一个全局递增序列,发起选主时加一,在仲裁过程中,如果发现对方的term比自己大,会将自己的term设置为等于对方的term
    • 通过term可以避免陈旧的块信息的干扰,在仲裁过程中,如果发现对方的term比自己小,则忽略对方的心跳块内容
    • 通过term可以实现抢主,在仲裁过程中,如果发现对方的term比自己大,自己会转换成备
  • 启动序号
    • 仲裁盘业务进程启动后第一次心跳时会将启动需要加一
    • 以后每次读仲裁盘后会对比属于自己的心跳块中的启动序号和内存中的启动序号是否一致,避免出现心跳块被其它进程或节点修改而不自知
  • 磁盘心跳计数
    • 每次写仲裁盘心跳块时将此计数加一
    • 连续多次(VOTEDISK_HEARTBEAT_OFFLINE_MAXNUM)发现对方心跳块中的心跳计数保持不变,则认为对方离线(可能是关机了、共享存储连接断了,进程退出了等原因)
  • 是否允许对应节点加入集群
    • 某个节点出现故障后,主节点需要花费一定的时间进行故障恢复,在故障恢复完成之前,这个节点不能重新加入集群
    • 只有主节点会设置该变量

节点状态

  • SLAVE: 从节点
    • 在发现其它节点都为SLAVE或者离线时,会转换为CANDIDATE
  • CANDIDATE:正在选主,这是由SLAVE转换为MASTER的中间状态
    • 在发现其它节点都给自己投票或者离线时,会转换为MASTER
    • 在发现对方term比自己大时,会转换为SLAVE
    • 在发现对方也是CANDIDATE,并且节点id比自己小时,转换为SLAVE
  • MASTER:主节点
    • 在发现对方term比自己高时,会转换为SLAVE
  • 状态转换图
../../../../_images/image3.png

缓存融合

缓存融合通过高速网络和共享存储将多个节点的内存融合在一起。

页面的获取可以通过读取磁盘,也可以通过读取远程节点的内存。

缓存融合通过PCM锁的方式来实现,下面通过几种获取页面的例子来解析缓存融合的原理。

从磁盘读取数据

节点C想读取最新版本的页面:

  • 节点C向主节点(节点D)发送请求,请求获取1008页面PCM的读锁。
  • 主节点发现任何节点都没有锁当前页面,直接将PCM锁的读锁授权给节点C。
  • 节点C收到主节点的请求后,直接从磁盘中读取页面放入本地缓存中。
../../../../_images/image4.png

两节点同时读一个页面

节点B想读取最新版本的页面:

  • 节点B向主节点(节点D)发送请求,请求获取1008页面PCM的读锁。
  • 主节点发现节点C有读锁,将请求转发给节点C,并直接把PCM的读锁授权给节点B。
  • 节点C收到主节点的请求后,将页面内容转发给节点B。
  • 节点B收到页面
../../../../_images/image5.png

节点读正在修改的页面

节点C想读取最新版本的页面:

  • 节点C向主节点(节点D)发送请求,请求获取PCM的读锁。
  • 主节点发现节点A有写锁,将请求转发给节点A,告诉节点A要进行锁降级。主节点将PCM锁的锁模式修改为读锁,并将读锁授权给节点C。
  • 节点A收到主节点的请求后,先刷redo日志,然后节点A将页面内容发送给节点C。
  • 节点C收到页面
../../../../_images/image6.png