MySQL主从复制和半同步复制
主从复制原理
1、主从复制主要是基于二进制日志(binlog)进行的,二进制日志记录的是一个个完整的事件。
2、把主服务器的二进制日志拿到从服务器再运行一遍。
3、复制过程:
1,slave端的IO线程连上master端,请求
2,master端返回给slave端,bin log文件名和位置信息
3,IO线程把master端的bin log内容依次写到slave端relay bin log里,并把master端的bin-log文件名和位置记录到master.info里。
4,salve端的sql线程,检测到relay bin log中内容更新,就会解析relay log里更新的内容,并执行这些操作;也就是说salve执行和master一样的操作而达到数据同步的目的;
复制过程涉及到的3个线程:
1、从库开启一个IO线程,负责链接主库请求和接收binlog日志并写入到relay-log
2、从库开启一个sql线程,负责解析relay-log中的事件并执行
3、主库开启一个dump线程,负责响应从库来的IO线程的请求。
主从搭建配置示例
以MySQL多实例进行搭建配置
环境说明
[root@anuo ~]# getenforce
Disabled
[root@anuo ~]# /etc/init.d/iptables status
iptables:未运行防火墙。
[root@anuo ~]# mysql --version
mysql Ver 14.14 Distrib 5.6.25, for Linux (x86_64) using EditLine wrapper
主库的配置文件
[root@anuo ~]# vim /data/3306/my.cnf
[mysqld]
user=mysql
port=3306
socket=/data/3306/mysql.sock
basedir=/usr/local/mysql
datadir=/data/3306/data
log-bin=/data/3306/mysql-bin --指定binlog的存放路径
server-id=1 --主库和从库的server-id 不能一样
skip_name_resolve=0 --表示跳过域名解析
[client]
socket=/data/3306/mysql.sock
[mysqld_safe]
log-error=/data/3306/mysql_3306.err
pid-file=/data/3306/mysql.pid
从库的配置文件
[root@anuo ~]# vim /data/3307/my.cnf
[mysqld]
user = mysql
port = 3307
socket = /data/3307/mysql.sock
basedir = /usr/local/mysql
datadir = /data/3307/data
log-bin = /data/3307/mysql-bin --从库的binlog可以不开启
server-id = 2 --server-id和主库的不一样
skip_name_resolve = 0
read_only = 1 --从库只读
[client]
port = 3307
socket = /data/3307/mysql.sock
[mysqld_safe]
log-error=/data/3307/mysql_3307.err
pid-file=/data/3307/mysqld.pid
启动数据库
[root@anuo data]# /data/3306/mysql start
2018-05-27 06:03:37 MySQL--启动中...
[root@anuo data]# /data/3307/mysql start
2018-05-27 06:03:47 MySQL--启动中...
[root@anuo data]# netstat -nltup|grep mysql
tcp 0 0 :::3306 :::* LISTEN 4028/mysqld
tcp 0 0 :::3307 :::* LISTEN 4268/mysqld
主库上创建用于复制的用户
[root@anuo data]# mysql -uroot -p -S /data/3306/mysql.sock --登陆主库
Enter password:
mysql> grant super,replication slave on *.* to 'hb'@'10.0.0.%' identified by '123'; --创建用户并授权
Query OK, 0 rows affected (0.12 sec)
mysql> flush privileges; --刷新权限
Query OK, 0 rows affected (0.05 sec)
mysql> show master status; --查看master的当前时间写到的二进制文件名和位置
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000011 | 409 | | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
--只有打开二进制日志,这句命令才有结果,表示当前数据库的二进制日志写到什么位置
(注:如果主库的之前就已经开启并有重要数据的话要先把数据进行备份传到从库进行恢复。我这是测试环境就忽略了这步骤。)
从库上复制的操作
[root@anuo ~]# mysql -S /data/3307/mysql.sock --登陆从库
mysql> change master to
-> master_host='10.0.0.15', --主的IP
-> master_port=3306, --主的端口
-> master_user='hb', --对应前面主授权时的用户
-> master_password='123', --对应前面主授权时的密
-> master_log_file='mysql-bin.000011', ----主上面查到的文件名
-> master_log_pos=409; --主上面查到的位置号
Query OK, 0 rows affected, 2 warnings (0.11 sec)
mysql> start slave; --启动从库复制
Query OK, 0 rows affected (0.07 sec)
mysql> show slave status\G
*************************** 1. row ***************************
……
Slave_IO_Running: Yes
Slave_SQL_Running: Yes --看到这两人个线程为yes,代表搭建成功
……
进行测试主从同步
在主库上创建库或表,再到从库上查看是否同步成功。 此步骤忽略。
MySQL一主多从搭建
一主多从也就是在上面的一主一从的基础上多加一台从服务器
(我这里多加一台centos7.3的做从进行演示)
[root@vm1 ~]# vim /etc/my.cnf --编辑配置文件
[mysqld]
port=3306
datadir=/data/mysql
pid-file=/data/mysql/mysql.pid
socket=/data/mysql/mysql.socket
log-error=/data/mysql/mysql-err.log
user=mysql
server-id=3 --多加一条server-id号跟之前的不一样就可以了
[client]
socket=/data/mysql/mysql.socket
[root@vm1 ~]# systemctl restart mysqld.service --重启
[root@vm1 ~]# lsof -i:3306
登陆数据库操作跟上面的从服务器操作是一样的
mysql> change master to
-> master_host='10.0.0.15',
-> master_port=3306,
-> master_user='hb',
-> master_password='123',
-> master_log_file='mysql-bin.000011',
-> master_log_pos=409;
Query OK, 0 rows affected, 2 warnings (0.01 sec)
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 10.0.0.15
Master_User: hb
Master_Port: 3306
Connect_Retry: 60
Master_Log_File: mysql-bin.000011
Read_Master_Log_Pos: 503
Relay_Log_File: mysql-relay-bin.000002
Relay_Log_Pos: 377
Relay_Master_Log_File: mysql-bin.000011
Slave_IO_Running: Yes
Slave_SQL_Running: Yes --看到2给yes也就是成功了
半同步搭建
所谓的半同步复制就是master每commit一个事务,要slave应用这个事物后回给master信号。这样master才能把事物成功commit。这样就保证了master-slave的数据绝对的一致(但是以牺牲master的性能为代价).但等待时间也是可以调整的。 mysql半同步复制等待时间超时后(默认时间为10秒),会自动转换成异步复制 ,相对于异步复制,半同步复制提高了数据的安全性。
安装mysql5.5之后的版本,因为这个版本之后才实现的半同步复制
第一大步: 先要搭建好mysql主从异步复制,上面已经搭过了就过程省略 。
第二大步:在异步基础上转成半同步复制
1)在master上安装这个插件
mysql> install plugin rpl_semi_sync_master soname 'semisync_master.so';
Query OK, 0 rows affected (1.51 sec)
(--删除插件的方法 mysql > uninstall plugin rpl_semi_sync_master;)
mysql> show global variables like 'rpl_semi_sync%'; --安装OK后,主上会多几个参数
+------------------------------------+-------+
| Variable_name | Value |
+------------------------------------+-------+
| rpl_semi_sync_master_enabled | OFF | --OFF表示半同步还没有开启
| rpl_semi_sync_master_timeout | 10000 | --默认主等待从返回信息的超时间时间,10秒。
| rpl_semi_sync_master_trace_level | 32 | --监控
| rpl_semi_sync_master_wait_no_slave | ON | --是否允许每个事物的提交都要等待slave的信号.on为每一个事物都等待
+------------------------------------+-------+
4 rows in set (0.83 sec)
2)在slave上安装插件
mysql> install plugin rpl_semi_sync_slave soname 'semisync_slave.so';
Query OK, 0 rows affected (0.63 sec)
mysql> show global variables like 'rpl_semi_sync%';
+---------------------------------+-------+
| Variable_name | Value |
+---------------------------------+-------+
| rpl_semi_sync_slave_enabled | OFF |
| rpl_semi_sync_slave_trace_level | 32 |
+---------------------------------+-------+
2 rows in set (0.78 sec)
3)master上激活半同步复制
mysql> set global rpl_semi_sync_master_enabled =on;
Query OK, 0 rows affected (0.04 sec)
4)slave上激活半同步复制并重启IO线程
mysql> set global rpl_semi_sync_slave_enabled=on; --激活半同步
Query OK, 0 rows affected (0.04 sec)
mysql> stop slave IO_THREAD; --关闭IO线程
Query OK, 0 rows affected (0.14 sec)
mysql> start slave IO_THREAD; --启动IO线程
Query OK, 0 rows affected (0.11 sec)
5)在master查看状态
mysql> show global status like 'rpl_semi_sync%';
+--------------------------------------------+-------+
| Variable_name | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients | 1 | --有一个从服务器启用半同步复制
| Rpl_semi_sync_master_net_avg_wait_time | 0 | --master等待slave回复的平均等待时间。单位毫秒
| Rpl_semi_sync_master_net_wait_time | 0 | --master总的等待时间。单位毫秒
| Rpl_semi_sync_master_net_waits | 0 | --master等待slave回复的总的等待次数
| Rpl_semi_sync_master_no_times | 0 | --master关闭半同步复制的次数
| Rpl_semi_sync_master_no_tx | 0 | --master 等待超时的次数
| Rpl_semi_sync_master_status | ON | --标记master现在是否是半同步复制状态
| Rpl_semi_sync_master_timefunc_failures | 0 | --master调用时间(如gettimeofday())失败的次数
| Rpl_semi_sync_master_tx_avg_wait_time | 0 | --master花在每个事务上的平均等待时间
| Rpl_semi_sync_master_tx_wait_time | 0 | --master花在事物上总的等待时间
| Rpl_semi_sync_master_tx_waits | 0 | --master事物等待次数
| Rpl_semi_sync_master_wait_pos_backtraverse | 0 | --后来的先到了,而先来的还没有到的次数
| Rpl_semi_sync_master_wait_sessions | 0 | --当前有多少个session因为slave回复而造成等待
| Rpl_semi_sync_master_yes_tx | 0 | --标记slave是否在半同步状态
+--------------------------------------------+-------+
14 rows in set (0.10 sec)
6)在slave上查看状态就只有下面一条信息
mysql> show global status like 'rpl_semi_sync%';
+----------------------------+-------+
| Variable_name | Value |
+----------------------------+-------+
| Rpl_semi_sync_slave_status | ON |
+----------------------------+-------+
1 row in set (0.00 sec)
第三大步 测试:
mysql> create database btbcs;
Query OK, 1 row affected (0.10 sec)
mysql> show global status like 'rpl_semi_sync%_yes_tx';
+-----------------------------+-------+
| Variable_name | Value |
+-----------------------------+-------+
| Rpl_semi_sync_master_yes_tx | 1 | --表示这次事物成功从slave返回一次确认信号
+-----------------------------+-------+
1 row in set (0.04 sec)
模拟错误,把slave上的IO线程停掉
--再回到master上测试
mysql> create database btbcs2;
Query OK, 1 row affected (10.34 sec) --这次插入一个值需要等待10秒(默认的等待时间)
mysql> create database btbcs3;
Query OK, 1 row affected (0.00 sec) --再插入数据时候就发现自动转成了原来的异步模式了
再把slave上的IO线程开启,查看数据发现刚才slave关闭期间的那几条数据还是会自动复制过来,数据又回到一致
如果是把slave上的mysql停掉,再次把slave启动,看到半同步复制没启来,是异步模式,需要重新把同步模式再启起来就可以了
mysql> set global rpl_semi_sync_slave_enabled=on; --启动半同步模式
mysql> stop slave IO_THREAD; --关闭IO线程
mysql> start slave IO_THREAD; --启动IO线程
slave启起来后数据也是一样会回到一致