# 一、应用访问形式
MySQL
高可用的前提就是当进行了Master
和Slave
的切换之后,需要让应用进行感知,否则即使切换完成了,应用也是无法访问的。所以首先要从架构上对访问的情况进行梳理。

【1】通过Tian/Dal
访问数据库,通过从QConfig
配置文件中拿到具体的IP
(动态数据源)配置去访问数据库。如果发生切换之后,切换信息会同步到QConfig
然后对DAL
信息进行重新的推送,然后就会应用就会感知到IP
发生了变化。
【2】通过Data Source Configuration
访问数据库,在python/C++
的直连应用中比较多。这种场景可能会依赖DNS Server
。如果发生了DNS
切换,应用服务器需要刷新DNS
缓存,刷新了DNS
缓存之后,才能感知到DNS
服务发生了变化,感知到变化之后应用才能去访问数据库。有两种情况:一种是对VIP
的UP
和DOWN
这种VIP
是不会变的,那么应用会立马感知到。另一种是进行DR
切换,将DNS
切换到了另一个机房,此时DNS
底层的IP
发生了变化,此时就依赖应用下面的DNS
缓存来解决这个问题。DNS
缓存刷新时间,就是你最终切换的时间。所以有时候Python
直连应用感知变化的时间比Tian
调的时间长。
# 二、复制架构
MySQL
复制架构按照机房级别分为如下两种情况:
【1】在两个IDC
部署MySQL
服务器,其中IDC1
部署Master-Slave
,IDC2
只部署一个Slave
。假设IDC1
挂掉之后,会切换到IDC2
。如果只是Master
关掉,会在IDC
内进行一次切换,从而实现灾备的配置。而IDC1
骨干节点一般是内网,理论IDC1
中的Slave
比IDC2
中的Slave
的内容更全更新(主要从物理距离考虑)。

【2】我们有的DR
节点是上了阿里云的,这种场景所有的切换都是DR
切换,这种三机房的DR
部署,优先切换到IDC2
。因为是骨干网,延迟比较低。阿里云走的专线,延迟相对比较长。

# 三、半同步复制
MySQL
采用的复制方式都是半同步复制方式,半同步对数据的保护程度是最好的,在了解半同步复制之前,我们先看下MySQL
的两阶段提交问题。
当客户端进行Commit
的时候,首先会写入binlog
,此时会将事务置为prepare
状态,binlog
写完之后回向Slave
节点发送一个ACK
请求。确定binlog
是否传到了Slave
并且Slave
生成了relaylog
<a href='http://localhost:8080/blogs/db/replay.html'target='_blank'>中继日志,生成之后Slave
会向Master
回馈ACK
。此时Master
才会向引擎层进行写入并向Client
返回OK
别的事务才会看到。半同步复制可以保证在超时的情况下,一定有一个Slave
拥有最新的数据。还有一个优点,就是当在ACK
的时候挂掉了,那么在Slave
上拿到的中继日志一定是最新的,从而保证数据不丢失。从而保证我们在主从切换过程中,丢数据的概率大大降低。

# 四、CMHA
如下实际生产部署的高可用架构信息,我们的高可用是基于MHA
架构完成的,MHA
是一个日本工程师发明的设计工具。我们对MHA
封装之后称为CMHA
。CMHA
有两个核心主键: MySQL Sentinel
哨兵,基于Redis
哨兵进行了修改。哨兵模式的机制是探活Master
和Slave
节点,同时还要探活Slave
节点到Master
节点可通,比较重要,假设应用发现Master
连不上Slave
可以连接上,但是Slave
和Master
是通的,所以需要去验证一下,因为有可能是哨兵的节点和Master
节点不通而已。MHA
不仅仅保证主从的切换,还会保证数据的一致性。首先,MHA
会在MySQL Cluster
中找到最新的later slave
,然后从Master
上将日志补录到此Slave
中,最后才会发起切换。
MySQL Sentinel
和MHA
依赖上游的eosdb
,eosdb
是一个特殊的MHA
架构,主要的作用是存储一些元数据,包括DB
和dal
层面的元数据。同时,MHA
节点还依赖consul kv
可以理解为zookeeper
,拥有分布式选主的能力,还作为eosdb
的缓存,主要作用就是防止发生大面积的切换eosdb
有可能扛不住,所以通过consul kv
作为缓存层,减少eosdb
的压力。

实际切换流程:CMHA
发现Master
挂掉后会发起一次主从切换,CMHA
会通知三个主键:DNS Server
是否需要切换IP
、Dal Cluster
是否需要切换IP
、QConfig
会拿到新的IP
然后推送给应用,CMHA
还会去更新eosdb
中的数据。如果应用不是走QConfig
配置,是通过Data Sorce
、Configuration
等,就可能会因为DNS Server
什么时候切换完成,并在应用层将DNS Server
缓存更新完之后,才会自动将DNS
切换到New Master
上,这个时候应用才会感知到,此时切换流程就完成了。
因为MySQL
是一个有状态的服务,与应用层不同,应用层我们想切那个就切那个,Mysql
会碰到一致性问题。有几种情况会存在数据不一致性问题:假设Master crash
了,此时Master
日志还在,通过将Master
日志应用到New Master
上,此时New Master
的数据就是最新的。还有一种情况,假设Master
节点不是crash
的,而是有很多类似演练的这种大规模的网络切换,会存在一个问题,Master
节点没有死透,还有应用节点在访问,CMHA
做切换以后,New Master
有新的应用连接进来,此时两边都在写,就会出现脑裂问题。此时,我们会对Old Master
进行补刀,同时会对已经写入的Old Master
上的binlog
和New Master
的binlog
进行比较,通过业务来判断哪些数据是需要的哪些是不需要的,这个是当前架构解决不了的问题。
