苏宁MySQL_陈华军:苏宁云商的MySQL高可用实践

原标题:陈华军:苏宁云商的MySQL高可用实践

aebd8924a9ccacc02f27f02c0d31b901.gif

【IT168 专稿】本文根据【2016 第七届中国数据库技术大会】现场演讲嘉宾陈华军老师分享内容整理而成。录音整理及文字编辑IT168@ZYY@老鱼

讲师简介

86e7a6b80ba70866ba48519caaa2f848.png

▲陈华军

苏宁云商IT总部资深技术经理,之前长期从事数据库产品的开发和维护工作,期间向PostgreSQL社区贡献多件Patch,并参与和协调PostgreSQL中文手册的翻译。现于苏宁云商IT总部从事MySQL RDS项目的开发等。

正文

大家下午好,我是来自苏宁云商的陈华军,今天演讲的主题是《基于Pacemaker+MHA的MySQL高可用实践》,接下来我分享几个痛点:

cb3e8abf1df30bb46ea656523c81ec3c.png

跟大家交流一下我们做的一套高可用方案以及该方案具体解决了什么问题。

b7e0dc1fd2f9b3fa1e6e826fb4e240f9.png

先说一下我们曾经用过的一套架构,MySQL主从复制,由MHA做MySQL高可用,通过keepalived做MHA Manager的高可用,同时做VIP切换。后来我们发现,当网络发生故障时,该架构就会出问题,容易脑裂。

be4bd641329500603b4050c6ae1c2244.png

脑裂后可能会导致来回切换,数据双写进而数据混乱。我们也了解到其他一些发生过脑裂的案例,这些案例中采用的高可用架构几乎都有一个共同点,那就是用keepalived做高可用,实际上keepalived对脑裂是没什么防护作用的,我们认为keepalived不适合做主从这种有状态服务的HA。

dfff588a5502a00fcb1c50be66c38ad2.png

因此这个方案不是很靠谱,我们需要找到更靠谱的高可用方案。新的方案期望可以做到秒级的HA故障切换,并且在网络故障等特殊场景下不会脑裂。另外,有些业务,对数据一致性要求很高,我们希望这个高可用系统可以做到切换后数据不丢失。

9420e53335bd4be4f89652c67c5af689.png

如何实现这样的架构呢?

ba176257ffb5f49aadf6b50cf9e8b957.png

业界有很多通用的办法,比如增加第三方仲裁,或者是采取Quorum机制,也就是集群里面有三个节点(最好是奇数个),只有取得了过半节点的认可,才能成为master,这种方式可以有效防止脑裂。但还是有一点漏洞,比如新节点变成了master,但是这时旧的master可能还活着,也许还接收到了应用的写访问,这些写操作有可能成功了,那么切换后这些写操作相当于丢失了。

7c8035cba21a3cee2e855927f056b9cf.png

为了避免这样的事情发生,我们需要把旧master隔离掉。有几种方式,传统的HA采用物理fence设备,可以通过重启或者关机等手段把旧节点停掉。但这种方式不通用,不易部署,可靠性也需要打一个问号。

第二种方式,引入中间层proxy,所有流量全部经过proxy,由proxy隔离故障节点流量,但这种方式增加了系统复杂性,还有一定的性能损失。如果系统本身有proxy,这种方法还是可以的,但如果是为了隔离,专门搞一个proxy是不划算的。

第三种方式是在每个节点上部署Agent,发现本节点已经不是合法的Master时,自行停止。这种方法基本可行,但从master发现自己不是合法master,到把自己停掉,需要一段时间。并且不能处理OS hang住的情况,可能存在时间差,并且Agent也可能出故障。

810806b15aafc111a02bffe0a4146d7b.png

所以我们还要再考虑一层防护,就是让脱离集群的旧Master自己阻止写操作=成功。这个可以通过配置MySQL半同步复制,并且设置超大的半同步复制降级为异步复制的超时时间(比如300天)实现。

ef52b78d697424e7ae771bb12690dd0f.png

