主从复制,延时从库,半同步,过滤复制,GTID复制
介绍
1.1. 基于二进制日志复制的
1.2. 主库的修改操作会记录二进制日志
1.3. 从库会请求新的二进制日志并回放,最终达到主从数据同步
1.4. 主从复制核心功能:
辅助备份,处理物理损坏
扩展新型的架构:高可用,高性能,分布式架构等
主从复制搭建准备
两台以上mysql实例 ,server_id,server_uuid不同
主库开启二进制日志
主库建立专用的复制用户
保证主从开启之前的某个时间点,从库数据是和主库一致(补课)
告知从库,复制user,passwd,IP port,以及复制起点(change master to)
线程(三个):Dump thread IO thread SQL thread 开启(start slave)
主从复制搭建
准备多实例环境
#创建目录并授权
mkdir -p{3307,3308,3309}/{logs,data,binlog}
chown mysql:mysql -R /data/
#清理主库数据
rm -rf /data/3307/data/*
#重新初始化3307
mysqld --initialize-insecure --user=mysql --basedir=/opt/mysql --datadir=/data/3307/data
#根据数据位置修改配置文件并分别发送到各节点
log_bin=/data/3307/data/mysql-bin #binlog配置必须开启
#启动所有实例
systemctl start mysqld3307
###配置验证
mysql -S /data/3308/data/mysql.sock -e "select @@server_id;" #验证serverid
mysql -S /data/3307/data/mysql.sock -e "show variables like '%log_bin%';" #binlog是否打开
主库创建复制用户
[root@db01 3307]# mysql -S /data/3307/mysql.sock
mysql>grant replication slave on *.* to repl@'172.22.186.29' identified by '1';
mysql>select user,host from mysql.user;
主库数据备份还原至从库
[root@db01 3307]# mysqldump -S /data/3307/data/mysql.sock -A --master-data=2 --single-transaction -R --triggers >/tmp/full.sql
[root@db01 3307]# mysql -S /data/3308/data/mysql.sock
mysql> set sql_log_bin=0;
mysql>source /tmp/full.sql
####prompt定义mysql提示符
\d The default database
\h The server host
\m Minutes of the current time
\P The current TCP/IP port or socket file
\R The current time(Hour), in 24-hour military time(0-23)
\r The current time(Hour), standard 12-hour time(1-12)
\s Seconds of the current time
\u Your user name
告知从库关键复制信息
ip port user password binlog position
[root@db01 3307]# mysql -S /data/3308/mysql.sock
db01 [mysql]>help change master to
CHANGE MASTER TO
MASTER_HOST='source2.example.com', #主库ip
MASTER_USER='replication', #同步用户
MASTER_PASSWORD='password', #同步密码
MASTER_PORT=3306, #端口
MASTER_LOG_FILE='source2-bin.001', #通过还原数据的脚本查看binlog文件
#-- CHANGE MASTER TO MASTER_LOG_FILE='mysql_bin.000001', MASTER_LOG_POS=449;
MASTER_LOG_POS=4, #事件
MASTER_CONNECT_RETRY=10;
#配置主从
CHANGE MASTER TO
MASTER_HOST='172.22.186.29',
MASTER_USER='repl',
MASTER_PASSWORD='1',
MASTER_PORT=3307,
MASTER_LOG_FILE='mysql_bin.000001',
MASTER_LOG_POS=449,
MASTER_CONNECT_RETRY=10;
#主从复制信息配置错误处理办法--首先停止主从进程,然后重置主从配置,再重新配置即可
stop slave;#关闭主从复制
reset slave all; #重置
CHANGE MASTER TO
MASTER_HOST='172.22.186.29',
MASTER_USER='repl',
MASTER_PASSWORD='1',
MASTER_PORT=3307,
MASTER_LOG_FILE='mysql_bin.000001',
MASTER_LOG_POS=449,
MASTER_CONNECT_RETRY=10;
start slave;
mysql> show slave status\G;#查询主从状态
主从复制过程
查看mysql主库线程
mysql -S /data/3307/data/mysql.sock -e "show processlist"
Id: 7
User: repl
Host: wutonglinaliyun:48614
db: NULL
Command: Binlog Dump
Time: 6186
State: Master has sent all binlog to slave; waiting for more updates
Info: NULL
文件进程介绍
主:Binlog Dump THREAD 二进制日志投递线程
从:IO THREAD 请求和接受binlog日志 SQL THREAD:回放日志
主:mysql-bin.000001
从:
db01-relay.000001 ===>中继日志
master.info ===》主库信息记录日志
relay-log.info ===> 记录中继应用情况信息
工作过程
1.从库执行change master to 时,ip port user password binlog position写入到master.info进行记录
2. 从库执行start slave 时,从库会启动IO线程和SQL线程
3.IO_T,读取master.info信息,获取主库信息连接主库
4. 主库会生成一个准备binlog DUMP线程,来响应从库
5. IO_T根据master.info记录的binlog文件名和position号,请求主库DUMP最新日志
6. DUMP线程检查主库的binlog日志,如果有新的,TP(传送)给从库的IO_T
7. IO_T将收到的binlog日志存储到了TCP/IP 缓存,立即返回ACK给主库 ,主库工作完成
8.IO_T将缓存中的数据,存储到relay-log日志文件,更新master.info文件binlog 文件名和postion,IO_T工作完成
9.SQL_T读取relay-log.info文件,获取到上次执行到的relay-log的位置,作为起点,回放relay-log
10.SQL_T回放完成之后,会更新relay-log.info文件。
11. relay-log会有自动清理的功能。
细节:
1.主库一旦有新的日志生成,会发送“信号”给binlog dump ,IO线程再请求
主从监控
主库监控
mysql> show processlist #看到Binlog Dump进程存在,state状态是Master has sent all binlog to slave; waiting for more updates(Master已经发送所有binlog到slave;等待更多更新)
从库监控
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
/* 这几个项记录的主库的信息,读取的master.info中记录
Master_Host: 172.22.186.29
Master_User: repl
Master_Port:3307
Connect_Retry:10 #主从连接重试次数,重试间隔时长1分钟
Master_Log_File:mysql_bin.000001 #已获取到的binlog的文件名
Read_Master_Log_Pos:449 #已经获取到binlog的位置号
*/
/* 从库relaylog的信息(relay-log.info )
Relay_Log_File:wutonglinaliyun-relay-bin.000002 #从库已经运行过的relaylog文件名
Relay_Log_Pos:320 #从库已经运行过的relaylog位置点
*/
Relay_Master_Log_File:mysql_bin.000001
/* 从库两个进程的状态
Slave_IO_Running:Yes
Slave_SQL_Running:Yes
*/
/* 过滤复制相关配置或状态
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:449
Relay_Log_Space:537
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
/*从库线程报错详细信息
Last_IO_Errno:0 #错误号
Last_IO_Error:#错误详细信息,如果为空则查看从库错误日志,也会有详细记录
Last_SQL_Errno:0
Last_SQL_Error:
*/
Replicate_Ignore_Server_Ids:
Master_Server_Id:7
Master_UUID:ad5fa82d-8f07-11ec-8d35-00163e0e6664
Master_Info_File:/data/3308/data/master.info
SQL_Delay:0 #延时从库设定时间,防止主从同时误操作
SQL_Remaining_Delay:NULL #延时操作剩余时间
Slave_SQL_Running_State:Slavehasreadallrelaylog;waitingformoreupdates
Master_Retry_Count:86400
Master_Bind:
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
Master_SSL_Crl:
Master_SSL_Crlpath:
Retrieved_Gtid_Set: #接收到的gtid的个数
Executed_Gtid_Set:ad5fa82d-8f07-11ec-8d35-00163e0e6664:1 #执行gtid个数
Auto_Position:0
Replicate_Rewrite_DB:
Channel_Name:
Master_TLS_Version:
主从错误复制分析
IO线程故障
###io线程工作包括连接主库、请求新的binlog、写relaylog、更新master.info、server_id重复,进程失败的原因和工作内容有关
#连接主库连接不上(connecting):
错误原因:网络不同、防火墙策略、ip地址、端口、用户名密码不正确、skip_name_resolve(5.7以前版本会有,作用是将写的ip地址通过hosts文件转换为主机名)、连接数上限
验证办法:使用复制用户通过tcp/ip方式连接数据库验证以上问题
解决办法:stop slave;reset slave all; CHANGE MASTER TO即可
#请求新的binlog,io线程状态no
错误原因:
日志名称:检查Relay_Log_File:Relay_Log_Pos:配置,对比备份位置号
日志损坏、日志不连续:binlog日志丢失或主库binlog日志reset master,重置了binlog序号
解决办法:CHANGE MASTER TO修改binlog日志的名称和位置
写relaylog、更新master.info权限
server_id重复
sql线程故障
sql线程工作:读写relay-log.info、读取relay-log执行sql,sql执行异常
故障原因:
0.relay-log.info、relay-log文件损坏
1.版本差异,参数设定不同,比如:数据类型的差异,SQL_MODE影响
2.要创建的数据库对象,已经存在
3.要删除或修改的对象不存在
4.DML语句不符合表定义及约束时.
归根揭底的原因都是由于从库发生了写入操作.
Last_SQL_Error: Error 'Can't create database 'db'; database exists' on query. Default database: 'db'. Query: 'create database db'
#解决方案
方法一:
stop slave;
set global sql_slave_skip_counter = 1;
#将同步指针向下移动一个,如果多次不同步,可以重复操作。
start slave;
方法二:
/etc/my.cnf
slave-skip-errors = 1032,1062,1007
常见错误代码:
1007:对象已存在
1032:无法执行DML
1062:主键冲突,或约束冲突
但是,以上操作有时是有风险的,最安全的做法就是重新构建主从。把握一个原则,一切以主库为主.
###一劳永逸的解决办法
(1) 可以设置从库只读.
db01 [(none)]>show variables like '%read_only%';
注意:
只会影响到普通用户(read_only| OFF),对管理员用户无效(super_read_only)。
(2)加中间件
读写分离。
主从延时分析
Seconds_Behind_Master:0#从库延时时间,不一定准确,可以参考延迟事件量
#网络 、主从硬件差异较大、版本差异、参数因素都会导致主从延时
(1) 二进制日志写入不及时
[rep]>select @@sync_binlog;#双一标准的另一个,立即落盘日志
(2) CR的主从复制中,主库是有能力并发运行事务的,但在dump_T在传输日志的时候,是以事件为单元传输日志的,所以导致事务的传输工作时串行方式,这个时候主库的tps较高时就会产生较大的主从延时(5.6 5.5)
1. 主库并发事务量大,主库可以并行,传送时是串行
2. 主库发生了大事务,由于是串行传送,会产生阻塞后续的事务.
解决方案:
1. 5.6 开始,开启GTID,实现了GC(group commit)机制,可以并行传输日志给从库IO
2. 5.7 开始,不开启GTID,会自动维护匿名的GTID,也能实现GC,我们建议还是认为开启GTID
3. 大事务拆成多个小事务,可以有效的减少主从延时.
SQL线程导致的主从延时
在CR复制情况下: 从库默认情况下只有一个SQL,只能串行回放事务SQL
1. 主库如果并发事务量较大,从库只能串行回放
2. 主库发生了大事务,会阻塞后续的所有的事务的运行
解决方案:
1. 5.6 版本开启GTID之后,加入了SQL多线程的特性,但是只能针对不同库(database)下的事务进行并发回放.
2. 5.7 版本开始GTID之后,在SQL方面,提供了基于逻辑时钟(logical_clock),binlog加入了seq_no机制,
真正实现了基于事务级别的并发回放,这种技术我们把它称之为MTS(enhanced multi-threaded slave).
3. 大事务拆成多个小事务,可以有效的减少主从延时.
[https://dev.mysql.com/worklog/task/?id=6314]
延时从库
是我们认为配置的一种特殊从库.人为配置从库和主库延时N小时.
主从复制非常擅长解决物理损坏.延时主从复制可以解决逻辑损坏
延时从库配置
#SQL线程延时:数据已经写入relaylog中了,SQL线程"慢点"运行
一般企业建议3-6小时,具体看公司运维人员对于故障的反应时间
mysql>stop slave;
mysql>CHANGE MASTER TO MASTER_DELAY = 300;
mysql>start slave;
mysql> show slave status \G
SQL_Delay: 300
SQL_Remaining_Delay: NULL
延时从库应用
#故障恢复思路
1主1从,从库延时5分钟,主库误删除1个库
1. 5分钟之内 侦测到误删除操作
2. 停从库SQL线程
3. 截取relaylog
起点 :停止SQL线程时,relay最后应用位置
终点:误删除之前的position(GTID)
4. 恢复截取的日志到从库
5. 从库身份解除,替代主库工作
故障模拟及恢复
1.主库数据操作
mysql> create database relay charset utf8;
mysql> use relay
mysql> create table t1 (id int);
mysql> insert into t1 values(1),(2);
mysql> drop database relay;
2. 停止从库SQL线程
#mysql> show slave status \G 进程停止前从库同步时间
SQL_Delay: 300
SQL_Remaining_Delay: 214
stop slave sql_thread;
#进程停止后从库同步时间
SQL_Delay: 300
SQL_Remaining_Delay: NULL
3. 找relaylog的截取起点和终点
起点:#mysql> show slave status \G 找到以下两个参数,标识已经执行过的,往后是需要我们手动执行的
Relay_Log_File: wutonglinaliyun-relay-bin.000002
Relay_Log_Pos: 320
终点:
mysql> show relaylog events in 'wutonglinaliyun-relay-bin.000002';
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info | 主库binlog posid
| wutonglinaliyun-relay-bin.000002 | 4 | Format_desc | 8 | 123 | Server ver: 5.7.37-log, Binlog ver: 4 |
| wutonglinaliyun-relay-bin.000002 | 123 | Previous_gtids | 8 | 154 | |
| wutonglinaliyun-relay-bin.000002 | 154 | Rotate | 7 | 0 | mysql_bin.000001;pos=449 |
| wutonglinaliyun-relay-bin.000002 | 201 | Format_desc | 7 | 0 | Server ver: 5.7.37-log, Binlog ver: 4 |
| wutonglinaliyun-relay-bin.000002 | 320 | Gtid | 7 | 514 | SET @@SESSION.GTID_NEXT= 'ad5fa82d-8f07-11ec-8d35-00163e0e6664:2' |
| wutonglinaliyun-relay-bin.000002 | 385 | Query | 7 | 624 | create database relay charset utf8 |
| wutonglinaliyun-relay-bin.000002 | 495 | Gtid