实现高可用性的原则很简单:
只要有单点故障(SPOF:Single Point of Failure)的存在,就无法保证系统的高可用性(关于单点故障可以参考Fenng的这篇文章,比较通俗易懂)。
为了搞清楚哪里需要冗余机制,我们需要找到部署中所有潜在的单点。虽然说起来简单,但是需要一点想象力,以确保真正找到全部单点。交换机,路由器,网卡甚至电缆都是单点,除了这些,电源和物理设施也很重要。还有一些也为成为单点,比如只有一个员工知道如何处理某种类型的故障,所有的网络都被集中到一个web页面进行管理等。但定位到所有的单点并不意味着你必须要全部消除它们,因为有些单点或许因为经济上,技术上或者地理上的原因而无法完全消除,但知道这些单点的存在将有助于出错时排错。
在考虑要不要消除某个单点,有些因素需要考虑:复制组件的成本,不同组件发生故障的概率,替换组件的时机以及修复组件时的担当的风险。比如你替换一个组件需要一周时间,在这一周期间,运行中的备用组件也有可能出现故障,这些你都必须要考虑到。
一旦确定要消除的单点,接下来就需要考虑如何建立冗余机制,有两种方案可供选择:1)为每一个组件建立一个备用组件,如果原始组件发生故障,立即启用备用组件;2)系统本身有额外的容量,当一个组件出现故障时仍能hold住。第一种方案,虽然看起来简单,但是成本高。你必须让备用组件处于standby状态,一直和主组件保持一致。其优点就是在切换组件的时候不会损失性能,而且切换到standby组件所花的时间通常要比重新构建组件快。方案二为系统构建额外容量的方案可以让你使用所有组件(资源)来运行系统,这样系统可以处理更高的瞬间峰值负载。但有一点必须明白,这种方案时,系统必须拥有额外的容量以保证在某些组件出现故障时系统仍然能hold住。有时候只为一个服务器发生故障留有余地还不够,这个时候你需要权衡,以及这种情况出现的概率是多少。比如安装了100台服务器,其中一台服务器发生故障的概率是1%,那么1台,2台,3台服务器发生故障的概率会是多少呢?根据二项式定理计算可得到依次为100%,20.33%,16.17%。
只做冗余还是不够,当你一个组件发生故障时,你还需要知道如何去应对。在之前的例子里,当Slave服务器出现故障时很容易去处理,因为只需把新的连接全部重定向到能工作的Slave服务器,同时你需要考虑:1)现有的连接怎么处理?仅仅中止程序并给用户返回一个出错信息明显不是一个好主意。通常情况下,在用户和数据库之间有一个应用层,这个时候应该让应用层向别的服务器提交查询;2)如果Master发生故障怎么处理?假设你已经提供了一个额外的Master做冗余,你还必须提供机制让所有Slave重定向新的Master。
下面介绍一下如何处理各种拓扑结构下MySQL服务器宕机的技术。一般来说,需要考虑三种角色:Master,Slave,Relay。
如果你管理一个小站点,你可以不用规划并手动管理这些服务器,但是随着服务器数量的快速增长,自动化就变得很有必要。特别是下列的这些工作:
最简单的复制服务器的拓扑就是热备份的拓扑。该拓扑结构里面包括一个Master和一个被称作热备份的专用服务器。工作原理就是当Master发生故障时,热备份立即充当Master的镜像服务器,所有的客户端和Slave服务器全部切换到热备份服务器进行工作。不过切换的时候需要考虑一些细节的问题:1)当切换到热备份的服务器时,你需要重新定位需要从哪里开始复制二进制日志,一般热备份的日志位置信息和Master不一样;2)某个Slave可能需要的二进制日志在热备份服务器上不一定有;3)当修好的Master切换回来的时候,它上面的有些修改可能任何其他Slave都未来得及复制。
首先,问题简单化,我们看看从Master切换到热备份服务器的过程,该过程Master并不宕机。默认情况下,slave线程执行的事件并不写入二进制日志,但是作为热备份的slave明显是需要这些二进制日志的,所以为热备份服务器增加这样一个参数。
[mysqld]
log-slave-updates
切换时的主要问题在于,如何使得从热备份服务器开始复制的位置和从Master停止复制的位置完全相同。有很多原因可以使得热备服务器和Master服务器的二进制日志位置信息不一致,比如Master启动的时候热备份服务器并没有连上,即使这个没问题,也不能保证同一个事件写入Master和热备份服务器二进制日志的过程和时机完全一样。
切换的基本思路是:确认让slave和热备份服务器在同一点上停止复制,然后让salve连到热备份服务器。
standby>SHOW SLAVE STATUS\G
...
Relay_Master_Log_File: master-bin.000096
...
Exec_Master_Log_Pos: 756648
slave>SHOW SLAVE STATUS\G
...
Relay_Master_Log_File: master-bin.000096
...
Exec_Master_Log_Pos: 743456
# 从上可知说明热备份服务器的日志位置要领先于Slave,所以需要让Slave从Master继续复制到和热备份一样的位置
slave>START SLAVE UNTIL MASTER_LOG_FILE = 'master-bin.000096' MASTER_LOG_POS = 756648;
slave>SELECT MASTER_POS_WAIT('master-bin.000096', 756648);
# 现在Slave和热备份服务器都在同一个点停止复制,就可以让Slave连到热备份服务器上,但是指定从哪个文件和位置开始复制呢。对于同一个复制点在Master上的文件和位置和热备份上的文件和位置是不一样的。
standby>SHOW MASTER STATUS\G
File: standby-bin.000019
Position: 56447
Binlog_Do_DB:
Binlog_Ignore_DB:
slave>CHANGE MASTER TO
MASTER_HOST = 'standby-1',
MASTER_PORT = 3306,
MASTER_USER = 'repl_user',
MASTER_PASSWORD = 'xyzzy',
MASTER_LOG_FILE = 'standby-bin.000019',
MASTER_LOG_POS = 56447;
slave>START SLAVE;
如果Slave的复制位置在热备份服务器之前的话,我们只需互换一下上面的步骤。下一节我们将考虑如何处理Master意外停止的情况。
双Master拓扑结构中,两个Master互相复制数据以保持同步。因为是对称的,这种设置容易使用。这种设置中,服务器可以是主动的(active),也可以是被动(passive)的。主动的服务器是指接受写操作,然后这些变化通过复制传播到其他Slave上。被动的服务器是指不接受写而仅仅是跟随主动Master,随时准备切换。两个服务器有两种设置,一种是active-active,一种是active-passive,第二种很像热备份的的拓扑,带是由于是对称,切换起来比较方便。在双Master配置中,passive服务器并不一定要求接受读请求,这个时候其实就是一个冷备份。在双Master的拓扑中,并不一定非要通过复制来保证两个Master的同步。
active-active型双Master的常用的一个场景就是让服务器在物理上接近不同的用户组。用户使用本地服务器,更改会被复制到另外一台服务器来保持两者同步。由于事务是在本地提交的,所以响应比较快。但由于事务是本地提交的,两个服务器并不是时时刻刻完全一致的。这就会有些问题:1)如果同一个信息在两台服务器上更新,将会服务器将会产生冲突,复制也会终止。你可以只让其中一台接受写操作,可以在某种程度上避免冲突的发生。2)如果两台服务器在处于不一致状态下发生故障,有些事务将会丢失,这也是异步复制的硬伤,不过你可以通过使用半同步复制(MySQL 5.5引入)来限制事务丢失的个数。
对于active-passive型的来说,你可能使用passive的Master来做服务器升级这样的管理工作。active-passive有一个根本性的问题需要解决。split-brain syndrome:当网络连接短时间内中断,从而使得从服务器主动升级为主服务器,然后网络又恢复了。如果在他们各自为主服务器的时间里,更改在两台服务器上都执行就会产生冲突。当使用共享磁盘的方式时,两台服务器同时写磁盘会产生有趣的问题。
对于如何实现双Master直接的同步,有几种方案。
这是最直接的双Master方案:两个Master通过一个像SAN(Storage Area Network)的共享磁盘架构连接在一起,并被设置成使用相同的文件。因为其中一个是passive,它不会写任何东西到文件中,