1. 主从复制

1) 原理

MySQL自己在执行增删改的时候会记录binlog日志
所以这个binlog日志里就记录了所有数据增删改的操作

然后从库上有一个IO线程,这个IO线程会负责跟主库建立一个TCP连接,接着请求主库传输binlog日志给自己,这个时候主库上有一个IO dump线程,就会负责通过这个TCP连接把binlog日志传输给从库的IO线程

接着从库的IO线程会把读取到的binlog日志数据写入到自己本地的relay日志文件中去,然后从库上另外有一个SQL线程会读取relay日志里的内容,进行日志重做,把所有在主库执行过的增删改操作,在从库上做一遍,达到一个还原数据的过程。

简单来说,你只要给主节点挂上一个从节点,从节点的IO线程就会跟主节点建立网络连接,然后请求主节点传输binlog日志,主节点的IO dump线程就负责传输binlog日志给从节点,从节点收到日志后就可以回放增删改操作恢复数据。

2) 异步主从的搭建

A. 开启binlog

要确保主库和从库的server-id是不同的,这个是必然的,其次就是主库必须打开binlog功能,你必须打开binlog功能主库才会写binlog到本地磁盘,接着就可以按如下步骤在主库上执行一通操作了。

B. 创建slave账号

首先在主库上要创建一个用于主从复制的账号:

create user ‘backup_user’@’192.168.31.%’ identified by ‘backup_123’;
grant replication slave on . to ‘backup_user’@’192.168.31.%’;
flush privileges;

C. 主库数据备份,不可用

接着你要考虑一个问题,假设你主库都跑了一段时间了,现在要挂一个从库,那从库总不能把你主库从0开始的所有binlog都拉一遍吧!这是不对的,此时你就应该在凌晨的时候,在公司里直接让系统对外不可用,说是维护状态,然后对主库和从库做一个数据备份和导入。

可以使用如下的mysqldump工具把主库在这个时刻的数据做一个全量备份,但是此时一定是不能允许系统操作主库了,主库的数据此时是不能有变动的。

/usr/local/mysql/bin/mysqldump —single-transaction -uroot -proot —master-data=2 -A > backup.sql

注意,mysqldump工具就在你的MySQL安装目录的bin目录下,然后用上述命令就可以对你主库所有的数据都做一个备份,备份会以SQL语句的方式进入指定的backup.sql文件,只要执行这个backup.sql文件,就可以恢复出来跟主库一样的数据。

至于上面命令里的—master-data=2,意思就是说备份SQL文件里,要记录一下此时主库的binlog文件和position号,这是为主从复制做准备的。

D. 拷贝数据

接着你可以通过scp之类的命令把这个backup.sql文件拷贝到你的从库服务器上去就行了,这个scp命令怎么用就不用我们来说了,大家随便网上查一下就知道这个命令是怎么用的了,这个是很简单的。

E. slave还原数据

接着操作步骤转移到从库上去执行,在从库上执行如下命令,把backup.sql文件里的语句都执行一遍,这就相当于把主库所有的数据都还原到从库上去了,主库上的所有database、table以及数据,在从库里全部都有了。

F. 指定主库进行复制

接着在从库上执行下面的命令去指定从主库进行复制。

CHANGE MASTER TO MASTER_HOST=’192.168.31.229’, MASTER_USER=’backup_user’,MASTER_PASSWORD=’backup_123’,MASTER_LOG_FILE=’mysql-bin.000015’,MASTER_LOG_POS=1689;

master的binlog文件和position是怎么知道的?
这不就是之前我们mysqldump导出的backup.sql里就有,大家在执行上述命令前,打开那个backup.sql就可以看到如下内容:

MASTER_LOG_FILE=’mysql-bin.000015’,MASTER_LOG_POS=1689

然后你就把上述内容写入到主从复制的命令里去了。

G. 开启主从复制

接着执行一个开始进行主从复制的命令:start slave,再用show slave status查看一下主从复制的状态,主要看到Slave_IO_Running和Slave_SQL_Running都是Yes就说明一切正常了,主从开始复制了。

