MySQL-主从复制
主从复制原理
主从复制的前提
1)两台或两台以上的数据库实例
2)主库要开启二进制日志
3)主库要有复制用户
4)主库的server_id和从库不同
5)从库需要在开启复制功能前,要获取到主库之前的数据(主库备份,并且记录binlog当时位置)
6)从库在第一次开启主从复制时,时必须获知主库:ip,port,user,password,logfile,pos
IP:10.0.0.51
Port:3306
User:rep
Password:oldboy123
logFile:mysql-bin.000002
Pos:120
7)从库要开启相关线程:IO、SQL
8)从库需要记录复制相关用户信息,还应该记录到上次已经从主库请求到哪个二进制日志
9)从库请求过来的binlog,首先要存下来,并且执行binlog,执行过的信息保存下来
主从复制涉及到的文件和线程
主库:
1)主库binlog:记录主库发生过的修改事件
2)dump thread:给从库传送(TP)二进制日志线程
从库:
1)relay-log(中继日志,差异日志):存储所有主库TP过来的binlog事件
<font color='red'>relay-log会定期清除,在一个SQL线程执行完成之后,并且长时间不用的情况下</font>
2)relay-log.info:记录relaylog的名字,和上一次读取relaylog的位置点
3)master.info:存储复制用户信息,上次请求到的主库binlog位置点
4)IO thread:接收主库发来的binlog日志,也是从库请求主库的线程
5)SQL thread:执行主库TP过来的日志
做主从复制,是为了缓解主库的压力,并不是为了备份。(延时从库)
1)通过change master to语句告诉从库主库的ip,port,user,password,file,pos
2)从库通过start slave命令开启复制必要的IO线程和SQL线程
3)从库通过IO线程拿着change master to用户密码相关信息,连接主库,验证合法性
4)从库连接成功后,会根据binlog的pos问主库,有没有比这个更新的
5)主库接收到从库请求后,比较一下binlog信息,如果有就将最新数据通过dump线程给从库IO线程
6)从库通过IO线程接收到主库发来的binlog事件,存储到TCP/IP缓存中,并返回ACK更新master.info
7)将TCP/IP缓存中的内容存到relay-log中
8)SQL线程读取relay-log.info,读取到上次已经执行过的relay-log位置点,继续执行后续的relay-log日志,执行完成后,更新relay-log.info
主从复制实践(生产实践)
主库有数据,并且一直在提供服务,不停库的情况下,添加新的从库
#1.还原环境
[root@db02 ~]# /etc/init.d/mysqld stop
[root@db02 ~]# rm -fr /application/mysql/data/
[root@db02 ~]# cd /application/mysql/scripts/
[root@db02 scripts]# ./mysql_install_db --user=mysql --basedir=/application/mysql --datadir=/application/mysql/data
[root@db02 scripts]# /etc/init.d/mysqld start
------
[root@db03 ~]# /etc/init.d/mysqld stop
[root@db03 ~]# rm -fr /application/mysql/data/
[root@db03 ~]# cd /application/mysql/scripts/
[root@db03 scripts]# ./mysql_install_db --user=mysql --basedir=/application/mysql --datadir=/application/mysql/data
[root@db03 scripts]# /etc/init.d/mysqld start
#2.修改主库的配置
[root@db01 ~]# vim /etc/my.cnf
log-bin=mysql-bin
binlog_format=row
server_id=10
#3.修改从库的配置
[root@db02 ~]# vim /etc/my.cnf
server_id=5
[root@db02 ~]# /etc/init.d/mysqld restart
Shutting down MySQL.. SUCCESS!
Starting MySQL. SUCCESS!
------
[root@db03 ~]# vim /etc/my.cnf
server_id=5
[root@db03 ~]# /etc/init.d/mysqld restart
Shutting down MySQL.. SUCCESS!
Starting MySQL. SUCCESS!
#4.主库操作
#创建主从复制用户
mysql> grant replication slave on *.* to slave@'%' identified by '123';
#查看binlog位置点?(新主从环境)
mysql> show master status;
+------------------+----------+
| File | Position |
+------------------+----------+
| mysql-bin.000001 | 134 |
+------------------+----------+
#有数据的情况,打点全备
[root@db01 ~]# mysqldump -A -R --triggers --master-data=1 --single-transaction |gzip > /tmp/replication.sql.gz
#将打点全备的数据,发送到从库上
[root@db01 ~]# scp /tmp/replication.sql.gz 172.16.1.52:/tmp
[root@db01 ~]# scp /tmp/replication.sql.gz 172.16.1.53:/tmp
#导入数据
[root@db02 ~]# zcat /tmp/replication.sql.gz |mysql
[root@db03 ~]# zcat /tmp/replication.sql.gz |mysql
#如果全备数据很大,建议不要scp
[root@db01 ~]# zcat /tmp/replication.sql.gz |mysql -uroot -p123 -h10.0.0.52
[root@db01 ~]# zcat /tmp/replication.sql.gz |mysql -uroot -p123 -h10.0.0.53
#5.从库操作
#找位置点和名字
[root@db02 ~]# zcat /tmp/replication.sql.gz |head -22|tail -1
CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=161362;
#执行同步主库
change master to
master_user='slave',
master_password='123',
master_host='10.0.0.51',
master_log_file='mysql-bin.000002',
master_log_pos=161362;
#开启IO和SQL线程
start slave;
#检查主从复制状态
show slave status\G
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
MySQL主从复制问题
IO
1.网络
ping 10.0.0.51
2.端口
telnet 10.0.0.51 3306
tcping 10.0.0.51 3306
3.用户名
4.密码
mysql -uslave -p123 -h10.0.0.51
5.反向解析
vim /etc/my.cnf
[mysqld]
skip_name_resolve
#不正经
skip-name-resolv
skip-name-resolve
skip_name_resolv
6.binlog的名字和位置点一定要一致
mysql> show master status;
+------------------+----------+
| File | Position |
+------------------+----------+
| mysql-bin.000002 | 3149338 |
+------------------+----------+
mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)
mysql> change master to
-> master_log_file='mysql-bin.000002',
-> master_log_pos=3149338;
Query OK, 0 rows affected (0.01 sec)
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
7.server_id相同
mysql> show variables like 'server_id';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| server_id | 10 |
+---------------+-------+
[root@db03 ~]# vim /etc/my.cnf
server_id=5
8.UUID相同
#1.修改uuid
[root@db03 data]# vim auto.cnf
[auto]
server-uuid=54c76db8-20eb-11ea-bed9-000c29e98744
[root@db03 data]# /etc/init.d/mysqld restart
Shutting down MySQL.. SUCCESS!
Starting MySQL. SUCCESS!
#2.删除uuid
[root@db03 data]# rm -fr /application/mysql/data/auto.cnf
[root@db03 data]# /etc/init.d/mysqld restart
Shutting down MySQL.. SUCCESS!
Starting MySQL. SUCCESS!
SQL
主库和从库数据不一致:
- 主库上有从库没有的数据
[root@db03 data]# vim /etc/my.cnf
slave-skip-errors=1032,1062,1007,1049
[root@db03 data]# /etc/init.d/mysqld restart
- 主库上没有从库上有的数据
set global sql_slave_skip_counter=1;
mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)
mysql> set global sql_slave_skip_counter=1;
Query OK, 0 rows affected (0.00 sec)
mysql> start slave;
Query OK, 0 rows affected (0.01 sec)
但是以上操作都是有风险存在的
做主从复制之前,保证主库和从库的数据一致性。
处理方法三:
1)重新备份数据库,恢复到从库
2)给从库设置为只读
#在命令行临时设置
set global read_only=1;
#在配置文件中永久生效
read_only=1
MySQL延时从库
延时从库,原理,在SQL线程上做手脚,不影响IO线程连接dump线程取数据。
延时从库操作步骤
mysql> stop slave;
Query OK, 0 rows affected (0.00 sec)
mysql> change master to
-> master_delay=180;
Query OK, 0 rows affected (0.01 sec)
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
#新从库
change master to
master_host='10.0.0.51',
master_user='slave',
master_password='123',
master_log_file='mysql-bin.000001',
master_port=3306,
master_log_pos=250,
master_delay=3600;
企业中一般会延时3-6小时
企业案例
思考问题:
总数据量级500G,正常备份去恢复需要1.5-2小时
1)配置延时3600秒
mysql>CHANGE MASTER TO MASTER_DELAY = 3600;
2)主库
drop database db;
3)怎么利用延时从库,恢复数据?
思路:
1.停止SQL线程
mysql> stop slave sql_thread;
2.找到relaylog的名字和起始位置点
[root@db03 data]# cat relay-log.info
./db03-relay-bin.000003
283
3.查看relay log到删库之前
[root@db03 data]# mysqlbinlog --base64-output=decode-rows -vvv db03-relay-bin.000003
12611
4.导出被删除的库
[root@db03 data]# mysqldump -uroot -p123 -A > /tmp/zls1_new.sql
5.截取relay log
[root@db03 data]# mysqlbinlog --start-position=283 --stop-position=12611 db03-relay-bin.000003 > /tmp/delay.sql
6.将导出的sql文件发送到主库
[root@db03 data]# scp /tmp/*.sql 172.16.1.51:/tmp
7.在主库导入数据
[root@db01 data]# mysql < /tmp/zls1_new.sql
[root@db01 data]# mysql < /tmp/delay.sql
8.在延时从库开启SQL线程
mysql> start slave sql_thread;
Query OK, 0 rows affected (0.00 sec)
半同步复制
[root@db03 data]# cd /application/mysql/lib/plugin
mysql> show global variables like 'have_dynamic_loading';
+----------------------+-------+
| Variable_name | Value |
+----------------------+-------+
| have_dynamic_loading | YES |
+----------------------+-------+
#主库安装插件
INSTALL PLUGIN rpl_semi_sync_master SONAME'semisync_master.so';
#主库启用插件
SET GLOBAL rpl_semi_sync_master_enabled = 1;
#检查安装
mysql> 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_stop_slave_timeout | 31536000 |
+------------------------------------+----------+
mysql> show global status like 'rpl_semi%';
+--------------------------------------------+-------+
| Variable_name | Value |
+--------------------------------------------+-------+
| Rpl_semi_sync_master_clients | 0 |
| Rpl_semi_sync_master_net_avg_wait_time | 0 |
| Rpl_semi_sync_master_net_wait_time | 0 |
| Rpl_semi_sync_master_net_waits | 0 |
| Rpl_semi_sync_master_no_times | 1 |
| Rpl_semi_sync_master_no_tx | 136 |
| Rpl_semi_sync_master_status | OFF |
| Rpl_semi_sync_master_timefunc_failures | 0 |
| Rpl_semi_sync_master_tx_avg_wait_time | 0 |
| Rpl_semi_sync_master_tx_wait_time | 0 |
| Rpl_semi_sync_master_tx_waits | 0 |
| Rpl_semi_sync_master_wait_pos_backtraverse | 0 |
| Rpl_semi_sync_master_wait_sessions | 0 |
| Rpl_semi_sync_master_yes_tx | 0 |
+--------------------------------------------+-------+
#从库上安装插件
INSTALL PLUGIN rpl_semi_sync_slave SONAME'semisync_slave.so';
#从库启动插件
SET GLOBAL rpl_semi_sync_slave_enabled = 1;
#重启IO线程
mysql> stop slave io_thread;
Query OK, 0 rows affected (0.00 sec)
mysql> start slave io_thread;
Query OK, 0 rows affected (0.01 sec)
过滤复制
主库配置过滤
白名单:只记录白名单中列出的库的二进制日志
- binlog-do-db
binlog-do-db=wzry
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000003 | 120 | wzry | | |
+------------------+----------+--------------+------------------+-------------------+
黑名单:不记录黑名单列出的库的二进制日志
- binlog-ignore-db
binlog-ignore-db=wzry
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000004 | 3248 | | wzry | |
+------------------+----------+--------------+------------------+-------------------+
从库配置过滤
白名单:只执行白名单中列出的库或者表的中继日志
- --replicate-do-db=test
- --replicate-do-table=test.t1
- --replicate-wild-do-table=test.t*
黑名单:不执行黑名单中列出的库或者表的中继日志
- --replicate-ignore-db
- --replicate-ignore-table
- --replicate-wild-ignore-table