Day011-MySQL主从复制
2019-10-23 本文已影响0人
驮着集装箱的鲸鱼
1. 主从复制介绍
依赖于二进制日志,“实时”备份的一个多节点架构。
2. 主从复制的前提(搭建主从复制)
(1)至少2个实例
(2)不同的server_id
(3)主库需要开启二进制日志
(4)主库需要授权一个专用的复制用户
(5)主库数据备份
(6)开启专用复制线程
3. 搭建主从复制步骤
3.1 准备多实例
过程略
3.2 检查多实例server_id
[root@db01 ~]# mysql -S /data/3307/mysql.sock -e 'select @@server_id;'
+-------------+
| @@server_id |
+-------------+
| 7 |
+-------------+
[root@db01 ~]# mysql -S /data/3308/mysql.sock -e 'select @@server_id;'
+-------------+
| @@server_id |
+-------------+
| 8 |
+-------------+
[root@db01 ~]# mysql -S /data/3309/mysql.sock -e 'select @@server_id;'
+-------------+
| @@server_id |
+-------------+
| 9 |
+-------------+
3.3 检查3307(主库)二进制日志状态
[root@db01 ~]# mysql -S /data/3307/mysql.sock -e 'show variables like "%log_bin%";'
+---------------------------------+----------------------------+
| Variable_name | Value |
+---------------------------------+----------------------------+
| log_bin | ON |
| log_bin_basename | /data/3307/mysql-bin |
| log_bin_index | /data/3307/mysql-bin.index |
| log_bin_trust_function_creators | OFF |
| log_bin_use_v1_row_events | OFF |
| sql_log_bin | ON |
+---------------------------------+----------------------------+
3.4 主库创建专用的复制用户
[root@db01 ~]# mysql -uroot -P3307 -S /data/3307/mysql.sock
mysql> grant replication slave on *.* to repl@'10.0.0.%' identified by '123';
3.5 进行主库数据备份
生产中可以用历史备份
[root@db01 ~]# mysqldump -S /data/3307/mysql.sock -A --master-data=2 -R -E --triggers --single-transaction > /tmp/full_3307.sql
[root@db01 ~]# ls /tmp/
full_3307.sql
3.6 恢复数据到从库
[root@db01 ~]# mysql -S /data/3308/mysql.sock -P 3308
mysql> set sql_log_bin=0;
mysql> source /tmp/full_3307.sql
另一台步骤省略……
3.7 change master to 告诉从库复制的信息(如IP、端口、用户名、密码、binlog等)
从库操作
vim /tmp/full_3307.sql
大约22行左右 -- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=443; 用这个当做起点
[root@db01 ~]# mysql -S /data/3308/mysql.sock -P3308
mysql> help change master to;
mysql> CHANGE MASTER TO 注意 不能用小写
-> MASTER_HOST='10.0.0.51', (主库IP)
-> MASTER_USER='repl', (专用复制用户)
-> MASTER_PASSWORD='123', (授权的密码)
-> MASTER_PORT=3307, (主库端口)
-> MASTER_LOG_FILE='mysql-bin.000002', (这是从/tmp/full_3307中截取的)
-> MASTER_LOG_POS=443, (这是从/tmp/full_3307中截取的)
-> MASTER_CONNECT_RETRY=10;(与主库连接失败后重试连接的次数)
3.8 启动从库复制线程
从库操作
mysql> start slave;
3.9 如果change master to 信息输入错误,可以用以下方法解决,然后重新输入
mysql> stop slave;
mysql> reset slave all; 清理之前输入的CHANGE MASTER TO信息
mysql> CHANGE MASTER TO
MASTER_HOST='10.0.0.51',
MASTER_USER='repl',
MASTER_PASSWORD='123',
MASTER_PORT=3307,
MASTER_LOG_FILE='mysql-bin.000002',
MASTER_LOG_POS=443,
MASTER_CONNECT_RETRY=10;
mysql> start slave;
查看主从搭建是否成功
3308> show slave status\G
……省略若干行
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
……省略若干行
4. 主从复制工作过程
4.1 名词认识
在主从复制工作过程中,会用到很多的文件及涉及到的线程
(1)文件
主库:
涉及到的文件为“binlog”
从库:存在于数据目录下
relay-log:中继日志文件
master.info:主库信息文件
relay-log.info:中继日志应用信息文件
(2)线程
主库:
binlog_dump_thread:二进制日志投递线程。可以使用show processlist查看,名称为Binlog Dump。
从库:默认为传统复制模式
IO_Thread:从库的IO线程(请求和接收binlog)
SQL_Thread:从库的SQL线程(回放(重新运行)从主库拿过来的日志)
4.2 主从复制工作原理(过程)
(1)从库执行change master to语句,然后立即将主库的信息(ip、端口等)记录到master.info中,这个文件就在从库的数据目录下。
(2)从库执行start slave语句的瞬间,会立即生成IO_Thread和SQL_Thread。
(3)IO_Thread读取master.info文件,获取主库的相关信息(IP、端口号等)。
(4)IO_Thread连接主库,连接层开始验证用户名、密码、端口号、IP等是否合法。
一旦合法,主库会立即分配一个dump_thread线程,来与IO_Thread进行交互。
(5)IO_Thread根据master.info中的二进制日志信息,向主库的DUMP_Thread线程请求最新的二进制日志。
(6)DUMP_Thread经过show master status查询,如果发现有新的二进制日志,就截取新的日志并返回给从库的IO_Thread。
(7)从库IO_Thread收到主库发来的binlog,存储在到TCP_IP缓存中,在网络底层返回ACK给主库。
(8)从库IO_Thread会将二进制日志信息写入到relay-log中。
(9)从库IO_Thread更新master.info信息,重置二进制日志位置点信息。
(10)从库SQL_Thread读取relay-log.info文件,获取上次执行过的relay-log.info位置点。
(11)根据获取到的位置点,SQL_Thread按照位置点往下执行relaylog日志。
(12)SQL_Thread执行完后,更新relay-log.info文件。
(13)pwrge线程(非主从线程)把应用过的relay_log定期自动清理
主从复制原理图.png
思考:主库创建一个库后,从库怎么知道的?
源码解释:
主库发生的信息修改,更新二进制日志后,会发送一个信号给dump线程,然后dump线程通知io线程,io线程到主库请求并获取到最新的二进制日志。
5. 主从复制监控及故障分析与处理
5.1 主从监控
主库:
mysql> show processlist; 通过该命令监控主库的线程
+----+------+-----------------+------+-------------+------+---------------------------------------------------------------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+------+-----------------+------+-------------+------+---------------------------------------------------------------+------------------+
| 8 | repl | 10.0.0.51:38432 | NULL | Binlog Dump | 5704 | Master has sent all binlog to slave; waiting for more updates | NULL |
| 9 | root | localhost | NULL | Query | 0 | starting | show processlist |
+----+------+-----------------+------+-------------+------+---------------------------------------------------------------+------------------+
从库:
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
主库信息:(master.info)
Master_Host: 10.0.0.51 (主库IP地址,记录与master.info中)
Master_User: repl (主库中创建的复制用户)
Master_Port: 3307 (主库端口号)
Connect_Retry: 10 (与主库连接失败后重试连接的次数)
Master_Log_File: mysql-bin.000002 (主库已经获取到的日志名)
Read_Master_Log_Pos: 443 (已经获取到的binglog日志位置号)
从库信息(relaylog):
Relay_Log_File: db01-relay-bin.000002 (从库已经运行过的relay log的文件名)
Relay_Log_Pos: 320 (从库已经运行过的relay log的位置点)
Relay_Master_Log_File: mysql-bin.000002
从库复制线程工作状态:
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
过滤复制相关状态:默认情况下,主从复制比例为1:1
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Last_Errno: 0
Last_Error:
Skip_Counter: 0
Exec_Master_Log_Pos: 443
Relay_Log_Space: 526
Until_Condition: None
Until_Log_File:
Until_Log_Pos: 0
Master_SSL_Allowed: No
Master_SSL_CA_File:
Master_SSL_CA_Path:
Master_SSL_Cert:
Master_SSL_Cipher:
Master_SSL_Key:
从库延时(信息同步)主库的时间,单位“秒”,生产中要避免这种延时
Seconds_Behind_Master: 0
Master_SSL_Verify_Server_Cert: No
从库线程报错详细信息----->IO报错的号码
Last_IO_Errno: 0
从库线程报错详细信息----->IO报错的具体信息
Last_IO_Error:
从库线程报错详细信息----->SQL报错的号码
Last_SQL_Errno: 0
从库线程报错详细信息----->SQL报错的具体原因
Last_SQL_Error:
Replicate_Ignore_Server_Ids:
Master_Server_Id: 7
Master_UUID: 92257cfc-8e8e-11e9-a0c5-000c29577287
Master_Info_File: /data/3308/data/master.info
延时从库操作设定时间----->防止主库误操作立即同步到从库(生产需要,主动设置)
SQL_Delay: 0
延时从库操作剩余时间:
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
Master_Retry_Count: 86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
GTID复制相关信息----->从主库接收到的GTID个数
Retrieved_Gtid_Set:
GTID复制相关信息----->主库与从库一共执行了的GTID个数
Executed_Gtid_Set:
Auto_Position: 0
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
5.2 主从故障的分析及处理
(1)观察从库复制线程状态
3308> show slave status\G
……省略若干行
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
……省略若干行
(2)从库线程报错详细信息
Last_IO_Error: 0 (IO报错号码)
Last_IO_Error: (IO报错具体信息)
Last_SQL_Error: 0 (SQL报错号码)
Last_SQL_Error: (SQL报错具体信息)
5.2.1 IO线程故障
IO线程工作流程
(1)连接主库
(2)请求新的binlogo
(3)写入realy-log
(4)更新master.ingo
IO故障分析
(1)连接主库连接不上
报错:connecting
原因:
网络不通
防火墙阻挡
IP错误
port错误
用户,密码不对
skip_name_resolve(5.7以前的版本,禁止域名和主机名解析)
链接数上限,默认151个链接数
解决办法:
mysql -urepl -p123 -h 10.0.0.51 -P 3307
如果能够连接上,证明没有问题
如果连接不上,就有可能是用户名、密码、端口、IP地址错误。
模拟错误:
用户名错误:
[root@db01 ~]# mysql -urep -p123 -h 10.0.0.51 -P 3307
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied for user 'rep'@'10.0.0.51' (using password: YES)
密码错误:
[root@db01 ~]# mysql -urepl -p1231 -h 10.0.0.51 -P 3307
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied for user 'repl'@'10.0.0.51' (using password: YES)
IP错误:
[root@db01 ~]# mysql -urepl -p123 -h 10.0.0.5 -P 3307
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 2003 (HY000): Can't connect to MySQL server on '10.0.0.5' (110)
端口错误:
[root@db01 ~]# mysql -urepl -p123 -h 10.0.0.51 -P 3306
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 2003 (HY000): Can't connect to MySQL server on '10.0.0.51' (111)
上述错误解决办法:
stop slave;
reset slace all;
change master to;
重新指定IP、端口、等
start slave;
(2)请求新的binlog
报错显示:IO线程显示为NO
原因:
(1)日志名不对
(2)日志损坏
(3)日志不连续
解决办法:
1. 日志名不对
从库查看:从库请求的日志名是否与主库的日志相同
mysql> show slave status\G
省略部分输出……
Master_Log_File: mysql-bin.000002
Read_Master_Log_Pos: 443
与备份文件full_3307中的-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000002', MASTER_LOG_POS=443;是否相同。
也可以在主库中使用show master status;确定
2. 日志损坏,日志不连续
显示:
Slave_IO_Running: No
经过过排查原因,没有发现日志名不对的情况。那么就有可能是日志损坏了。
模拟场景:
主库:
mysql -S /data/3307/mysql.sock
mysql> flush logs;
mysql> flush logs;
mysql> flush logs;
mysql> flush logs;
mysql> flush logs; 刷新日志对主从无影响
mysql> reset master; 此命令一旦执行,主从链接就异常了,显示如下
从库:
mysql> show slave status\G
……省略部分内容
Slave_IO_Running: No
Slave_SQL_Running: Yes
……省略部分内容
主库:
mysql> create database dd;
mysql> create database dd1;
mysql> create database dd2;
此时主从状态已经异常了,所以新建的库不会同步
解决方法:
让日志从头开始记录
主库:
show master status\G
记住binlgogID和POSID
从库:
mysql -S /data/3308/mysql.sock
stop slave;
reset slave all ;
CHANGE MASTER TO
MASTER_HOST='10.0.0.51',
MASTER_USER='repl',
MASTER_PASSWORD='123',
MASTER_PORT=3307,
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=154,
MASTER_CONNECT_RETRY=10;
start slave;
其他错误
(3)relaylog损坏或无权限等,满足不了写入需求时,就会报错。出现概率小
(4)更新master.info 出现概率小
(5)server_id重复
5.2.2 SQL线程故障
SQL线程的作用:
读relay-log.info
读relay-log,并执行日志,relay-log里面存放的是主库执行过的SQL语句。
更新relay-log.info
故障原因:
(1)以上文件损坏,最好是重新构建主从,恢复主库数据到从库,然后chage master to等一系列操作,这也是最靠谱的方法。
(2)从库不能执行主库执行过的SQL语句。
为什么从主库拿过来的SQL语句,在从库不能执行?
答:
1. 有可能是数据库版本差异较大,不过这种情况可能性较小。
2. 主从数据库参数配置不一致(例如SQL_mode、内存参数等)
3. 想要创建的对象已经存在。
4. 想要删除或修改的对象不存在。
5. 主键冲突。
6. DML语句不符合表的定义及约束。
总结以上问题:除了前两个问题外,其他都是从库写入造成的故障。
注意:生产环境中,从库要杜绝一切写入!!!
从库写入故障模拟演示1
从库操作:
mysql> create database test; 从库创建库
Query OK, 1 row affected (0.01 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| t1 |
| test |
+--------------------+
6 rows in set (0.01 sec)
主库操作:
mysql> show databases; 主库中不存在从库中的test库
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| t1 |
+--------------------+
5 rows in set (0.01 sec)
从库操作:
mysql> show slave status\G 此时的主从关系还是正常的
*************************** 1. row ***************************
省略部分输出……
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
省略部分输出……
主库操作:创建从库中的test库,并创建一个表
mysql> create database test;
Query OK, 1 row affected (0.00 sec)
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| t1 |
| test | 此时主库也有了从库中的test库,表面上看着没毛病
+--------------------+
6 rows in set (0.00 sec)
mysql> use test
Database changed
mysql> create table t1(id int);
Query OK, 0 rows affected (0.29 sec)
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| t1 |
+----------------+
1 row in set (0.00 sec)
从库操作:查看主库中的表在同步到从库没有
mysql> use test;
Database changed
mysql> show tables;
Empty set (0.00 sec) 没有同步主库的他t1表到从库
从库查看主从状态:发现主从状态已经异常了
mysql> mysql> show slave status\G
*************************** 1. row ***************************
省略部分输出……
Slave_IO_Running: Yes
Slave_SQL_Running: No
省略部分输出……
Last_Errno: 1007
Last_Error: Error 'Can't create database 'test'; database exists' on query. Default database: 'test'. Query: 'create database test'
省略部分输出……
Last_SQL_Errno: 1007
Last_SQL_Error: Error 'Can't create database 'test'; database exists' on query. Default database: 'test'. Query: 'create database test' 无法创建test库,test库已经存在,就是因为从库写入导致的
省略部分输出……
1 row in set (0.00 sec)
解决从库写入故障方法 1 --以主库为准的恢复(推荐方法)
模拟故障:
从库操作:
(1)删除从库创建的库
mysql> drop database test;
Query OK, 0 rows affected (0.01 sec)
(2)再次查看主从状态,发现还是没有恢复
mysql> mysql> show slave status\G
*************************** 1. row ***************************
省略部分输出……
Slave_IO_Running: Yes
Slave_SQL_Running: No
省略部分输出……
Last_Errno: 1007
Last_Error: Error 'Can't create database 'test'; database exists' on query. Default database: 'test'. Query: 'create database test'
省略部分输出……
Last_SQL_Errno: 1007
Last_SQL_Error: Error 'Can't create database 'test'; database exists' on query. Default database: 'test'. Query: 'create database test' 无法创建test库,test库已经存在,就是因为从库写入导致的
省略部分输出……
1 row in set (0.00 sec)
原因是SQL线程一旦检测到故障,就不会再工作了!重启一下就好了!
(3)重启主从状态
mysql> start slave;
Query OK, 0 rows affected (0.00 sec)
(4)再次查看主从状态
mysql> mysql> show slave status\G
*************************** 1. row ***************************
省略部分输出……
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
省略部分输出……
(5)检查数据同步情况
mysql> use test;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| t1 | 同步成功
+----------------+
1 row in set (0.00 sec)
解决从库写入故障方法 2 --以从库为准的恢复
模拟故障:
从库操作:
mysql> create table t2(id int,name varchar(20));
Query OK, 0 rows affected (0.01 sec)
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| t1 |
| t2 |
+----------------+
2 rows in set (0.00 sec)
主库操作:
mysql> use test;
Database changed
mysql> create table t2(id int,name varchar(20) charset utf8mb4);
Query OK, 0 rows affected (0.08 sec)
从库查看主从状态:发现主从已经异常了
mysql> show slave status\G
*************************** 1. row ***************************
省略部分输出…………
Slave_IO_Running: Yes
Slave_SQL_Running: No
省略部分输出…………
Last_Errno: 1050
Last_Error: Error 'Table 't2' already exists' on query. Default database: 'test'. Query: 'create table t2(id int,name varchar(20) charset utf8mb4)'
省略部分输出…………
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 1050
Last_SQL_Error: Error 'Table 't2' already exists' on query. Default database: 'test'. Query: 'create table t2(id int,name varchar(20) charset utf8mb4)'
省略部分输出…………
1 row in set (0.01 sec)
解决方法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.00 sec)
再次查看主从状态:发现主从关系已经恢复,但是数据时不能同步的
mysql> show slave status\G
*************************** 1. row ***************************
省略部分输出……
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
省略部分输出……
主库操作:
mysql> insert into t2 values(1,'abc');
Query OK, 1 row affected (0.00 sec)
mysql> select * from t2;
+------+------+
| id | name |
+------+------+
| 1 | abc |
+------+------+
1 row in set (0.01 sec)
从库操作:发现数据没有同步
mysql> select * from t2;
Empty set (0.00 sec)
查看主从状态:
mysql> show slave status\G
省略部分输出…………
Last_SQL_Error: Column 1 of table 'test.t2' cannot be converted from type 'varchar(80(bytes))' to type 'varchar(20(bytes) latin1)'
报错:字符集长度不一致,即使主从状态一致,数据页无法同步
省略部分输出…………
从库操作:跳过错误操作
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.00 sec)
主库操作:删除导致主从异常的表,t2表
mysql> drop table t2;
Query OK, 0 rows affected (0.01 sec)
从库操作:
mysql> show tables;
+----------------+
| Tables_in_test |
+----------------+
| t1 |
+----------------+
1 row in set (0.00 sec)
解决方法2:最完美的解决办法(推荐)
(1)设置从库只读,防止从库写入,redo-only参数。
从库设置:
mysql> show variables like '%read_only%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| innodb_read_only | OFF |
| read_only | OFF | read_only 设置为1,从库就为只读状态,但是只能作用在普通用户身上
| super_read_only | OFF | super_read_only设置为1,对全部用户生效,从库只读
| transaction_read_only | OFF |
| tx_read_only | OFF |
+-----------------------+-------+
5 rows in set (0.00 sec)
(2)使用中间件做成读写分离的架构。
6. 主从延时原因分析(面试题)
从库延时主库的时间:
Seconds_Behind_ Master: 0 从库延时主库时间单位为秒
6.1 主库方面
原因(1):
binlog日志写入不及时
解决方法:双一标准的第二个“1”!
mysql> select @@sync_binlog;
+---------------+
| @@sync_binlog |
+---------------+
| 1 | 每次事务提交,立即刷写日志到磁盘,5.6以后的默认就是1。
+---------------+
1 row in set (0.00 sec)
原因(2):
主库并发业务较高,事务量大,忙不过来
解决方法:
a. 升级硬件
b. 分布式架构
原因(3):
从库太多
解决方法:
a. 减少从库,读少的情况下可以这样
b. 级联主从(主库+中间库+从库) 读多写少
主从延时补充:
对于Classic Rrplication(传统复制模式),主库是有能力并发运行事务的,但是在Dump_T在传输日志的时候,是以事件为单元来传输日志的,所以导致事务传输工作是串行方式的。
这时在主库TPS(每秒的事务量级)很高时,会产生比较大的主从延时。
那么如何处理这个问题呢?
group commit(在同一时刻提交的事务)=GTID复制+双一
从5.6开始,加入了GTID,在复制时,可以将原来串行的传输模式变成并行的。
但是光有GTID的支持是不够的,还需要“双一”保证,也就是sync_binlog=1。
5.7 中默认就是双一模式,也就是sync_binlog=1。
6.2 从库方面
Classic Rrplication,SQL线程只有一个,只能串行执行relay的事务。
那么如何解决呢?
可以多加几个SQL线程
在5.6中出现了database级别的多线程SQL,但是只能针对不同库下的事务,才能并发。
到5.7版本加入了MTS,才真正实现了事务级别的并发SQL。
7. 延时从库
注意:延时从库跟主从延时是不一样的,延时从库是主动配置的,用来防止误操作同步
7.1 主从复制能解决的故障--数据损坏
(1)物理损坏:
数据库的物理文件被误操作,rm
磁盘坏了等
(2)逻辑损坏:
数据库内部命令误操作,drop
(3)对于传统的主从复制来讲,比较“擅长处理物理损坏”,但是“不擅长逻辑损坏”。
7.2 延时从库设计理念
对从库的SQL线程进行延时设置
7.3 延时多久合适?
生产中建议3-6小时
如果需要用到被延时的数据,可以恢复3-6个小时的日志
7.4 设置方法(从库)
mysql>stop slave;
mysql>CHANGE MASTER TO MASTER_DELAY = 300; 300为测试环境设置,单位为秒
mysql>start slave;
mysql> show slave status \G
……省略若干行
SQL_Delay: 300 延迟同步5分钟
SQL_Remaining_Delay: NULL 同步时间计时器,主库有操作时触发
……省略若干行
7.5 延时从库使用方法
7.5.1 使用思路
模拟故障:
主库操作:
create database delay charset utf8mb4;
use delay;
create table t1(id int);
insert into t1 values(1),(2),(3);
commit;
drop database delay; 此时,主库误操作,发生逻辑损坏,从库5分钟后也会执行该操作
现在发现上面这个问题了,解决办法:
(1) 停止从库SQL线程,停止主库业务。
(2) 模拟从库SQL线程,手工恢复relaylog到drop之前的位置点。
(3) 截取relaylog日志,找到起点(relay-log.info中)和终点(drop操作之前)。
(4) 恢复截取日志,验证数据可用性。
开始处理:如果主库有业务,主库也要停掉
1. 停止从库SQL线程
mysql -S /data/3308/msyql.sock
stop slave sql_thread;
2. 找从库中relaylog的起点和终点
show slave status\G
起点:
Relay_Log_File: db02-relay-bin.000002
Relay_Log_Pos: 1087
终点:只看左边一列,右边一列对应的是主库的binlog日志点
show relaylog events in 'db02-relay-bin.000002';
找到drop操作
db02-relay-bin.000002 | 1759 drop之前 | Query | 6 | 3504 | drop database delay
3. 截取从库relay log日志
mysqlbinlog --start-position=1087 --stop-position=1759 /data/3308/data/db01-relay-bin.000002 >/tmp/relay.sql
要确定relay.sql中没有包含drop操作才能下一步
4. 恢复从库数据
set sql_log_bin=0;
source /tmp/relay.sql
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| delay |
| mysql |
| performance_schema |
| sys |
+--------------------+
mysql> use delay
mysql> select * from t1;
+------+
| id |
+------+
| 1 |
| 2 |
| 3 |
+------+
3 rows in set (0.00 sec)
8. 过滤复制
把某一个库复制到从节点,可以在主库方面或从库方面来实现
(1)重新恢复主从环境 仅为测试环境操作
主库操作:
mysql> show master status;
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000002 | 887 | | | |
+------------------+----------+--------------+------------------+-------------------+
1 row in set (0.00 sec)
从库操作:
stop slave;
reset slave all;
CHANGE MASTER TO
MASTER_HOST='10.0.0.51',
MASTER_USER='repl',
MASTER_PASSWORD='123',
MASTER_PORT=3306,
MASTER_LOG_FILE='mysql-bin.000002',
MASTER_LOG_POS=887,
MASTER_CONNECT_RETRY=10;
start slave;
主库方面实现(了解)
主库操作:
mysql> show master status;
省略部分输出…………
Binlog_Do_DB 白名单,在白名单中的库名会记录日志
可以写到配置文件中,但是要小写
Binlog_Ignore_DB 黑名单,在黑名单中的不记录日志
实际工作中只用白名单或黑名单。
从库方面实现
show slave status\G
省略部分输出…………
Replicate_Do_DB: 只会进行复制某些或某个库(库级别的白名单)(使用较多)
Replicate_Ignore_DB: 不复制某些或某个库(库级别的黑名单)(使用较多)
Replicate_Do_Table: 只会进行复制某些或某个表(表级别的白名单)
Replicate_Ignore_Table: 不复制某些或某个表(表级别的黑名单)
Replicate_Wild_Do_Table: 模糊匹配白名单
Replicate_Wild_Ignore_Table: 模糊匹配黑名单
省略部分输出…………
例子:只需要复制xyz库的数据到从库
(1)更改my.cnf配置文件
[root@db01 ~]# vim /data/3308/my.cnf
……省略若干行
replicate_do_db=xyz
……省略若干行
[root@db01 ~]# systemctl restart mysqld3308
(2)检查配置是否生效
show slave status\G
……省略若干行
Replicate_Do_DB: xyz
……省略若干行
注意:如果有多个库的话,写多行即可。
replicate_do_db=xxx
replicate_do_db=xxx
replicate_do_db=xxx
(3)主库创建xyz库与abc库
mysql> create database xyz;
mysql> create database abc;
(4)从库查看同步情况
mysql> show databases;
+--------------------+
| Database |
+--------------------+
|省略部分输出……|
| xyz |
+--------------------+
7 rows in set (0.00 sec)
(5)总结
在SQL线程回放日志时,进行过滤控制
因为在创建非白名单内的库时,从库通过show slave status\G,
查看发现Master_log_file与Read_Master_Log_Pos都发生了变化,
说明创建非白名单内的库时,该库的日志文件已经同步过来,但是并没有进行回放,所以没有该库。
9. 半同步复制(面试题,了解理论即可)
半同步复制和传统复制的区别:
半同步复制是一个插件形式提供的功能。
主库方面多了一个线程:ack_receillver
从库多了一个线程:ACK_send
主库:receillver线程,只有接到从库发来的ACK确认,主库事务才能commit成功。
从库:Acksend只有等relaylog落地才能发送ACK
主库只会等10s,如果ACK还没有收到,会自动替换为异步复制(传统),不等了。
10 .GTID复制
10.0 GTID提供的特性
group commit , MTS
10.1 重点参数(GTID复制必加)
gitd-mode=on 开启GTID
enforce-gtid-consistency=true 强制GTID一致性,主从环境必配
log-slave-updates=1 从库配置,强制刷新从库二进制日志。应用场景5.7:1. 高可用(MHA)2. 级联复制的中间库
10.2 搭建一主两从GTID复制环境
需要3台服务器
10.0.0.51 主库
10.0.0.52 从库
10.0.0.53 从库
(1)清理环境
pkill mysqld
\rm -rf /data/*
\rm -rf /data/*
mkdir -p /data/mysql/data
mkdir -p /data/binlog/
chown -R mysql.mysql /data
10.3 准备配置文件
主库db01:
cat > /etc/my.cnf <<EOF
[mysqld]
basedir=/application/mysql/
datadir=/data/mysql/data
socket=/tmp/mysql.sock
server_id=51
port=3306
secure-file-priv=/tmp
autocommit=0
log_bin=/data/binlog/mysql-bin
binlog_format=row
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1
[mysql]
prompt=db01 [\\d]>
EOF
从库(db02):
cat > /etc/my.cnf <<EOF
[mysqld]
basedir=/application/mysql
datadir=/data/mysql/data
socket=/tmp/mysql.sock
server_id=52
port=3306
secure-file-priv=/tmp
autocommit=0
log_bin=/data/binlog/mysql-bin
binlog_format=row
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1
[mysql]
prompt=db02 [\\d]>
EOF
从库(db03):
cat > /etc/my.cnf <<EOF
[mysqld]
basedir=/application/mysql
datadir=/data/mysql/data
socket=/tmp/mysql.sock
server_id=53
port=3306
secure-file-priv=/tmp
autocommit=0
log_bin=/data/binlog/mysql-bin
binlog_format=row
gtid-mode=on
enforce-gtid-consistency=true
log-slave-updates=1
[mysql]
prompt=db03 [\\d]>
EOF
10.4 初始化数据(所有节点)
mysqld --initialize-insecure --user=mysql --basedir=/application/mysql --datadir=/data/mysql/data
10.5 启动数据库
/etc/init.d/mysqld start
10.6 主库创建用户
grant replication slave on *.* to repl@'10.0.0.%' identified by '123';
10. 7 两个从库开始主从
mysql -e "change master to master_host='10.0.0.51',master_user='repl',master_password='123' ,MASTER_AUTO_POSITION=1;start slave; "
mysql -e "show slave status \G"|grep Yes
10.8 GTID复制与传统复制的区别
参数比对:
GTID复制:
CHANGE MASTER TO
MASTER_HOST='10.0.0.51',
MASTER_USER='repl',
MASTER_PASSWORD='123' ,
MASTER_AUTO_POSITION=1; 指明为GTID复制模式
传统复制:
CHANGE MASTER TO
MASTER_HOST='10.0.0.51',
MASTER_USER='repl',
MASTER_PASSWORD='123',
MASTER_PORT=3306,
MASTER_LOG_FILE='mysql-bin.000002',
MASTER_LOG_POS=887,
MASTER_CONNECT_RETRY=10;
总结:
MASTER_AUTO_POSITION=1; 指明为GTID复制模式后,
会自动寻找复制起点