业务中有一个统一写MySQL的服务这里称为DataAgg,但进行为了高可用需要进行主备(master-slave,leader-follower)集群部署,多个运行着的DataAgg只能同时有一个允许工作(基于高可用KV的Master发现策略-Master Discovery by HA KV), 大概的实现思想是, 基于redis集群或者ETCD的分布式锁来实现
以ETCD为例: #
如果部署有ETCD(originated from two ideas, the unix “/etc” folder and “d”istributed systems) 直接调用官方包提供的方法即可,主要代码NewSession->NewElection->Campaign,在Campaign时如果未能成为master或者leader就会一直卡住;若Campaign返回则说该调用端的服务获取到了leader角色,具体代码在底部,效果如图:
以redis-cluster为例: #
- 以一个key是否存在作为是否有 master角色的DataAgg 工作的标志; value记录主DataAgg的信息; 这个key设置有TTL,防止master异常情况
- 多个DataAgg轮洵同一个key,dataAgg得到value后与自身信息校验:
- 如果value为空,即这个key不存在也就还没有master工作,则更新这个key,自身成为master
- 如果是自身并且也是master,则更新这个key
- 如果不是自身,不作处理
- 如果value为空,即这个key不存在也就还没有master工作,则更新这个key,自身成为master
这样会存在什么问题?
- TTL时间可能不会有master,比如master在update masterKey之后异常消失; 无DataAgg工作的TTL时间与影响业务程度大小,需要考虑,一般成正比,TTL越长业务影响可能越大
- 无法知道有哪些DataAgg服务结点正在运行,比如可能有”僵尸”进程没有被正确的进行退出处理,这个进程一直占用着master的角色导致整个DataAgg集群不能正常工作
后来改善一下:
- 各个DataAgg发心跳包请求分别定时上报自己的信息;
- 去掉masterKey,改为每一个DataAgg获取所有结点的信息后,作master检验,检验策略或者算法可以定制,master认定算法单独抽出来可测试化
在redis中这样实现:
- NodePeers这个set保存结点的id:这样每一个peer通过这个set就可以知道有哪些peer运行着
- 每一个peer定时发心跳包请求设置key:value,其中key会在NodePeer这个set填入, value则是自身的信息
由于网络的延迟性,可能会出现多个master角色工作的情况;这样解决:在每一个peer中进行master校验时,发现多个master并且自身也是master的情况,则peer主动退回成slave或者follower的角色,等到下次心跳时进行master的决策认定;
etcd具体代码test case: