类MHA高可用方案存在的问题

本文分析了MHA在处理MySQL高可用性时遇到的问题,包括MHA与ProxySQL协同的缺陷、可能导致的脑裂现象以及MHA自身的单点故障。提出了改进方案,如改造二次检测脚本以考虑ProxySQL状态,并讨论了PXC和MGR等替代方案。总结指出,针对中间件的适配和选择原生集群方案是提升高可用性的关键,但需权衡技术变革的风险和业务需求。
摘要由CSDN通过智能技术生成

类MHA高可用方案存在的问题

MHA Generaly Available since 2011?

MHA在当时主要解决两个问题:

  1. 自动的数据补偿
  2. 自动的主从切换

还有两个重要的背景需要交代:

  1. 当时主要使用异步复制
  2. 当时还没有ProxySQL

所以当时基本使用MHA+VIP作为MySQL复制集的高可用方案.

不谈vip的脑裂问题, 这种架构的一个关键点在于, MHA是作为一个外部机制检测MySQL复制集状态, 并变更复制集拓扑, 变更后漂移vip, 也就是说MHA既控制了集群拓扑的变化, 又控制了app的访问路径(写通过vip)

脑裂

MHA+ProxySQL架构有一个问题:

MHA对MySQL复制级的监控检测逻辑中不包含ProxySQL, 因为MHA不知道用户在MySQL上层会构建什么样的中间件, 同时MHA变更集群拓扑后也并不会通知ProxySQL. 也就是说MHA和ProxySQL有可能会产生不同的"观点"

在这里插入图片描述
如上图场景

  • APP-1, ProxySQL-1和主库在一个网络分区, 正在写入数据(异步复制, 或半同步超时不是无限大)
  • APP-2, ProxySQL-2, 从库和MHA manager在一个网路分区, 无法连通主库

这种情况, MHA会Failover. Failover后变成如下拓扑

在这里插入图片描述

这就导致了脑裂(如果是半同步且超时无限大, 那么不会脑裂, 因为数据无法写入Master). 实际上如果在secondary_check_script中配置了ProxySQL地址

secondary_check_script=masterha_secondary_check -s ProxySQL-1 -s ProxySQL-2 -s Slave-1 -s Slave-2 -s Slave-3

这样配置后, 在图-1的场景中, manager二次检测时无法ssh到ProxySQL-1, 二次检测脚本会以exit_code=2退出, 不会发生Failover, 就不会脑裂(如果是半同步且超时无限大, 那么不会脑裂, 因为数据无法写入Master).

在masterha_secondary_check脚本中有如下注释, 这是exit code的含义, 只有0会触发Failover
# 0: master is not reachable from all monotoring servers
# 1: unknown errors
# 2: at least one of monitoring servers is not reachable from this script
# 3: master is reachable from at least one of monitoring servers

极端场景无法完成Failover

上文的场景就是一种极端场景. 在这种场景(图-1)下, 正确的做法是切断Master流量(关闭APP-1并不太现实, 因为实际可能不只一个应用, 关闭ProxySQL或Master都是可以的), 然后进行切换. 但这正是MHA无法做到的.

在这里插入图片描述

想象图-3场景, 使用半同步复制rpl_semi_sync_master_wait_for_slave_count=1

这种情况下, MHA仍然不会Failover(二次检测脚本-s中指定了slave-4), 那么按照正常逻辑, 应该Failover吗?

个人认为要看情况:

  • 如果添加从库的速度很慢, 一旦Slave-4出现问题无法返回ack, Master将不能提供写入, 那么应该Failover, 将Slave1-3组成一个新的复制集, 一主两从, 两个从库出现异常的概率显然要小很多
  • 如果添加从库的速度很快(备份集小, 自动化完善), 并且当时的场景不允许哪怕3-5秒的不可用(切换用时), 那么可以快速为Master添加一个从库Slave-5

