1.mysql-utilities工具集简介
它是类似于percona-toolkit的一套工具集,只不过是由Oracle官方出品的。它本身提供了非常多的工具:
mysqlauditadmin
mysqlauditgrep
mysqlbinlogmove
mysqlbinlogpurge
mysqlbinlogrotate
mysqldbcompare
mysqldbcopy
mysqldbexport
mysqldbimport
mysqldiff
mysqldiskusage
mysqlfailover
mysqlfrm
mysqlgrants
mysqlindexcheck
mysqlmetagrep
mysqlprocgrep
mysqlreplicate
mysqlrpladmin
mysqlrplcheck
mysqlrplms
mysqlrplshow
mysqlrplsync
mysqlserverclone
mysqlserverinfo
mysqlslavetrx
mysqluc
mysqluserclone
看这些工具的名字就大概知道它的用途了。这次我们需要使用到的主要是其中两个工具:mysqlrpladmin和mysqlfailover。这两个工具可以实现MySQL的master的自动切换和手动切换,解决主库的HA问题。
2.官方文档、代码
代码在github上,开源,oracle官方主推的mysql管理相关的工具集。
我们这次主要关心的是它的failover模块。
代码地址:https://github.com/mysql/mysql-utilities.git
我对代码做了一些注释,添加了HA切换过程中的extention point脚本:
代码位置:ssh://git@git.sankuai.com/~alex/mysql-utilities.git。权限已经开放,dba组员可以直接clone。
除了对代码添加部分注释外,也添加了4个简单的hook脚本,以及搭建和准备mysql ha环境需要的各种命令:
官方文档位置:http://dev.mysql.com/doc/index-utils-fabric.html
这里可以下载html、pdf等版本的官方文档。
3.环境和安装
- linux下的最新版本:wget https://www.python.org/ftp/python/2.7.10/Python-2.7.10.tgz
- 然后解压
- mkdir /usr/local/python27
然后安装python
./configure --prefix=/usr/local/python27
sudo make
sudo make install
- 安装对应的mysql工具集:sudo /usr/local/python27/bin/python setup.py build
- 安装mysql-connector依赖包:使用pip安装即可
4.工具集介绍-mysqlrpmadmin、mysqlfailover
主动切换的工具:mysqlrpladmin
该工具用来执行有计划的主库切换。所有有计划,就是由DBA主动触发的切换。这也分为两种场景:
场景1:
master状态ok,希望切换到slave。在这种场景下,数据库不会丢失任何数据。
切换命令:
./scripts/mysqlrpladmin.py --master=mysql01 --new-master=mysql02 --discover-slaves-login=login_into_slave --demote-master --verbose --rpl-user=rpl:rpl switchover
命令说明:
当前mysql01是主库,它的状态是ok的。希望切换到mysql02上。切换后,mysql01将变成mysql02的从库(这是--demote-master来控制的)。
场景2:
master已经挂了。而且我们的自动化切换程序没有正常工作。那么我们现在不得不手动来切换。
切换命令:
./scripts/mysqlrpladmin.py --slaves=mysql02,mysql03,mysql04 --candidates=mysql02 failover
命令说明:
现在已经明确知道mysql01挂掉了。而且它在挂掉之前,有3个从库:mysql02、mysql03、mysql04。DBA在处理故障时, 决定让mysql02作为新的主库。执行上述命令即可。
两个extention point
--exec-after=EXEC_AFTER 在切换之后执行的脚本。比如发送邮件或短信报警,比如修改中间层配置,把老的主库替换为新的配置后重启中间层,比如修改cmdb的配置等。
--exec-before=EXEC_BEFORE 在failover开始之前需要执行的脚本,比如发送通知邮件,比如把老的主库设置为read only,比如检查老的主库上是否有慢查询等,根据情况来看是否可以切换。
该工具还支持如下命令:
health:显示当前mysql集群的复制状态,是否正常,有没有延迟,有没有错误
elect:发起选举。模拟一次选举流程,看哪个从库会被选中。(选择新主库的流程非常简单暴力,就是看从库是否活着,IO、SQL thread有没有在工作,同步是否有延迟,如果这3个条件都是好的,则就是它了!即选择第一个满足这3个条件的从库作为继承人!)。看起来很简单暴力,但是在gtid场景下,继承人接下来会change master to到剩下的所有从库上,把所有数据都同步过来,然后reset slave all;然后把剩下的所有从库都指向它。这就完成了binlog对齐的功能。
gtid:显示所有nodes的gtid相关的信息。
reset、start、stop:在制定的从库上执行reset、stop、start命令。
加上上面的failover与switchover命令,mysqlrpladmin工具让DBA非常灵活的管理集群的复制。
自动切换的工具:mysqlfailover
mysqlfailover工具可以作为daemon进程,不间断的监控集群master的状态,一旦发现master挂掉,则会自动执行切换逻辑。
其工作原理如下:
- 不间断的监控主库的状态,连续3次,每次间隔5秒,ping主库,如果发现主库挂了,则准备发起切换
- 如果指定了候选主库,则使用候选主库作为新的主库;如果没有指定候选主库或者候选主库的状态不对,则会指定发现的某个从库作为继承人;如果找不到继承人,则不切换
该工具有如下3种工作模式:
auto:当发现主库挂了,自动发起切换
elect:同上,但是如果candidates列表上的服务器不可用,则报错并退出------也即不考虑candidates列表之外的从库,即使它们可能是可以作为候选主库的
fail:只监控,但是不实际发起切换(这个特点可以被我们利用,如利用这样的节点参与投票但是不参与切换)
举例1:启动监控
./scripts/mysqlfailover.py --master=mysql01 --discover-slaves-login=login_into_slave --interval=5 --pid=./pid/mfa1.pid --log=./log/mfa1.log --daemon=start
命令说明:
监控主库mysql01,自动发现从库。以daemon方式运行,日志文件为mfa1.log。这里没有指定候选的主库,所以当主库挂掉后,所有被discover的从库都有可能成为新的主库。
举例2:停止监控
./scripts/mysqlfailover.py --master=mysql01 --discover-slaves-login=login_into_slave --interval=5 --pid=./pid/mfa1.pid --log=./log/mfa1.log --daemon= stop
命令说明:停掉对mysql01的监控。程序会查找对应的pid文件,找到pid后,停掉监控。
举例3:指定extention point脚本
./scripts/mysqlfailover.py --master=mysql01 --discover-slaves-login=login_into_slave --interval=5 --log=./log/mfa1.log --exec-before="/home/sankuai/mysql-utilities/6.exec_before.sh" --exec-after="/home/sankuai/mysql-utilities/7.exec_after.sh" --exec-post-failover="/home/sankuai/mysql-utilities/9.exec_post_failover.sh" --pid=./pid/mfa1.pid --force --daemon=start
命令说明:
监控mysql01,自动发现从库,每隔5秒发送一次检测命令。在切换之前,执行脚本/home/sankuai/mysql-utilities/6.exec_before.sh中的内容,切换之后执行/home/sankuai/mysql-utilities/7.exec_after.sh中的内容;在切换全部完成后,执行/home/sankuai/mysql-utilities/9.exec_post_failover.sh中的命令。
--force的意思是,如果之前已经有mysqlfailover进程在监控mysql01这一套数据库了,那么这次启动加上–force的话,这个程序将会以fail模式运行,也就是发现主库挂了则本进程只报警,但是不切换。这是为了避免当发现主库挂了以后,多个进程同时执行切换过程而导致事故。
3个extention point
前面我们看到,mysqlrpladmin工具有两个extention point。但是mysqlfailover工具除了上述2个extention point,还多了一个--exec-post-failover。
--exec-post-failover指定的脚本可以用来发送短信或大象通知,以及重启某些程序,或者自杀,都可以,非常灵活。
注意:自动切换和主动切换是两种不同的使用场景。自动切换和主动切换都支持hook脚本,这样我们就只需要写一套hook脚本,就可以把自动切换和主动切换统一起来。
重写认定主库挂掉的逻辑
在监控节点本身是单点的情况下,认定master挂掉是非常难的事情。特别是网络不稳定的情况下,几乎是不可能的事情。所以,作者也提供了extention point,让我们可以改写这个认定主库挂掉的逻辑。
这个脚本通过--exec-fail-check选项来指定。
5.部署mysqlfailover需要满足的前提条件
6.mysqlfailover和mysqlrpladmin工具如何检测errant transactions
这两个工具在切换之前,都会去检测从库上是否存在errant transactions。如果存在,而且mysqlfailover在启动的时候加上了--pedantic选项,则mysqlfailover程序会拒绝切换。如果没有加上--pedantic选项,则工具仍然会切换,同时也会发出警告。
errant transactions的定义如下:
如果从库上存在这样的gtid集合,则可能导致切换事故。所以mysqlfailover工具对有错误倾向的事务进行了检测。
其检测原理如下:
由于集群中的每个实例,都有可能在未来的某个时刻作为主库,所以,对于每一个当前是从库的实例,如果发现该实例上有一个或多个gtid只存在于该实例上,那么它就是errant transactions。(对于主库,我们不能这样来判断。因为,从库可能有延迟,这样就可能存在某gtid在检测的时候只存在于主库上。但是对于从库,如果发现某个gtid只在一个从库上,则肯定是errant transaction)
errant transaction会被查找出来,并提示DBA要么使用--pedantic选项来强制修复,要么忽略。
注意:对于这个问题,无论我们将来使用mysqlfailover还是MHA,我们都会写专门的工具来周期性检测errant transactions,如果发现问题则要修复。
7.mysqlfailover如何避免多个实例监控同一套mysql资源而导致同时切换的问题
mysqlfailover程序在启动的时候,如果是处于auto或elect模式,则会自动在mysql库下,建立如下的表:
CREATE TABLE `failover_console` (
`host` char(30) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
`port` char(10) COLLATE utf8mb4_unicode_ci DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
同时把该进程监控的mysql资源的master的host与port写入到该表中。例如,某mysqlfailover进程监控的是10.32.86.218:5002,则会在该表中插入如下数据:
当任何其他服务器上的mysqlfailover程序启动了,而且也监控这一套资源时,会先查询这个表,发现这个表已经有这行数据,就知道有人已经在监控这套资源了。为了避免多个mysqlfailover程序同时监控&在出现故障的时候同时切换,后启动的mysqlfailover程序会自动从auto或elect模式降级为fail模式,从而在它检测到故障的时候只报警而不切换。切换的任务还是交给先启动的mysqlfailover程序。
那么,当先来的mysqlfailover程序停止的时候,会先把自己注销掉,直接delete对应的数据,然后drop failover_console表。
注意:所有对failover_console表的操作,都会设置set sql_log_bin=0,也即不会记录任何binlog。以免因为自己的原因而出现errant transactions。
作者把这个表放到mysql权限库,让人非常费解,从安全的角度来说,放到任何一个其他的库都比这个库好。
8.优缺点对比-主要对比mysqlfailover与MHA
mysql-utilities优点:
- mysqlfailover原生的对mysql服务down的判断逻辑非常简单,但是它提供了3个extention point,可以触发各种脚本。可以使用自己的逻辑来取代官方的失败检测逻辑。
- mysqlfailover工具因为不考虑master服务器上,mysql死掉而os存活情况下的master上的binlog的获取过程,所以,mysqlfailover不需要任何ssh信任关系设置,因此安全性较高。
- 部署简单,只需要在管理机上部署mysql-utilities代码和mysql-connector python包即可。mysql数据库上不需要安装额外的包,也不需要启动agent。
- mysqlfailover工具是在mysql支持GTID特性之后才出现在mysql-utilities工具集中,吸取了MHA的很多思想,而且使用纯python实现,从改造的角度来说,代价较小。
- mysqlfailover在切换之前会进行errant transactions的检测,可以避免错误的切换。而这一点MHA并不支持,只能自己实现。
mysql-utilities缺点:
- mysqlfailover只支持5.6的基于gtid的切换。因此,5.5的mysql集群无法实现主库的高可用。鉴于我们现在有较多的5.5版本mysql,这可能是我们要考虑的问题。
- mysqlfailover因为不需要ssh,因此,数据的一致性和不丢数据这两个终极需求,只能依靠semi-sync来实现。否则,master死掉而os存活的情况下,mysqlfailover对binlog的保护弱于MHA。
- mysqlfailover的文档太少,而且在生产环境上的真实案例比较少,容易掉到坑里;而MHA则是非常成熟的技术,品质有保证。
- mysqlfailover虽然是Oracle官方推荐的HA工具,但是它的代码更新频率非常低,这从官方的commit log中可以看出来;而且对bug的反应速度比较慢。
- mysqlfailover工具依然是单点,只允许同一时刻只有一个进程处于auto或elect工作模式。如果要部署多个进程来监控同一套mysql资源,则后启动的进程只能处于fail模式。当mysqlfailover进程处于fail模式的时候,发现主库故障则只是报警,而不切换。所以,mysqlfailover本质上还是一个单点。
- mysqlfailover不支持mysqlbinlog server,这可能不利于我们以后在所有业务线上推广semi-sync,特别是写入密集的业务上。
- 为了方便从库的检测,需要加上report-host与report-port(非强制)。
- mysqlfailover程序自身使用的账号需要的权限非常大,还需要with grant option权限,这可能带来一些安全问题。
说明:copy from 美团点评 http://wiki.sankuai.com/pages/viewpage.action?pageId=374054749