MySQL Replication
主从复制介绍
1.主从复制基于binlog来实现的
2.主库发生新的操作,都会记录binlog
3.从库取得主库的binlog进行回放
4.主从复制的过程时异步
搭建主从复制
1.2个或以上的数据库实例
2.主库需要开启二进制日志
3.server_id要不同,区分不同的节点
4.主库需要建立专用的复制用户(replication slave)
5.人为告诉从库一些复制信息(ip,port user pass,二进制日志起点)
6.从库应该开启专门的复制线程
准备多实例
3307为主库 3308位从库 (搭建过程https://www.jianshu.com/writer#/notebooks/40881420/notes/57340778
)
启动3307
pkill mysqld
systemctl start mysqld 3307
初始化3308
mysqld --initialize-insecure --user=mysql --basedir=/application/mysql --datadir=/data/3308/data
systemctl start mysqld3308
mysql -S /data/3308/mysql.sock
检查3307
mysql -uroot -p123456 -S /data/3307/mysql.sock -e 'select @@port'
检查配置文件
主库:二进制日志是否开启
3307
[mysqld]
basedir=/application/mysql
datadir=/data/3307/data
socket=/data/3307/mysql.sock
port=3307
server_id=7
log_bin=/data/3307/mysql-bin
3308
[mysqld]
basedir=/application/mysql
datadir=/data/3308/data
socket=/data/3308/mysql.sock
port=3308
server_id=8
log_bin=/data/3308/mysql-bin
主库创建复制用户
mysql -uroot -p123456 -S /data/3307/mysql.sock -e "grant replication slave on *.* to repl@'10.0.0.%' identified by '123456';"
主库进行全备
mysqldump -root -p123456 -S /data/3307/mysql.sock -A --master-data=2 --single-transaction -R -E --triggers >/tmp/full.sql
从库
mysql -uroot -p123456 -S /tmp/full.sql
set sql_log_bin=0;
source /tmp/full.sql
告诉从库复制信息
查看起始点
more /tmp/full.sql
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000003', MASTER_LOG_POS=444;
登陆数据库
mysql -uroot -p123456 -S /data/3308/mysql.scok
CHANGE MASTER TO
MASTER_HOST='10.0.0.51', #主机IP或主机名
MASTER_USER='repl', #用户
MASTER_PASSWORD='123456', #密码
MASTER_PORT=3307, #端口
MASTER_LOG_FILE='mysql-bin.000003', #binlog日志
MASTER_LOG_POS=444, #起点
MASTER_CONNECT_RETRY=10;
从库开启复制线程(IO,SQL)
start slave;
检查主从复制的状态
show status slave \G
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
主库创建一个数据库
create database hahaha;
从库检查
show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| backup |
| binlog |
| gtid |
| hahaha |
| mysql |
| performance_schema |
| school |
| sky |
| sys |
| test |
| world |
| zabbix |
+--------------------+
如果复制中出现错误看看是否change master to里写错了
stop slave;
reset slave all;
再次change master to...
主从复制的原理
主从复制中涉及的文件
主库:
binlog
从库:
relaylog 中继日志
master.info 主库信息文件
relaylog.info relaylog应用的信息
主从复制中涉及的线程
主库:
binlog_dump Therad : DUMP_T
从库:
SLAVE_IO_THREAD : IO_T
SLAVE_SQL_THREAD : SQL_T
1.从库执行change master to命令(主库的连接信息+复制点)
2.从库将以上信息,记录到master.info文件中
3.从库执行start slave 命令,立即开启IO_T和SQL_T
- 从库的IO_T,读取master.info文件中的信息(IP,PROT,USER,PASS,binlog
位置点)
5.从库IO_T请求连接主库,主库专门提供一个DUMP_T,负责和IO_T交互
6.IO_T根据binlog的位置信息,请求主库新的binlog
7.主库DUMP_T 将最新的binlog,通过网络TP(传送)给从库的IO_T
8.IO_T接收到新的binlog日志,存储到TCP/IP缓存中,立即返回ACK给主库,并更新master.info
9.IO_T将TCP/IP缓存中数据,转存到磁盘relaylog中
10.SQL_T读取relay.info中的信息,获取上次已经应用过的relay.log的位置信息
11.SQL_T会按照上次的位置点往后回放最新的relaylog,再次更新relay.info信息
12.从库会自动purge应用过relay进行定期清理
补充说明:
一旦主从复制构建成功,主库当中发生了新的变化,都会通过dump_T发送信号给IO_T,增强了主从复制的实时性
主从复制监控
show slave status\G
mysql> show slave status \G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
[主库相关信息 master.info]
Master_Host: 10.0.0.51 地址
Master_User: repl 用户
Master_Port: 3307 端口
Connect_Retry: 10 尝试几次
Master_Log_File: mysql-bin.000003 应该与主库相同
Read_Master_Log_Pos: 609
[从库relaylog应用信息relay.info]
Relay_Log_File: db01-relay-bin.000002 从库SQL_T到那个点
Relay_Log_Pos: 485
Relay_Master_Log_File: mysql-bin.000003
[从库线程运行状态用于排错]
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Last_IO_Errno: 0 从下面复制过来的
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
[过滤复制有关的]
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
[从库延迟的时间]
Seconds_Behind_Master: 0 查看主从复制延迟
[延迟从库,人为定制]
SQL_Delay: 0
SQL_Remaining_Delay: NULL
[GTID复制有关的状态信息]
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 0
主从复制故障
从库:
IO线程故障
连接主库(connecting): 网络,连接信息错误或变更了,防火墙,连接数上限
排查思路:使用复制用户手工登陆,是否用户名 密码 端口 是否正确
stop slave
reset slave all;
change master to...
start slave;
请求binlog
binlog 没开
binlog 损坏,不存在,reset master
主库reset master处理办法
从库
stop slave;
reset slave all;
change master to 最新的
start slave;
SQL线程故障
relay-log损坏
回放relaylog,一下容易出现SQL故障的
insert delete update ----> t1 表不存在,
create table sky --->sky 库不存在
约束冲突(主建,唯一键,非空...)
合理解决办法:
一切以主库为准进行解决
如果出现问题,尽量进行反操作
最直接稳妥的办法,重新构造主从
暴力的解决办法
方法一:
stop slave;
set gloabl sql_slave_skip_counter =1;
将同步指针向下移动一个,如果多次不同步,可以重复操作
start slave;
方法二:
/etc/my.cnf
slvae-skip-errors=1032,1062,1007
常见错误代码
1007:对象已经存在
1032:无法执行DML
1062:主建冲突,或约束冲突
但是,以上操作有时是由风险的,最安全的做法就是重新构造主从
对于主建冲突问题
主从延迟
主库方面
1,binlog写入不及时
sync_binlog=1 及时写入
2,默认情况下dump_T 是串行传输binlog
在并发事务量大时,由于dump_t是串行工作的,导致传输日志较慢
解决办法
必须GTID,使用group commit方式,支持dump_t并行
3.主库及其繁忙
慢语句
锁等待
从库个数
网络延时
从库方面
1.传统复制中
如果主库并发事务量很大,或者出现大事务
由于从库是单线程,导致,不管传的日志有多少,只能一次执行一个事务
5.6版本,有了GTID,可以实现多sql线程,但是只能基于不同库的事务进行并发回放(database)
5.7版本,有了增强的GTID,增加了seq_no,增加了新型的并发SQL线程模式(logical_clock),MTS技术
2.主从硬件差异太大
3.主从的参数配置
4.从库和主库的索引不一致
5.主从版本不一样
监控主从延迟
mysql> show slave status\G
Seconds_Behind_Master: 0
主库方面的原因监控
show master status\G
File: mysql-bin.000003
Position: 609
跟从库对比
Master_Log_File: mysql-bin.000003
Read_Master_Log_Pos: 609
从库方面的原因监控
cat relay-log.info
7
./db01-relay-bin.000003
320
mysql-bin.000003
609
show slave status\G
Relay_Log_File: db01-relay-bin.000004
Relay_Log_Pos: 320
Exec_Master_Log_Pos: 609
Master_Log_File: mysql-bin.000003
Read_Master_Log_Pos: 609
一致没有延迟,如果有区别,查了多少pos 看看谁导致的,查看 exec_masetr_log_pos 与read_master_log_pos查了多少个,查看日志
延时从库
stop slave;
#秒单位
change master to master_delay=300;
start slave;
查看状态
show slave status \G
SQL_Delay: 300 #300秒
SQL_Remaining_Delay: NULL #最近一个事务还差多少秒
在主库创建一个库
create database aa;
这个时候再去查看
show slave status\G
SQL_Delay: 300
SQL_Remaining_Delay: 294
假如主库被删除了 ,停掉sql线程
故障恢复思路
1.监控到数据库逻辑故障
2.停从库SQL线程,记录已经回放的位置点(截取日志起点)
stop slave sql_thread;
show slave status \G
relay_log_file: db01-relay-bin.000003
relay_log_pos: 320
3.截取relayLog
起点:
show slave status \G
relay_log_file relay_log_pos
终点:drop之前的位置点
show relaylog events in ' '
进行截取
4.模拟sql线程回放日志
从库 source
5.恢复业务
情况一:就一个库的话,从库代替主库工作
情况二:从库导出故障库,还原到主库中
故障演练
主库
create database delay charset utf8mb4;
use delay;
create table t1 (id int);
insert into t1 values(1),(2),(3);
commit;
drop databases delay;
从库
停止从库SQL线程
stop slave sql_thread;
获取起点位置
show slave statu \G
Relay_Log_File: db01-relay-bin.000003
Relay_Log_Pos: 320
找到relay的截取终点
mysql> show relaylog events in 'db01-relay-bin.000003';
+-----------------------+-----+----------------+-----------+-------------+---------------------------------------+
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
+-----------------------+-----+----------------+-----------+-------------+---------------------------------------+
| db01-relay-bin.000003 | 4 | Format_desc | 8 | 123 | Server ver: 5.7.26-log, Binlog ver: 4 |
| db01-relay-bin.000003 | 123 | Previous_gtids | 8 | 154 | |
| db01-relay-bin.000003 | 154 | Rotate | 7 | 0 | mysql-bin.000003;pos=765 |
| db01-relay-bin.000003 | 201 | Format_desc | 7 | 0 | Server ver: 5.7.26-log, Binlog ver: 4 |
| db01-relay-bin.000003 | 320 | Anonymous_Gtid | 7 | 830 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| db01-relay-bin.000003 | 385 | Query | 7 | 943 | create database delay charset utf8mb4 |
| db01-relay-bin.000003 | 498 | Anonymous_Gtid | 7 | 1008 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| db01-relay-bin.000003 | 563 | Query | 7 | 1108 | use `delay`; create table t1 (id int) |
| db01-relay-bin.000003 | 663 | Anonymous_Gtid | 7 | 1173 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| db01-relay-bin.000003 | 728 | Query | 7 | 1246 | BEGIN |
| db01-relay-bin.000003 | 801 | Table_map | 7 | 1292 | table_id: 255 (delay.t1) |
| db01-relay-bin.000003 | 847 | Write_rows | 7 | 1342 | table_id: 255 flags: STMT_END_F |
| db01-relay-bin.000003 | 897 | Xid | 7 | 1373 | COMMIT /* xid=2891 */ |
| db01-relay-bin.000003 | 928 | Anonymous_Gtid | 7 | 1438 | SET @@SESSION.GTID_NEXT= 'ANONYMOUS' |
| db01-relay-bin.000003 | 993 | Query | 7 | 1533 | drop database delay |
+-----------------------+-----+----------------+-----------+-------------+---------------------------------------+
15 rows in set (0.00 sec)
|db01-relay-bin.000003 | 993 | Query | 7 | 1533 | drop database delay 这个就是结束位置
截取relaylog
cd /data/3308/data/
截取
mysqlbinlog --start-position=320 --stop-position=993 db01-relay-bin.000003 >/tmp/relay.sql
查看一下relay.sql有没有drop命令 没有就对了
恢复relay到从库
set sql_log_bin=0;
source /tmp/relay.sql
show databases;
show tables;
+-----------------+
| Tables_in_delay |
+-----------------+
| t1 |
+-----------------+
1 row in set (0.00 sec)
过滤复制
快速恢复测试环境
从库
drop database delau;
stop slave;
reset slave all;
主库
reset master;
从库重新连接
mysql> change master to
-> master_host='10.0.0.51',
-> master_user='repl',
-> master_password='123456',
-> master_port=3307,
-> master_log_file='mysql-bin.000001',
-> master_log_pos=154,
-> master_connect_retry=10;
Query OK, 0 rows affected, 2 warnings (0.00 sec)
start slave;
参数
主库(很少用)
binlog_do_db=word 白名单 只会同步word
binlog_ignore_db=word 黑名单 不会同步world
从库(写到配置文件里全是小写)
[库级别的]
replicate_do_db=白名单
replicate_ignore_db:=黑名单
[表级别的]
Replicate_Do_Table:
Replicate_Ignore_Table:
[模糊匹配表]
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
测试
从库
replicate_do_db=repl
systemctl restart mysqld3308
主库
create database aaaaaaaaaa;
从库查看
show databases;
并没有
主库
create database repl;
从库查看
show databases;
主从调优
5.7从库多线程MTS
必须开启GTID
binlog必须是row模式
gtid_mode=on
enforce_gtid_consistency=on
log_slave_updates=on
slave_parallel_type=LOGICAL_CLOCK
slave_parallel_workers=16
CPU核心数作为标准
master_info_repository=TABLE
relay_log_info_repository=TABLE
relay_log_recovery=ON