MariaDB主从复制
MySQL的二进制日志(binglog)会记录所有对数据库进行更改的操作,也就是说只要是会对数据库产生修改的操作都会被记录到二进制日志中去。
记录二进制日志的主要目的有两方面:
1. 恢复
2. 复制
MySQL的复制就是基于二进制日志而完成的,其工作原理如下:
当MySQL的Master节点的数据有更改的时候,Master会主动通知Slave,让Slave主动来Master获取二进制日志,于是Slave开启一个I/O thread,向Master请求二进制日志中记录的语句;Master将二进制日志中记录的语句发给Slave,Slave则将这些语句存到中继日志中,进而从中继日志中读取一句,执行一句,直到所有的语句被执行完。而经SQL语句从中继日志中读取出来,再一一执行的进程叫做SQL thread;将这些语句执行完之后,从节点的数据就和主节点的数据相同了,这就是所谓的MySQL主从复制。
由MySQL的主从复制原理可知:
l Master节点必须开启二进制日志功能
l Slave节点必须开启中继日志功能
l Slave节点需关闭二进制日志功能(默认不配置即可)
l Master和Slave节点需要配置不同的server-id
l Slave节点需连接到Master节点
半同步复制介绍
默认情况下,MySQL 5.5/5.6/5.7和MariaDB 10.0/10.1的复制功能都是异步的,异步复制的情况下可以提供最佳的性能。但是如果从节点没有接收到主节点发送过来的binlog日志时,会造成主从节点的数据不一致,甚至在恢复时造成数据丢失。
为了解决异步复制的数据丢失的问题,MySQL 5.5引入一种半同步复制模式,该模式可以确保从节点接收完主节点发送的binlog日志文件并写入自己的中继日志(relay log)里,然后会给主节点一个反馈,告诉对方已经接收完毕,这时主库线程才返回给当前session告知操作完成。当出现超时情况时,源主节点会暂时切换到异步复制模式,直到至少有一个设置为半同步复制模式的从节点及时收到信息为止。
注:半同步复制模式必须在主从节点同时启用,否则主节点默认使用异步复制模式。
上面提到了半同步复制和异步复制的切换,这里再详细描述一下:
它的工作原理是当Slave从库的io_thread线程将binlog日志接收完毕后,应给主库一个确定的信号,如果rpl_semi_sync_master_timeout=10000(10秒)超过10秒未收到Slave从库的接收确认信号,那么就自动切换为传统的异步复制模式。
环境信息
MariaDB : 10.1.21-MariaDB
CenOS: 7.2.1511 (Core)
MariaDB安装(采用Yum方式部署)
步骤一:配置Yum源
# touch /etc/yum.repos.d/MariaDB-IDC.repo
添加如下内容:
[mariadb]
name = MariaDB
baseurl =http://yum.mariadb.org/10.1/centos7-amd64
gpgkey=https://yum.mariadb.org/RPM-GPG-KEY-MariaDB
gpgcheck=1
由于我们的环境无法访问外网,单独部署一个MariaDB的Yum源:
# cat /etc/yum.repos.d/MariaDB-IDC.repo
[MariaDB-10.1-IDC]
name=MariaDB-10.1-IDC
baseurl=http://192.168.1.100/repo/yum.mariadb.org/10.1/centos7-amd64
gpgcheck=0
enabled=1
步骤二:安装MariaDB(192.168.1.104,192.168.1.105,192.168.1.106)
# yum install MariaDB-server MariaDB-client -y
我们这里的主从架构使用半复制模式,而半同步复制模式需要插件,默认的MariaDB部署包(MariaDB-server)中已经包含半同步复制插件:
# find / -name semisync*
/usr/lib64/mysql/plugin/semisync_slave.so
/usr/lib64/mysql/plugin/semisync_master.so
# 配置
步骤三:启动MariaDB
# systemctl start mariadb
步骤四:设置MariaDB的数据库用户root密码和安全设置
/usr/bin/mysql_secure_installation
或
mysql_secure_installation
备注:如果需要修改默认的数据路径,详细步骤如下:
1. 停止MariaDB服务
# systemctl stop mariadb
2. 创建存放数据的连接
mkdir -p /data/d10/mariadb
chown -R mysql:mysql /data/d10/mariadb
3. 将默认的数据拷贝到新的路径下面
cp -a /var/lib/mysql/* /data/d10/mariadb/
4. 修改配置文件/etc/my.cnf.d/server.cnf
[mysqld]
datadir=/data/d10/mariadb
socket=/var/lib/mysql/mysql.sock
character_set_server=utf8
slow_query_log=on
slow_query_log_file=/data/d10/mariadb/logs/slow_query_log.log
long_query_time=2
log-error = /data/d10/mariadb/logs/error.log
半同步复制配置
在Master和Slave首次启动时,安装插件,并开启半同步复制:
Master:
install plugin rpl_semi_sync_master soname 'semisync_master.so';
SET GLOBAL rpl_semi_sync_master_enabled =1;
Slave:
install plugin rpl_semi_sync_slave soname 'semisync_slave.so';
SET GLOBAL rpl_semi_sync_slave_enabled =1;
在初次加载插件后,MySQL会将该插件记录到系统表mysql.plugin中,下次启动系统则会自动加载该插件,无需再次执行上面的命令。
另外,在/etc/my.cnf配置文件里加入以下命令:
Master节点:
[mysqld]
#datadir=/data/d10/mariadb
#socket=/var/lib/mysql/mysql.sock
#character_set_server=utf8
#slow_query_log=on
#slow_query_log_file=/data/d10/mariadb/logs/slow_query_log.log
#long_query_time=2
#log-error =/data/d10/mariadb/logs/error.log
skip_name_resolve = ON
innodb_file_per_table = ON
server-id = 100
log-bin=master-bin
log-bin-index=master-bin.index
rpl_semi_sync_master_enabled=1 #只有安装过半同步复制插件后才可以配置这些参数
rpl_semi_sync_master_timeout=1000
expire_logs_days = 5
binlog_format = row
binlog_row_image = minimal
Slave节点:
[mysqld]
skip_name_resolve = ON
innodb_file_per_table = ON
server_id=101
relay_log_index = slave_relay_bin.index
relay_log = slave_relay_bin
rpl_semi_sync_slave_enabled =1
这样启动MySQL时就会自动开启半同步复制功能。
参数说明:
半同步复制的配置参数较少,其中在Master主库上有4个相关参数,说明如下:
rpl_semi_sync_master_enabled=ON 表示在master上开启半同步复制模式。
rpl_semi_sync_master_timeout=10000 该参数默认为10000毫秒,即10秒。不过,这个参数是动态可调的,它用来表示如果主库在某次事务中的等待时间超过10秒,则降级为异步复制模式,不再等待slave从库。如果主库再次探测到slave从库恢复,则会自动回到半同步复制模式。
rpl_semi_sync_master_wait_no_slave 表示是否允许master每个事务提交后都要等待slave的接收确认信号。默认为on,即每一个事务都会等待。如果为off,则slave追赶上后,也不会开启半同步复制模式,需要手工开启。
rpl_semi_sync_master_trace_level=32 表示用于开启半同步复制模式时的调试级别,默认为32。
在Slave从库上共有2个配置参数,如下:
rpl_semi_sync_slave_enabled=ON 表示在Slave上已经开启半同步复制模式。
rpl_semi_sync_slave_trace_level=32 表示用于开启半同步复制模式时的调试级别,默认为32。
验证半同步复制功能
MySQL 5.6/5.7和MariaDB 10.0/10.1版本一样。
1. 查看主从节点的配置
Master节点:
MariaDB [(none)]> show variables like 'rpl%';
+------------------------------------+--------------+
| Variable_name | Value |
+------------------------------------+--------------+
| rpl_semi_sync_master_enabled | ON |
| rpl_semi_sync_master_timeout | 1000 |
| rpl_semi_sync_master_trace_level | 32 |
| rpl_semi_sync_master_wait_no_slave |ON |
| rpl_semi_sync_master_wait_point | AFTER_COMMIT |
+------------------------------------+--------------+
Slave节点:
MariaDB [(none)]> show variables like 'rpl%';
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| rpl_semi_sync_slave_enabled | ON |
| rpl_semi_sync_slave_trace_level | 32 |
+---------------------------------+-------+
2. 查看主从半同步服务状态
Master节点:
MariaDB [(none)]> show global status like 'rp%';
+--------------------------------------------+-------------+
| Variable_name | Value |
+--------------------------------------------+-------------+
| Rpl_semi_sync_master_clients | 1 |
|Rpl_semi_sync_master_net_avg_wait_time | 873 |
| Rpl_semi_sync_master_net_wait_time | 3493 |
| Rpl_semi_sync_master_net_waits | 4 |
| Rpl_semi_sync_master_no_times | 1 |
| Rpl_semi_sync_master_no_tx | 5 |
| Rpl_semi_sync_master_status | ON |
|Rpl_semi_sync_master_timefunc_failures | 0 |
|Rpl_semi_sync_master_tx_avg_wait_time | 689 |
| Rpl_semi_sync_master_tx_wait_time | 2068 |
| Rpl_semi_sync_master_tx_waits | 3 |
|Rpl_semi_sync_master_wait_pos_backtraverse | 0 |
| Rpl_semi_sync_master_wait_sessions | 0 |
| Rpl_semi_sync_master_yes_tx | 3 |
| Rpl_status | AUTH_MASTER |
+--------------------------------------------+-------------+
其中:
Rpl_semi_sync_master_clients 表示支持和注册的半同步复制已经连接的Slave数量
Rpl_semi_sync_master_status 表示Master半同步复制的状态
Slave节点:
MariaDB [(none)]> show global status like 'rp%';
+----------------------------+---------------------------------------+
| Variable_name | Value |
+----------------------------+---------------------------------------+
| Rpl_semi_sync_slave_status | OFF |
| Rpl_status | AUTH_MASTER |
+----------------------------+----------------------------------------+
其中:
Rpl_semi_sync_slave_status 表示Slave半同步复制的状态,ON或1表示已经被启用,并且IO线程正在运行。
这里的值为OFF,说明还没有启动半同步复制。
3. 在Master主库上创建复制的用户
GRANT REPLICATION SLAVE, REPLICATION CLIENTON *.* TO 'repluser'@'%' IDENTIFIED BY '123456';
4. 在master主库上导出一份全量数据:
mysqldump -uroot -p123456 -q --single-transaction --master-data=2 -A > alldata.sql
5. 把主库上导出的全量数据远程拷贝到从库上,在slave库上导入全量数据完毕后:
CHANGE MASTER TO
MASTER_HOST='192.168.1.105',
MASTER_USER='repl_user',
MASTER_PASSWORD='123456',
MASTER_PORT=3306,
MASTER_LOG_FILE='master-bin.000002',
MASTER_LOG_POS=588;
6. 建立主从复制,并开启同步复制:
start slave;
再次查看Slave的状态:
MariaDB [(none)]> show global status like 'rp%';
+----------------------------+-------------+
| Variable_name | Value |
+----------------------------+-------------+
| Rpl_semi_sync_slave_status | ON |
| Rpl_status | AUTH_MASTER |
+----------------------------+-------------+
Rpl_semi_sync_slave_status的值已经为ON,表示启用半同步复制了。
我们也可以查看Master和Slave启动的进程:
Master节点进程:
MariaDB [(none)]> show processlist;
+----+----------+---------------------+------+-------------+------+-----------------------------------------------------------------------+------------------+----------+
| Id | User | Host | db | Command | Time | State |Info | Progress |
+----+----------+---------------------+------+-------------+------+-----------------------------------------------------------------------+------------------+----------+
| 3| root | localhost | NULL | Query | 0 | init | show processlist | 0.000 |
| 6| repluser | 192.168.1.106:36119 | NULL | Binlog Dump | 5 | Master has sent all binlog to slave;waiting for binlog to be updated | NULL | 0.000 |
+----+----------+---------------------+------+-------------+------+-----------------------------------------------------------------------+------------------+----------+
Slave节点的进程:
MariaDB [(none)]> show processlist;
+----+-------------+-----------+------+---------+------+-----------------------------------------------------------------------------+------------------+----------+
| Id | User | Host | db | Command | Time | State | Info | Progress |
+----+-------------+-----------+------+---------+------+-----------------------------------------------------------------------------+------------------+----------+
| 3| system user | | NULL |Connect | 57 | Slave has read all relaylog; waiting for the slave I/O thread to update it | NULL | 0.000 |
| 4| root | localhost | NULL |Query | 0 | init |show processlist | 0.000 |
| 5| system user | | NULL |Connect | 69 | Waiting for master tosend event | NULL | 0.000 |
+----+-------------+-----------+------+---------+------+-----------------------------------------------------------------------------+------------------+----------+
3 rows in set (0.00 sec)
7. 验证半同步复制模式:
Master节点创建库和表以及插入数据:
MariaDB [(none)]> create database semi_repl_db;
Query OK, 1 row affected (0.00 sec)
MariaDB [(none)]> use semi_repl_db;
Database changed
MariaDB [semi_repl_db]> create table test(id int,name text);
Query OK, 0 rows affected (0.01 sec)
MariaDB [semi_repl_db]> insert into testvalues(1,'mariadb');
Query OK, 1 row affected (0.00 sec)
Slave节点查看Master节点同步的的库和表以及数据:
MariaDB [semi_repl_db]> use semi_repl_db;
Database changed
MariaDB [semi_repl_db]> select * from test;
+------+---------+
| id | name |
+------+---------+
| 1 | mariadb |
+------+---------+
1 row in set (0.00 sec)
说明
1. 异步复制的性能(吞吐率)要稍好于半同步复制
2. 半同步复制中数据丢失的风险低
如果生产环境中开启了半同步复制,那么对数据的一致性要求较大。但是MySQL 5.6和MariaDB 10.0版本中,会存在数据不一致的情况。
情况如下:
假设一个场景下,客户端提交一个事务,master把binlog发送给slave,在发送的期间,网络出现波动,此时Binlog Dump线程发送就会卡住,要等待slave把binlog写入本地的relay-log里,然后给maser一个反馈信号,等待的时间以rpl_semi_sync_master_timeout参数为准,默认为10秒。在这等待的10秒里,在其他会话中,查看刚才的事务是可以看到的。此时一旦master发生宕机,由于binlog没有发送给slave,前端app切换到slave查看,就会发现刚才已经提交的事务不见了,这就是该工作原理的一个缺陷,需要引起注意。
在MySQL 5.7和MariaDB 10.1版本中,半同步的复制原理:
主库写入本地binlog文件里,要等待从库一个ACK信号,假如此时出现网络抖动,用户在其他会话里是看不见刚才提交的事务的,因为还没有将事务提交到引擎层。这时,主库宕机,从库提升为新的主库,用户再连接重新连接新主库时,重新提交就可以了。
为了解决这个问题,MySQL 5.7和MariaDB 10.1版本改善了半同步复制这个缺陷。通过rpl_semi_sync_master_wait_point这个参数加以控制,MySQL 5.7中默认为AFTER_SYNC,官方也推荐这个值。MariaDB10.1默认是AFTER_COMMIT,这个值是采用老式的MySQL 5.5/5.6或MariaDB 10.0半同步复制工作。
半同步复制的原理是:master将binlog发送给slave,只有在slave把binlog写到本地的relay-log里,才提交到存储引擎层,然后把请求返回给客户端,客户端才可以看到刚才提交的事务。如果slave未保存到本地的relay-log里,客户端是看不见刚才的事务的,这样局不会发生上述场景的事情。
半同步复制参数说明如下:
rpl_semi_sync_master_wait_point=AFTER_SYNC :主库把每一个事务写到二进制日志并保存到磁盘上,且发送给从库,主库再等待从库写到自己的relay-log里确认信息。在接收到确认信息后,主库把事务写到存储引擎里并把相应结果反馈给客户端,客户端将在那时进行处理。
rpl_semi_sync_master_wait_point=AFTER_COMMIT:主库把每一个事务写到二进制日志并保存到磁盘上,且发送给从库,并把事务写到存储引擎里,主库再等待从库写到自己的relay-log里确认信息。在接收到确认信息后,主库把相应结果反馈给客户端,客户端在那时进行处理。
这两个参数值的不同在于:当设置为AFTER_SYNC时,所有的客户端可以同时看到提交的数据,在得到从库写到自己的relay-log里的确认信息后,并把事务写到存储引擎里,这样,所有的客户端都可以在主库上看到同样的数据。
主库报错,所有已经写到从库的事务都已经保存到了relay-log里,主库的奔溃,HA切换到从库,不会带来任何损失,因为从库的relay-log的数据是最新的。
当设置为SYNC_COMMIT时,发起事务的客户端仅在服务器向存储引擎写入数据并接受从库得到确认信息之后才返回状态。在写入数据后和得到从库确认信息之前,其他的客户端可以看到这一是事务。如果出现了某种错误,比如从库的sql_thread线程没有执行,那么主库奔溃和故障转移给从服务器的前提下,有可能这个客户端会丢失那些用户曾经在主库上看到的信息。
此外,MySQL 5.7版本的半同步复制可以通过rpl_semi_sync_master_wait_slave_count参数指定有几台slave接收到binlog才成功返回客户端请求,默认是一台,但不能指定哪一台。
注:MariaDB 10.1版本没有这个功能。