为什么类MHA的高可用方案在这种情况下无法完成Failover?

  1. ProxySQL是一个"伪集群"

    ProxySQL集群目前只做到了配置同步, 成员之间并没有使用共识算法实现选举机制, 在图-1的场景中检查ProxySQL-1和ProxySQL-2的runtime_mysql_servers, 你会看到这样的结果

    ProxySQL-1
    admin@127.0.0.1 15:10:50 [(none)]> select * from runtime_mysql_servers;
    +--------------+---------------+------+-----------+---------+--------+-------------+-----------------+---------------------+---------+----------------+------------------------+
    | hostgroup_id | hostname      | port | gtid_port | status  | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms | comment                |
    +--------------+---------------+------+-----------+---------+--------+-------------+-----------------+---------------------+---------+----------------+------------------------+
    | 10           | 172.16.120.10 | 3358 | 0         | ONLINE  | 1      | 0           | 1000            | 0                   | 0       | 0              | master for backup read |
    | 11           | 172.16.120.10 | 3358 | 0         | ONLINE  | 1      | 0           | 1000            | 0                   | 0       | 0              | master for backup read |
    | 11           | 172.16.120.12 | 3358 | 0         | SHUNNED | 1000   | 0           | 1000            | 120                 | 0       | 0              | slave                  |
    | 11           | 172.16.120.11 | 3358 | 0         | SHUNNED | 1000   | 0           | 1000            | 120                 | 0       | 0              | slave                  |
    +--------------+---------------+------+-----------+---------+--------+-------------+-----------------+---------------------+---------+----------------+------------------------+
    
    ProxySQL-2
    admin@127.0.0.1 15:10:14 [(none)]> select * from runtime_mysql_servers;    
    +--------------+---------------+------+-----------+---------+--------+-------------+-----------------+---------------------+---------+----------------+------------------------+
    | hostgroup_id | hostname      | port | gtid_port | status  | weight | compression | max_connections | max_replication_lag | use_ssl | max_latency_ms | comment                |
    +--------------+---------------+------+-----------+---------+--------+-------------+-----------------+---------------------+---------+----------------+------------------------+
    | 11           | 172.16.120.11 | 3358 | 0         | ONLINE  | 1000   | 0           | 1000            | 120                 | 0       | 0              | slave                  |
    | 11           | 172.16.120.10 | 3358 | 0         | SHUNNED | 1      | 0           | 1000            | 0                   | 0       | 0              | master for backup read |
    | 11           | 172.16.120.12 | 3358 | 0         | ONLINE  | 1000   | 0           | 1000            | 120                 | 0       | 0              | slave                  |
    +--------------+---------------+------+-----------+---------+--------+-------------+-----------------+---------------------+---------+----------------+------------------------+
    3 rows in set (0.00 sec)
    

    如果ProxySQL集群有选举机制, 那么一个集群至少需要三个节点, 当一个节点意识到自己无法与大多数成员通信时, 它应当将自己置为不可用状态.

  2. MHA manager单点

    这和ProxySQL有一些类似的情况. 如果MHA也是一个集群, 并在MySQL复制集的每个节点部署一个node, 那么在图-1的场景中, Master节点上的MHA node应当意识到自己已经脱离了大多数成员, 它无法发起MySQL拓扑变更, 它要做应当是关闭Master(或打开read_only)

    青云开源的Xenon好像实现了类似的功能~~, 但我也不确定, 这个项目使用人数太少~~

    ​ https://github.com/radondb/xenon/issues/107

    ​ 不过同样, xenon是使用vip为应用提供写入通道, 也就是说xenon控制了访问路径

    Orchestrator不知道是否实现了这样的功能, 需要调研

  3. MHA的检测逻辑不包含ProxySQL, 变更拓扑后也没有通知ProxySQL

    1. MHA的检测机制和ProxySQL并不相同, 两者可能对拓扑情况有不同的判断. 应当改造二次检测脚本, 通过连接ProxySQL判断主库状态, 但即使这样做, 在图-1的场景中, manager会发现自己无法连接ProxySQL-1, 那么二次检测脚本应当以exit_code=2退出, 不会发生Failover, 所以这仍然无法解决极端场景不能Failover的问题.

    2. Failover后, MHA应当主动变更ProxySQL中的配置

      携程数据库高可用架构实践有类似描述

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vlki7qa9-1609394866363)(https://raw.githubusercontent.com/Fanduzi/Figure_bed/master/%E7%B1%BBMHA%E9%97%AE%E9%A2%98/%E5%9B%BE-4.png)]

    正确的做法与图-4类似, 在Failover后MHA应当将新的拓扑配置推送给"配置中心", 保证应用使用新的配置连接数据库

    美团也实现了类似的功能[踩坑无数,美团点评高可用数据库架构演进]
    在这里插入图片描述

  4. 主从复制集并不是集群

    即便从库都判定主库不可用, 也无能为力. 而假设是一个PXC或MGR集群(我们先不讨论这两者的问题), 图-1的场景会变成这样(以PXC为例):

在这里插入图片描述

实际上图中PXC节点数量为偶数并不合理, 只是为了迎合图-1场景作对比

在PXC中, 所有节点都是主节点, 都可以写入, 只要提交成功就不会丢失数据

MGR也有多主模式, 如果是单主模式, 脱离集群的节点会将自己设为read_only

在图-5的情况下, Master会被踢出集群, 也就是说选举和拓扑变更是MySQL自己控制的, ProxySQL只需要被动接受就好了. (如果无法踢出Master呢? 那只能说遇到了内部bug, 任何软件都可能有bug, 包括MHA ProxySQL, Orchestrator等)

即便是下图的场景, PXC和MGR也能很好地完成选举, 剔除Master和Slave-4

在这里插入图片描述

总结

对于类MHA高可用方案, 需要进行改造以适应中间件.

对于MHA来说:

  1. 要改造masterha_secondary_check脚本, 在二次检测时连接ProxySQL进行主库探活. master_ip_failover也需要改造, 要在failover后删除ProxySQL runtime_mysql_server中原主信息并load
  2. 一定要将半同步超时设置无限大, 避免脑裂

如果放弃MHA, 无论选择Orchestrator, PXC亦或是MGR, 都是MySQL架构上的大变动, 需要长时间的技术调研和测试以及业务方的配合, 这三者任何一个都需要DBA花时间学习, 是否升级架构取决于我们面临的问题是不是最迫切需要解决的, 以及风险可控性(扎实的理论基础和完善的测试可以提高可控性).

那么选择其实就两种:

  • 继续使用MHA或类MHA架构, 需要做二次开发适应ProxySQL
  • 使用PXC或MGR这类"原生"集群方案, 需要实际数据论证当前业务是否可以做这样的架构调整.

个人认为两种都可以, 不过MGR必将是未来金融级高可用方案的事实标准(个人拙见, 据我所知网易,腾讯金融目前就是使用MGR,不过它们对源码做了修改, 这并非中小企业所具备的能力), 但目前仍需等待(发展只有4年), 而PXC已经发展8年了, 目前来看相比MGR更可靠(去哪儿网, 马蜂窝和之前的一些p2p企业都是用PXC), 但任何能保证强一致性的集群都必然会有性能损耗, 还要看业务是否可以接受.

如果用长远的眼光看, 调研并在一些边缘系统实践MGR是需要做的.

如CMDB, 明显的读多写少的系统, 美团点评基于MGR的CMDB高可用架构搭建之路

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值