本文介绍了近几年美团点评MySQL数据库高可用架构的演进过程,以及我们在开源的基础上所做的一些创新技术。同时也与业界其他方案进行了全面的对比,了解业界在高可用方面的进展,以及我们未来的一些规划和展望。MMM2015年之前,美团点评(大众点评方面)长期使用MMM(Master-MasterreplicationmanagerforMySQL)做数据库高可用,积累了很多经验,踩了很多坑。在快速发展过程中发挥了重要作用。MMM的架构如下。如上图,整个MySQL集群提供了1个writeVIP(VirtualIP)和N(N>=1)readVIP对外提供服务。每个MySQL节点都部署了一个Agent(mmm-agent),mmm-agent和mmm-manager保持通信状态,定期向mmm-manager(这里称为heartbeat)报告当前MySQL节点的生存状态。当mmm-manager连续多次接收不到mmm-agent的心跳消息时,就会切换。mmm-manager在两种情况下处理异常。1、异常是从节点mmm-manager会尝试移除从节点的读VIP,并将读VIP漂移到其他存活节点,以此实现从库的高可用。2.例外是主节点。如果此时节点还没有完全挂掉,则响应刚好超时。然后尝试给DeadMaster加一个全局锁(flushtableswithreadlock)。从节点中选出一个候选主节点作为新的主节点进行数据补全。数据完成后,移除死主的写VIP,尝试加入新的主节点。补充其他存活节点的数据,重新挂载到新的主节点上。主库故障后,整个集群的状态变化如下:mmm-manager检测到master1故障,完成数据后,将写VIP漂移到master2,应用写操作在新节点上继续。但是MMM架构存在以下问题:VIP数量过多,管理困难(曾经有一个1master6slave的集群,一共7个VIP)。在某些情况下,集群中的大部分VIP会同时丢失,很难区分之前在该节点上使用了哪个VIP。mmm-agent过于敏感,容易导致VIP流失。同时由于mmm-agent本身不具备高可用,一旦挂掉,会导致mmm-manager误判,误认为MySQL节点异常。有一个mmm-manager的单点。一旦因为某种原因挂掉,整个集群就会失去高可用性。VIP需要使用ARP协议,跨网段、跨机房的高可用基本不可能实现,保障能力有限。同时MMM是谷歌技术团队开发的老牌高可用产品。行业内用的不多,社区也不活跃。Google早就停止维护MMM的代码分支了。我们在使用过程中发现了很多bug,我们修改了其中的一些,提交给了开源社区。有兴趣的同学可以参考这里。针对这一点,从2015年开始,美团点评改进了MySQL的高可用架构,更新为MHA,很大程度上解决了MMM之前遇到的各种问题。MHA(MySQLMasterHighAvailability)是Facebook工程师YoshinoriMatsunobu开发的一款MySQL高可用软件。从名字可以看出,MHA只负责MySQL主库的高可用。当主库出现故障时,MHA会选择一个数据最接近原主库的候选主节点(这里只有一个从节点,所以从节点就是候选主节点)作为新的主节点,并填写和之前DeadMasterBinlog的区别。数据完成后,写入VIP并漂移至新主库。整个MHA的架构如下(为简单起见,只描述一主一从):这里我们对MHA做了一些优化,避免了一些脑裂问题。比如DB服务器上行交换机出现flutter,导致主库无法访问,被管理节点判断故障,触发MHA切换,VIP漂移到新的主库。然后恢复开关,可以访问主数据库了。但是由于主库没有去掉VIP,导致两台机器同时有VIP,导致脑裂。我们在MHAManager中加入了对同一机架上其他物理机的检测,可以通过比较更多的信息来判断是网络故障还是单机故障。MHA+Zebra(DAL)Zebra(斑马)是美团点评基础架构团队开发的一款Java数据库访问中间件。是美团点评内部使用的基于c3p0封装的动态数据源,包括读写分离、分库分表、SQL流控等非常强大的功能。它与MHA配合,成为MySQL数据库高可用的重要组成部分。下面是MHA+Zebra合作的整体架构:以主库故障为例,处理逻辑有以下两种方式:MHA切换完成后,会主动向Zebra监控器发送消息,Zebra监视器将更新ZooKeeper的配置并更新主库。上面配置的读取流量标记为离线。Zebramonitor每隔一段时间(10s~40s)检查集群中节点的健康状态。一旦发现某个节点出现问题,会及时刷新ZooKeeper中的配置,并将该节点标记为下线。一旦节点变更完成,客户端检测到节点发生变更,会立即使用新的配置重新建立连接,而旧的连接会逐渐关闭。整个集群的failover流程如下(只描述Zebramonitor的主动检测,第一种MHA通知请自行脑补^_^)。由于切换过程仍然依赖VIP漂移,只能在同一网段或同一二层交换机上进行,无法实现跨网段或跨机房的高可用。为了解决这个问题,我们对MHA进行了二次开发,去掉了MHA添加VIP的操作,并通知Zebramonitor在切换后重新调整节点的读写信息(将Wirte调整为新master的真实IP,并设置DeadMaster读流量去掉),整个交换机完全去VIP化,实现跨网段甚至跨机房切换,彻底解决了之前高可用局限于同一网段的问题.上面的切换过程变成如下图所示。但是这种方式的MHA管理节点是单点的,在出现网络故障或者机器宕机的情况下还是存在风险的。同时由于Master和Slave之间基于Binlog的异步复制,当主库机器宕机或主库不可访问时,MHA切换过程中可能会出现数据丢失的情况。另外,当主从延迟过大时,也会给数据补全操作带来额外的时间开销。除了Proxy的Zebra中间件,美团点评还有一套基于Proxy的中间件,配合MHA使用。当MHA切换时,主动通知Proxy调整读写流量。与Zebra相比,Proxy更加灵活,也可以覆盖非Java应用场景。缺点是多了一层接入链路,相应的ResponseTime和故障率也会有一定程度的增加。感兴趣的同学可以自行前往GitHub查询详细文档。未来架构设想上面提到的MHA架构还存在以下两个问题:管理节点单点。MySQL异步复制中的数据丢失。鉴于此,我们在一些核心业务中使用了Semi-Sync,可以保证95%以上的场景下不会丢失数据(还有一些极端情况无法保证数据的强一致性)。另外,高可用采用分布式Agent,在某个节点失效后,通过一定的选举协议选出新的Master,从而解决了MHAManager的单点问题。针对上述问题,我们研究了一些业内领先的做法,现简要介绍如下。主从同步数据丢失针对主从同步数据丢失,一种做法是创建一个BinlogServer,模拟Slave接受Binlog日志,主库每次都需要收到BinlogServer的ACK响应数据被写入。写入成功。BinlogServer可以部署在就近的物理节点上,从而保证每次数据写入都能快速落地到BinlogServer上。发生故障时,只需要从BinlogServer中拉取数据即可,保证数据不会丢失。分布式Agent高可用针对MHA管理节点的单点问题,一种方法是在MySQL数据库集群的每个节点上部署Agent。当发生故障时,每个Agent参与选举投票,选出一个合适的Slave作为新的主库。防止仅通过Manager切换,去除MHA单点。整个架构如下图所示。MGR结合中间件的高可用一定程度上解决了之前的问题,但是Agent和BinlogServer是新引入的风险。同时BinlogServer的存在也带来了额外的响应时间开销。有没有办法在不丢失数据的情况下删除BinlogServer和Agent?答案当然是肯定的。近年来,分布式协议Raft和Paxos在MySQL社区非常流行。社区还推出了基于Paxos的MGR版本的MySQL。通过Paxos将一致性和切换过程下推到数据库,对上层屏蔽切换细节。架构如下(以MGR的单主为例)。当数据库出现故障时,MySQL会自行在内部进行切换。切换完成后,将topo结构推送给Zebra-monitor,Zebra-monitor更改对应的读写流量。但是这种架构和BinlogServer一样存在回复确认的问题,即主库数据每次写入,大部分节点都需要回复ACK,才认为写入成功,存在一定的响应时间开销。同时,每个MGR集群必须要求奇数个节点(大于1)。导致以前只需要一主一从两台机器,现在至少需要三台,造成了一定的资源浪费。但无论如何,MGR的出现无疑是MySQL数据库的又一次伟大创新。结束语本文介绍了美团点评MySQL数据库高可用架构从MMM到MHA+Zebra、MHA+Proxy的演进过程,同时也介绍了业界的一些高可用实践。该数据库近年来发展迅速。数据库的高可用设计没有完美的解决方案,只有不断的突破和创新。我们一直在这条路上探索更好的设计和更完美的解决方案。