最终的方案,是前面3个方法的组合。设置3个节点做半同步复制,3个节点最多只能形成1组半同步复制关系,因此可以完全杜绝数据丢失和双写。如果节点上的Agent发现自己失去Quorum分区,会自行释放资源。这里部署了两个Slave,这两个Slave同时用于读写分离,增加了读写分离之后的架构,如下图所示:

ce4b7aa05169f1d1db8d4597e184e4b3.png

左边3个是高可用节点,Master有一个写VIP,其中一个Slave上有一个读VIP,同时跟读VIP在一起的还有一个LVS,通过LVS做负载均衡。当读的负载能力不够时,可以追加额外的只读Slave节点进行负载均衡。额外的Slave节点不作为Master的候选节点,并且配置为异步复制,这样可以确保系统里不会出现两组半同步复制关系,也就避免了双写的风险。这个架构的具体落实需要代码实现。

da62412de9b9ec6c10173570802f2d55.png

我们刚开始考虑的是基于Zookeeper,再添加一些定制开发方案,比如Zookeeper做集群状态存储和选主,Monitor进行集群监控切换,Agent布置在各个MySQL节点上,对MySQL的状态进行健康监视和命令执行,MHA做实际的failover(包含日志补偿)。该方式用代码实现比较灵活,但因为这套系统缺少完整的集群管理,我们不仅要做Master的健康监视和故障时的切换,还希望监视Slave的状态并实现节点的增加删除等操作,这些操作全部使用代码开发来实现,开发量还是很大的。

716074e90f8dc5869bbe985e0f843914.png

第二种方式是基于Pacemaker,Pacemaker跟Corosync的组合是一个通用的集成管理软件,做统一的集群管理。在此基础上只需要定制开发一些Agent来监视各类资源即可,实际的切换(包括日志补偿)仍然利用MHA实现。这个方案的优点是集群的很齐备,各资源互相独立并可通过配置灵活组合。当然也有缺点,定制开发的学习成本比较高。但综合考虑这两种方案,最后还是选择了Pacemaker方案。

c11e0f241edeeca72a2596e3f46f6af2.png

在这个过程中也考虑过其他方案,比如Galera集群方案,但其性能损耗太大,不易扩展,还有一些功能上的限制,不能做大规模推广。还有Mysql Fabric方案,该方案还是无法解决故障节点隔离和数据一致性的问题,并且还要考虑Fabric本身的高可用。

2b5660a6017a286309b405b9417b85d0.png

下面就介绍一下Pacemaker,Pcemaker+Corosync方案,实际上现在已经是Linux下的首选集群套件(RHEL7里已经取代了RHCS)。

在功能上,Pacemaker提供了常用的集群管理功能,比如节点管理,资源管理和配置管理等。其中最重要的可以说是资源管理,对资源的启动,停止和健康监视。对有主从状态的资源,还提供Promote和demote操作,这分别对应对将MySQL从Slave提升为Master和从Master降为Slave。

另外,Pacemaker管理的资源本身是相互独立的,但是可以通过配置规则定义,将它们按要求整合到一起。我们可以定义资源跟其他资源之间以及资源跟节点之间的依赖或者排斥关系。比如我希望Master只能部署在特定的节点上,或者读写VIP一定要跟Master处于同一节点,这些都可以通过配置规则实现。

6e4c3cf04b74f1c3fefc27989c6443a0.png

这套集群框架由很多组件构成。下面节点介绍一下几个核心组件。其中一个组件是CIB,它用来存放全局的集群配置和状态,所谓配置是指集群包含哪些节点,部署了哪些资源,每个资源的参数配置等。状态是指节点或者资源的动态的状态。 CRMD是集群资源管理器,它发现CIB变更之后,会请求PEngine根据配置重新计算集群满足当前配置情况下的最佳状态是什么。并分发为达到集群最佳状态需要执行的各种指令,指令的执行由每个节点上LRMd实施。

aae0a26c6b132c2d0e9951482d9fd0da.png