H. 异步复制缺点

这仅仅是最简单的一种主从复制,就是异步复制,就是之前讲过的那种原理,从库是异步拉取binlog来同步的,所以肯定会出现短暂的主从不一致的问题的,比如你在主库刚插入数据,结果在从库立马查询,可能是查不到的。

3) 半同步主从

A. 问题

异步复制,不管从库是否收到数据,万一主库crash了,从库还没收到数据,数据就丢失了。

B. 半同步

半同步的意思是主库写完binlog之后,binlog要保证在从库上页写一份,这样自己宕机了,从库还有一份数据。高可用主从切换后,从变主,数据页是ok的。

C. 实现方式

MySQL 5.7默认的方式,主库把日志写入binlog,并且复制给从库,然后开始等待从库的响应,从库返回说成功给主库了,主库再提交事务,接着返回提交事务成功的响应给客户端。

这种方式可以保证你每个事务提交成功之前,binlog日志一定都复制到从库了,所以只要事务提交成功,就可以认为数据在从库也有一份了,那么主库崩溃,已经提交的事务的数据绝对不会丢失的。

D. 半同步插件安装

搭建半同步复制也很简单,在之前搭建好异步复制的基础之上,安装一下半同步复制插件就可以了,先在主库中安装半同步复制插件,同时还得开启半同步复制功能:

install plugin rpl_semi_sync_master soname ‘semisync_master.so’;
set global rpl_semi_sync_master_enabled=on;
show plugins;

可以看到你安装了这个插件,那就ok了。

接着在从库也是安装这个插件以及开启半同步复制功能:

install plugin rpl_semi_sync_slave soname ‘semisync_slave.so’;
set global rpl_semi_sync_slave_enabled=on;
show plugins;

接着要重启从库的IO线程:stop slave io_thread; start slave io_thread;

然后在主库上检查一下半同步复制是否正常运行:show global status like ‘%semi%’;,如果看到了Rpl_semi_sync_master_status的状态是ON,那么就可以了。

E. 建议

到此半同步复制就开启成功了,其实一般来说主从复制都建议做成半同步复制,因为这样配合高可用切换机制,就可以保证数据库有一个在线的从库热备份主库的数据了,而且主要主库宕机,从库立马切换为主库,数据不丢失,数据库还高可用。

4) GTID搭建主从

A. 主库配置

gtid_mode=on
enforce_gtid_consistency=on
log_bin=on
server_id=单独设置一个
binlog_format=row

B. 从库配置

gtid_mode=on
enforce_gtid_consistency=on
log_slave_updates=1
server_id=单独设置一个

C. 创建slave账号

首先在主库上要创建一个用于主从复制的账号:

create user ‘backup_user’@’192.168.31.%’ identified by ‘backup_123’;
grant replication slave on . to ‘backup_user’@’192.168.31.%’;
flush privileges;

D. 备份主库数据

E. 导入主库数据到从库

利用mysqldump备份工具做的导出,备份文件里会有SET @@GLOBAL.GTID_PURGED=*一类的字样,可以照着执行一下就可以了。

F. 校验

show master status,可以看到executed_gtid_set,里面记录的是执行过的GTID,接着执行一下SQL:select * from gtid_executed,可以查询到,对比一下,就会发现对应上了。
那么此时就说明开始GTID复制了。

5) 数据延迟问题

A. 监控

那么这个主从之间到底延迟了多少时间呢?这个可以用一个工具来进行监控,比较推荐的是percona-toolkit工具集里的pt-heartbeat工具,他会在主库里创建一个heartbeat表,然后会有一个线程定时更新这个表里的时间戳字段,从库上就有一个monitor线程会负责检查从库同步过来的heartbeat表里的时间戳。

把时间戳跟当前时间戳比较一下,其实就知道主从之间同步落后了多长时间了,关于这个工具的使用,大家可以自行搜索一下,我们这里就不展开了,总之,主从之间延迟了多长时间,我们这里实际上是可以看到的。