基于Pacemaker+Corosync的框架,很多东西都是现成的,我们要做的只是定义几个资源代理,即RA。其中VIP的RA采用现成的,我们只是开发了MySQL和LVS的RA,并通过配置将几个资源整合到一起,具体来说就是把写VIP和Master动态绑定,读VIP+LVS和Slave动态绑定。

35f83712c5d491d6b4283ca144146cd7.png

下面介绍一下主从切换的流程。如果发生切换有三种场景,第一种是MySQL RA检出Mysql进程有问题,第二种是Corosync检出mysql master节点故障,还有一种是人工发起在线切换,这些都会引起切换。切换时首先要更新CIB(比如把MySQL Master的状态改成停止),然后由Pengine引擎计算集群最佳状态然后由CRMd发起主从切换,它会选中一个Slave提升为Master,提升的时候判断原主死活,根据原主的死活采取不同的方式调用MHA进行切换,最后更新master信息,关于master信息后面会讲到。

9c30ab8655be6094717e5e3df1436e7c.png

前面提到了要防止脑裂和数据丢失,不能获得法定票数的分区上需要停止所有资源,通过最上面一行配置就可以实现了(如上图所示)。另外,可能集群包含的节点不止三个,这里定义了一个约束,限定Master只能在指定的3个HA节点上分配,并且在实施故障切换之前,检查本分区是否包含2个以上的HA节点,如否放弃切换。

52d3f2c40c3bbf22e7ad06b0db7633d5.png

为了保证数据一致性,我们需要隔离故障节点,比如切换后要阻止旧的Master再上线。这通过全局master信息实现。所谓master信息,即当前谁是master节点,这个信息放在全局的集群CIB里。并且本地文件也有一份,切换时,旧master的本地master信息文件不会更新,当旧master起来之后,发现自己的本地文件跟集群CIB里的不一致,就会出错而不能上线。除此以外,我们也检查Mysql show slave返回的主从状态信息,看其是否和集群CIB里的master信息一致。

81612dfe9e51bfc9afb0b3d1c3e2f8dc.png

第二种情况,是阻止MySQL运行中物理机或OS发生过crash的节点上线,有可能slave或者master没有配置成crash safe的状态,一旦宕机可能会丢失数据,跟一些节点的状态不一致,所以必须阻止这样的节点自动上线。

0b4816570511510326347b8cc50ae9d2.png

迁移阈值是指资源失败的时候可以重试的次数,可以根据情况设置,对MySQL资源,迁移阈值可以设为1~3之间。

cfdf9c6036c5570bdd8a34480eb87abf.png

对于LVS的管理,通过配置规则首先使Lvsdr和MySQL的Slave角色动态绑定;其次,Lvsdr根据Mysql slave的复制健康状况动态更新LVS。LVS会监视Slave的状态,如果Slave活着并且复制状态是健康的,则可以继续留在LVS的real sever列表中,否则将其剔除。

24aded4133737e84279cfacbf5829f57.png

Pacemaker本身提供了CUI工具做集群管理,因为参数比较多,操作起来还不是特别方便,所以我们把一些常用操作做成独立脚本,像集群的启动停止,在线切换等。右图是查看集群状态的输出,显示了MySQL,LVS和VIP资源以及集群节点的状态信息,Slave节点的复制状态等。

8c4013e9bee89f85ea2d577248b7db42.png

我们这套系统,刚开始时测试发现不是很稳定,大多数时候切换能成功,但偶尔又会切换失败。对于偶发性的问题,复现很花时间。为了加快测试进度,做了一套Failover测试RT集。在测试里模拟各种故障,然后检查切换是否成功,包括MySQL主从切换,LVS更新和数据是否丢失的检查。通过长时间运行这套RT集,发现并修补了很多发生概率非常低的BUG。

5d94bf4bd7617866dc351ef55276955a.png

通过长时间运行这套RT集,我们发现并修复了很多问题,特别是网络闪断引起的故障。其中一些问题的发生的概率很低,可能切换几百次会有一次切换不成功,这些问题如果通过手工测试的话很难被发现。