B. 影响

如果你做了读写分离架构,写都往主库写,读都从从库读,那么会不会你的系统刚写入一条数据到主库,接着代码里立即就在从库里读取,可能此时从库复制有延迟,你会读不到刚写入进去的数据!

没错,就是这个问题,这是我们之前也经常会遇到的一个问题。另外就是有可能你的从库同步数据太慢了,导致你从库读取的数据都是落后和过期的,也可能会导致你的系统产生一定的业务上的bug。

C. 解决

所以针对这个问题,首先你应该做的,是尽可能缩小主从同步的延迟时间,那么怎么做呢?其实就是让从库也用多线程并行复制数据就可以了,这样从库复制数据的速度快了,延迟就会很低了。

MySQL 5.7就已经支持并行复制了,可以在从库里设置slave_parallel_workers>0,然后把slave_parallel_type设置为LOGICAL_CLOCK,就ok了。

另外,如果你觉得还是要求刚写入的数据你立马强制必须一定可以读到,那么此时你可以使用一个办法,就是在类似MyCat或者Sharding-Sphere之类的中间件里设置强制读写都从主库走,这样你写入主库的数据,强制从主库里读取,一定立即可以读到的。

2. 高可用

A. 工具介绍

一般生产环境里用于进行数据库高可用架构管理的工具是MHA,也就是Master High Availability Manager and Tools for MySQL,是日本人写的,用perl脚本写的一个工具,这个工具就是专门用于监控主库的状态,如果感觉不对劲,可以把从库切换为主库。

这个MHA自己也是需要单独部署的,分为两种节点,一个是Manager节点,一个是Node节点,Manager节点一般是单独部署一台机器的,Node节点一般是部署在每台MySQL机器上的,因为Node节点得通过解析各个MySQL的日志来进行一些操作。

Manager节点会通过探测集群里的Node节点去判断各个Node所在机器上的MySQL运行是否正常,如果发现某个Master故障了,就直接把他的一个Slave提升为Master,然后让其他Slave都挂到新的Master上去,完全透明。

B. 搭建准备

首先,大家最好是准备4台机器,其中一台机器装一个mysql作为master,另外两台机器都装mysql作为slave,然后在每个机器上都得部署一个MHA的node节点,然后用单独的最后一台机器装MHA的master节点,整体就这么一个结构。

首先,大家得确保4台机器之间都是免密码互相通信的,这个大家可以自行搜索一下,大量的方法可以做到,就是4台机器之间要不依靠密码可以直接ssh登录上去,因为这是MHA的perl脚本要用的。

接着大家就应该部署一个MySQL master和两个MySQL slave,搭建的过程就按照之前讲解的就行了,先装好MySQL,接着进行主从复制的搭建,全部按照之前的步骤走就行了,可以选择异步复制,当然也可以是半同步复制的。

C. 搭建步骤

今天我们正式来讲解MHA数据库高可用架构的搭建,先来讲解一下在三个数据库所在机器上安装MHA node节点的步骤,首先那必须要先安装Perl语言环境了,这就跟我们平时用Java开发,那你必须得先装个JDK吧!

可以用yum装一下Perl语言环境:yum install perl-DBD-MySQL

然后从下述地址下载MHA node代码:https://github.com/yoshinorim/mha4mysql-node,接着就可以把node的压缩包用WinSCP之类的工具上传到机器上去,接着解压缩node包就可以了,tar -zxvf mha4mysql-node-0.57.tar.gz。

然后可以安装perl-cpan软件包:

cd mha4mysql-node-0.57
yum -y install perl-CPAN*
perl Makefile.PL
make && make install

到此为止,暂时node的安装就可以了,记得3个部署MySQL的机器都要安装node,接着就是安装MHA的manager节点,先安装需要的一些依赖包:

yum install -y perl-DBD-MySQL*
rpm -ivh perl-Params-Validate-0.92-3.el6.x86_64.rpm
rpm -ivh perl-Config-Tiny-2.12-1.el6.rfx.noarch.rpm
rpm -ivh perl-Log-Dispatch-2.26-1.el6.rf.noarch.rpm
rpm -ivh perl-Parallel-ForkManager-0.7.5-2.2.el6.rf.noarch.rpm

接着就可以安装manager节点了,先在下面的地址下载manager的压缩包:https://github.com/yoshinorim/mha4mysql-manager,然后上传到机器上去,按照下述步骤安装就可以了:

tar -zxvf mha4mysql-manager-0.57.tar.gz
perl Makefile.PL
make
make install

接着为MHA manager创建几个目录:/usr/local/mha,/etc/mha,然后进入到/etc/mha目录下,vi mha.conf一下,编辑他的配合文件

[server default]
user=zhss
password=12345678
manager_workdir=/usr/local/mha
manager_log=/usr/local/mha/manager.log
remote_workdir=/usr/local/mha
ssh_user=root
repl_user=repl
repl_password=repl
ping_interval=1
master_ip_failover_script=/usr/local/scripts/master_ip_failover
master_ip_online_change_script=/usr/local/scripts/master_ip_online_change

[server1]
hostname=xx.xx.xx.xx
ssh_port=22
master_binlog_dir=/data/mysqll
condidate_master=1
port=3306

[server1]
hostname=xx.xx.xx.xx
ssh_port=22
master_binlog_dir=/data/mysqll
condidate_master=1
port=3306

[server1]
hostname=xx.xx.xx.xx
ssh_port=22
master_binlog_dir=/data/mysqll
condidate_master=1
port=3306

上面那份配置文件就可以指导MHA manager节点去跟其他节点的node通信了,大家可以观察到,上面说白了都是配置一些工作目录,日志目录,用户密码之类的东西,还有一些脚本,另外比较关键的是,你有几个node节点,就配置一个server,把每个server的ip地址配置进去就可以了

接着创建存放脚本的目录:/usr/local/scripts,在里面需要放一个master_ip_failover脚本,vi master_ip_failover就可以了,输入下面的内容:

接着在编辑一下online_change这个脚本,如下:

完事儿过后,就可以给两个脚本增加权限:

chmod +x master_ip_failover
chmod +x master_ip_online_change

接着安装需要的软件包:yum -y install perl-Time-HiRes
执行SSH检测命令:/usr/local/bin/masterha_check_ssh —conf=/etc/mha/mha.conf
如果检测结果全部显示为OK,那么就代表你安装完毕了
然后检测主从架构:/usr/local/bin/masterha_check_repl —conf=/etc/mha/mha.conf
如果检测结果全部正常,那么就代表没问题了

D. VIP

首先,要在MySQL主库所在的机器上去添加VIP,所谓VIP就是虚拟VIP地址,这个大家可以关注一下,不懂的自行搜索,是一个重要的网络概念。

ip addr add xx.xx.xx.xx dev eth0,这里的xx.xx.xx.xx,就是你自定义的一个VIP地址

接着就可以启动MHA manager节点了,在MHA manager所在机器上执行下述命令:nohup masterha_manager —conf=/etc/mha/mha.conf > /tmp/mha_manager.log < /dev/null 2>&1 &,这就可以启动MHA的manager节点了

接着验证一下启动是否成功:masterha_check_status —conf=/etc/mha/mha.conf,此时只要看到MHA manager正常工作就行了,接着就可以测试一下数据库高可用了,比如你可以先把主库停了:mysqladmin -uroot -proot shutdown

然后从库会自动获取到主库机器上的VIP的,同时从库会被转换为新的主库,其他从库也会指向新的主库,这些都是MHA自动给你完成的,然后你可以把宕机的主库重新启动,然后把他配置为从库,指向新的主库就可以了

整体来说,数据库的高可用架构就是这么个意思,其实搭建虽然很繁琐,但是只要搭建好了,基本就是比较自动化的了,相信大家结合之前的一些内容,应该都能理解,只不过在搭建的过程中可能会遇到一些小问题,可以自己尝试去解决一下。