开发的过程中我们踩过不少坑。最开始我们用的是Pacemaker1.1.7,但是遇到各种各样的bug,也可能是配置里的各种依赖关系写的太复杂。后来改成1.1.14,这些问题就不存在了。

第二个问题是开始用mysqld_safe命令启动MySQL实例,但是该命令其实有监视跟重启mysql进程的功能,它跟Pacemaker功能重复并有冲突,后来改成用mysqld。

第三是我们三个节点的配置完全一样,这导致MHA对Slave做日志补偿时hang住,因为它要等有另外的半同步Slave连上了,解决办法是调用MHA前临时关闭半同步复制,补偿后再恢复。

第四是MHA的切换过程有很多步骤,第一步就是做状态检查,检查slave是不是活的,但它的检查机制和Pacemaker可能不一样。比如MySQL master的数据目录损坏或者被删掉了,这时Pacemaker可以检查出故障,并且发起了切换,但MHA检查时,会发现可以连到master上,认为它是好的,就不切了。为了解决这个问题,我们采取了一些措施,第一,尽量让二者的判断一致,第二,调用MHA前通过防火墙临时阻断MHA切换脚本对旧Master通信。

c352089d8e1f7d34889e43f1b0f157c4.png

还有一些注意事项,比如在高并发连接访问时,有可能一部分会话在等半同步,一部分不等,即存在一个组提交导致半同步被打破的BUG。第二个是我们设置了非常大的半同步复制时间超时,MySQL 5.5存在SQL执行时间随rpl_semi_sync_master_timeout线性增长的BUG。第三个跟测试网络环境有关,偶发性的产生读VIP的ARP缓存未及时更新的问题,测试机和数据库在同一个网段时容易发生,可适当减少ARP缓存失效时间。测试机跟数据库不在同一网段的时候,基本上没有发生这个问题。

504b51cbb49508b0c875d222ac68d938.png

总结一下,在效果上实现秒级故障切换;尽量保证数据不丢失;可伸缩的读负载均衡;可以自动隔离故障节点;应用基于VIP自动路由;易于管理。

但是也存在一些不足,对无读负载均衡需求的业务,三个节点存在资源浪费;MySQL主从延迟比较大时MHA日志补偿影响Failover速度;旧Master以外的其它任何节点故障的情况下,MHA的Failover失败;MySQL自身不能保证主从数据一致;MySQL本身容易产生主从延迟;MySQL大库的旧Master修复比较耗时。

83347d1edefb4b0bbe036740cca260fd.png

另外对双节点的集群,加上额外的仲裁,也可以做到比较严格的零数据丢失。比如两个节点一主一从,主从同步复制,Slave出问题之后,需要将同步复制切换为异步复制。为了防止脑裂可以增加一个分布式锁服务做仲裁,当Slave升级为Master,或者是Master想从同步复制降级为异步复制时,必须先获取锁,通过锁可以保证两件事情不会同时发生。master取得锁之后需要定期续租锁,否则锁会过期失效。

e6eda15425ef5e878577bdc0b4d02504.png

这个方案需要对master锁服务本身失效进行容错。当无法访问锁服务时,再通过另一个节点进行检查,如果另外的节点也不能访问锁服务,则认为锁服务失效,按已获得锁的逻辑处理。

通过这种方式可以确保两个节点外加一个锁,三个中任何一个出问题,都不会影响提供服务。如果两个出问题的话,肯定不行。

502ea2ec2a9ced884c64789f530fac26.png

前面提到双节点+分布式锁的方案,其实在PostgreSQL里有参考实现,有兴趣的可以看一下。这里可以顺便看一下PostgreSQL流复制。基于PostgreSQL流复制的HA方案上不存在刚才提到MySQL复制的问题。它是基于物理复制的,本身可以保证数据的一致性;relay消耗的资源少,同步复制基本不会发生主备延迟;通过pg_rewind很容易修复大库的旧Master。并且ClusterLabs开源项目自带的pgsql RA能够保证严格的数据一致性,可直接用于生产。

我的分享就结束了。谢谢大家!返回搜狐,查看更多

责任编辑:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值