标签:核心 completed maria pass 基于 主从切换 got semi sync like
(1)扩展方式: Scale Up ,Scale Out
(2)MySQL的扩展
读写分离
复制:每个节点都有相同的数据集
向外扩展
二进制日志
单向
(3)复制的功用:
数据分布
负载均衡读
备份
高可用和故障切换
MySQL升级测试
两台或两台以上实例,通过binlog实现最终数据同步关系;
主从复制前提(搭建过程)
a.至少两台MySQL实例,server_id,server_uuid不同;
b.主库要开binlog
c.专用的复制用户和权限
d.预同步主库数据到从库
e.告诉从库连接\同步起点
f.启动复制线程
配置主库
安装 mysql 8.0.20 二进制包
配置二进制文件路径,server_id
cat > /etc/my.cnf <<EOF [mysqld] user=mysql basedir=/usr/local/mysql datadir=/data/3306/data port=3306 socket=/tmp/mysql.sock server_id=10 log_bin=/data/3306/data/binlog plugin-load-add=mysql_clone.so clone=FORCE_PLUS_PERMANENT [client] socket=/tmp/mysql.sock EOF
重启MySQL
systemctl restart mysqld
验证二进制日志,clone插件是否开启,server_id,server_uuid是否和从库不同
select @@log_bin; select @@log_bin_basename; select @@server_id; select @@server_uuid; SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE ‘clone‘;
创建复制专用用户并授权
create user repl@‘10.0.0.%‘ identified with mysql_native_password by ‘123‘; grant replication slave on *.* to repl@‘10.0.0.%‘;
创建给予端用户并授权
CREATE USER ‘donor_clone_user‘@‘%‘ IDENTIFIED BY ‘123‘; GRANT BACKUP_ADMIN on *.* to ‘donor_clone_user‘@‘%‘;
查看主状态
show master status;
配置从库
安装 mysql 8.0.20 二进制包
配置server_id和主库不同
cat > /etc/my.cnf <<EOF [mysqld] user=mysql basedir=/usr/local/mysql datadir=/data/3306/data port=3306 socket=/tmp/mysql.sock server_id=20 log_bin=/data/3306/data/binlog plugin-load-add=mysql_clone.so clone=FORCE_PLUS_PERMANENT [client] socket=/tmp/mysql.sock EOF
重启MySQL
systemctl restart mysqld
验证server_id,server_uuid是否和从库不同,clone插件是否开启
select @@server_id; select @@server_uuid; SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE ‘clone‘;
创建接受端用户并授权
CREATE USER ‘recipient_clone_user‘@‘%‘ IDENTIFIED BY ‘123‘; GRANT CLONE_ADMIN on *.* to ‘recipient_clone_user‘@‘%‘;
设置主库IP:端口加入给予主机列表
SET GLOBAL clone_valid_donor_list=‘10.0.0.51:3306‘;
使用克隆用户连接新数据库
mysql -urecipient_clone_user -p1 -h10.0.0.61
执行远程克隆
CLONE INSTANCE FROM ‘donor_clone_user‘@‘10.0.0.51‘:3306 IDENTIFIED BY ‘123‘;
克隆完成,新数据库自动重启
使用root用户连接新数据库
mysql -uroot -p123
查看克隆状态信息
mysql> select * from performance_schema.clone_status\G *************************** 1. row *************************** ID: 1 PID: 0 STATE: Completed BEGIN_TIME: 2020-11-18 10:22:39.531 END_TIME: 2020-11-18 10:22:46.824 SOURCE: 10.0.0.51:3306 DESTINATION: LOCAL INSTANCE ERROR_NO: 0 ERROR_MESSAGE: BINLOG_FILE: binlog.000021 BINLOG_POSITION: 276 GTID_EXECUTED: 1aa38bc6-1cbc-11eb-a6b8-000c29caebef:1-9, c985eb8e-2896-11eb-a6af-000c29caebef:1-3, d1d0b198-2899-11eb-babe-000c29caebef:1-4 1 row in set (0.01 sec)
告诉从库连接信息,从什么位置点开始自动复制(help change master to
)
CHANGE MASTER TO MASTER_HOST=‘10.0.0.51‘, MASTER_USER=‘repl‘, MASTER_PASSWORD=‘123‘, MASTER_PORT=3306, MASTER_LOG_FILE=‘binlog.000021‘, MASTER_LOG_POS=276, MASTER_CONNECT_RETRY=10;
注意:
MASTER_LOG_FILE
和MASTER_LOG_POS
必须和主库中show master status;
查到的一致
启动复制线程
start slave;
查看从状态
show slave status \G
主从复制原理
# 主库: binlog 二进制日志 # 从库 relaylog:中继日志,从库用来临时存储接收到的binlog master.info:主库相关信息(ip port user password 已经获取的binlog 位置点) relay-log.info:存储SQL线程回放过的日志 三线程四文件(主库一个文件,从库三个文件。主库一个线程,从库两个线程)
主节点:
dump Thread:为每个Slave的I/O Thread启动一个dump线程,用于向其发送binary log events
从节点:
I/O Thread:向Master请求二进制日志事件,并保存于中继日志中
SQL Thread:从中继日志中读取日志事件,在本地完成重放
主从复制特点:
异步复制
主从数据不一致比较常见
复制架构:
Master/Slave, Master/Master, 环状复制 一主多从 从服务器还可以再有从服务器 一从多主:适用于多个不同数据库 主主
复制需要考虑二进制日志事件记录格式
STATEMENT(5.0之前)
ROW(5.1之后,推荐)
MIXED
主从复制(Classic Replication)原理描述:异步复制
从库执行 change master to ...
时,将主库连接信息和binlog位置信息写入master.info
文件或者slave_master_info
表中
从库执行 start slave
时,从库启动IO线程和SQL线程
IO线程读取master.info
,获取主库信息连接主库
主库会生成一个DUMP
线程(自动监控binlog
变化),来响应从库
IO线程根据master.info
记录的binlog
文件名和position
号,请求主库DUMP
最新日志
DUMP线程检查主库的binlog
日志,如果有新的,传送给从从库的IO线程,主库不关心投递的结果(异步)。
IO线程将收到的日志存储到了TCP/IP 缓存
IO线程将缓存中的数据,存储到relay-log日志文件,更新master.info
文件或者slave_master_info
表的binlog
文件名和postion
,IO线程工作完成
SQL线程读取relay-log.info
文件或者slave_relay_log_info
表,获取到上次执行到的db02-relay-bin
的位置,作为起点,回放db02-relay-bin
SQL线程回放完成之后,会更新relay-log.info
文件。
回放过的db02-relay-bin
,relay_log_purge
线程会定期删除这些日志。
注意:主库一旦有新的日志生成,dump 会发送“信号”给从库 ,IO线程再去请求
https://mariadb.com/kb/en/library/setting-up-replication/ https://dev.mysql.com/doc/refman/5.5/en/replication-configuration.html
常见报错场景:
通信故障:
外部网络问题(防火墙,网络不通,...)
连接信息问题(ip\port\user\passwd)
用户错误
密码错误
-- 报错信息:
Slave_IO_Running: Connecting Last_IO_Errno: 1045 Last_IO_Error: error connecting to master ‘repl1@10.0.0.51:3306‘ - retry-time: 10 retries: 2 message: Access denied for user ‘repl1‘@‘10.0.0.61‘ (using password: YES) -- 连接测试:
[root@db01 ~]# mysql -urepl -p123333 -h 10.0.0.51 -P 3306 mysql: [Warning] Using a password on the command line interface can be insecure. ERROR 1045 (28000): Access denied for user ‘repl‘@‘10.0.0.61‘ (using password: YES)
-- 处理方法:
stop slave; reset slave all; change master to ... ; start slave; show slave status \G
地址错误
Slave_IO_Running: Connecting Last_IO_Errno: 0 Last_IO_Error:
端口错误
-- 报错信息:
Slave_IO_Running: Connecting Last_IO_Errno: 2003 Last_IO_Error: error connecting to master ‘repl@10.0.0.51:3307‘ - retry-time: 10 retries: 1 message: Can‘t connect to MySQL server on ‘10.0.0.51‘ (111) -- 连接测试:
[root@db01 opt]# mysql -urepl -p123333 -h 10.0.0.51 -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.51‘ (111)
禁止域名解析:skip_name_resolve
达到最大连接数上限
-- 报错信息:
Last_IO_Errno: 1040
Last_IO_Error: error reconnecting to master ‘repl@10.0.0.51:3307‘ - retry-time: 10 retries: 7
-- 连接测试:
[root@db01 ~]# mysql -urepl -p123 -h 10.0.0.51 -P 3307
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1040 (HY000): Too many connections
-- 处理方法:
set global max_connections=1024;
请求二进制日志故障:
主库二进制日志文件名错误或缺失
Slave_IO_Running: No Last_IO_Errno: 13114 Last_IO_Error: Got fatal error 1236 from master when reading data from binary log:
‘Could not find first log file name in binary log index file‘
主库二进制日志文件位置点错误
Slave_IO_Running: No Last_IO_Errno: 13114 Last_IO_Error: Got fatal error 1236 from master when reading data from binary log:
‘binlog truncated in the middle of event; consider out of disk space on master; the first event ‘binlog.000021‘ at 156, the last event read from ‘/data/3306/data/binlog.000021‘ at 125,
the last byte read from ‘/data/3306/data/binlog.000021‘ at 276.‘
注意: 在主从复制中,禁止主库
reset master;
。可以选择expire
进行定期清理主库二进制日志
server_id
重复
Last_IO_Errno: 13117 Last_IO_Error: Fatal error: The slave I/O thread stops because master and slave have equal MySQL server ids; these ids must be different for replication to work (or the --replicate-same-server-id
option must be used on slave but this does not always make sense; please check the manual before using it).
server_uuid
重复
Last_IO_Errno: 1593 Last_IO_Error: Fatal error: The slave I/O thread stops because master and slave have equal MySQL server UUIDs;
these UUIDs must be different for replication to work.
正常状态:
Slave_SQL_Running: Yes Last_SQL_Errno: 0 Last_SQL_Error:
故障状态:
Slave_SQL_Running: NO Last_SQL_Errno: 故障代码 Last_SQL_Error: 故障信息
故障原因分析:
SQL线程功能:回放relay-log.info
,执行里面的SQL语句。
故障现象
relay-log
损坏,断节,找不到
接收到的SQL无法执行
要创建的对象,已经存在
要删除或修改的对象不存在
约束冲突,DML语句不符合表定义及约束
版本差异,参数设定不同,比如:数据类型的差异,SQL_MODE影响
故障原因
chang master to ...
指定的binlog
位置点不对
从库被写入
业务繁忙时,从库宕机了
主从切换时,没有正确操作(锁定原主库+binlog写入)
双主结构,没有正确使用
Last_SQL_Error: Error ‘Can‘t create database ‘db‘; database exists‘ on query. Default database: ‘db‘. Query: ‘create database db‘
解决方案:
以主库为准
冲突操作回退回去
从库跳过错误
pt-checksum
/pt-sync
从库跳过指定错误代码
vim /etc/my.cnf
[mysqld]
slave-skip-errors = 1032,1062,1007
常见错误代码:
1007: 对象已存在
1032: 无法执行DML
1062: 主键冲突,或约束冲突
将同步指针向下移动一个,如果多次不同步,可以重复操作。
stop slave;
set global sql_slave_skip_counter=1;
start slave;
删除从库中有冲突的数据,有风险
最安全的做法就是重新构建主从
从库配置只读
show variables like ‘%read_only%‘;
select @@read_only;
select @@super_read_only;
?
-- 普通用户只读
set @@read_only=1;
-- 管理员用户只读
set @@super_read_only=1;
双主结构,屏蔽多写
加中间件,读写分离。
主从延时:主库做的操作,从库很久才做。
主从延时带来的延伸问题:
读写分离架构,依赖主从环境。主库作为写节点,从库作为读节点。要是过高,导致读的不及时。
高可用架构,依赖主从环境。主库宕机,故障切换时,可能会丢失较多数据。
时间差,主从延时的秒数(非人为)
Seconds_Behind_Master: 0
主库日志执行位置点
Master_Log_File: mysql-bin.000005 Read_Master_Log_Pos: 444
从库日志执行位置点
Relay_Log_File: db01-relay-bin.000002 Relay_Log_Pos: 485
对比主从日志执行位置点,可以找到故障操作点,计算延时日志量
主从硬件差异
主从版本差异
网络问题:延时、阻塞、攻击
资源耗尽
大事务(尽量切割)大事务拆成多个小事务,可以有效的减少主从延时。
全表扫描
存储过程
DDL阻塞
...
其他原因
过度追求安全:从库关闭“双一”
锁冲突:RR隔离级别,锁冲突严重;调整为RC隔离级别,保证索引主从一致
产生场景:
主库并发大量事务
从库个数多
binlog_dump 线程以事件为单元,串行传输二进制日志给从库IO,串行阻塞后续的事务(5.6 5.5),导致主从延时。
解决方案:
5.6 版本:开启GTID,实现GC(
5.7 版本:不开启GTID,也会自动维护匿名的GTID,也能实现GC,建议开启GTID
产生场景:
主库并发大量事务,从库默认只有一个SQL线程,串行回放relay-log中的事务,阻塞后续的事务运行,导致主从延时。
解决方案:
5.6 版本:开启GTID,加入SQL多线程的特性,但是只能针对不同库(database)下的事务进行并发回放。
5.7 版本:开始GTID,加入MTS(enhanced multi-threaded slave
)技术,基于logical_clock
(逻辑时钟)机制,binlog
加入了seq_no
机制,真正实现了基于事务级别的并发回放。
产生情景:
需求:master 有4个库A,B,C ,D,现在需要将其中2个库B,C单独拆分出来。
做法:单独搭建一个只有B,C库的实例,然后只复制master的B,C库,过滤掉A,D库。
show master status;
# 使用白名单或黑名单控制二进制日志是否记录,不常用
Binlog_Do_DB # 白名单,出现的记录
Binlog_Ignore_DB # 黑名单,出现的不记录
show slave status\G
# 在SQL线程回放流程中,加入过滤功能:库,表,通配符表的白名单和黑名单
# 白名单:只执行白名单中列出的库或者表的中继日志
# 黑名单:不执行黑名单中列出的库或者表的中继日志
Replicate_Do_DB Replicate_Ignore_DB Replicate_Do_Table Replicate_Ignore_Table Replicate_Wild_Do_Table Replicate_Wild_Ignore_Table
在线配置:
stop slave SQL_THREAD; change replication filter Replicate_Do_Table=(test.t1,test.t2); start slave sql_thread;
永久配置:
vim /etc/my.cnf [mysqld] replicate_do_table=test.t1 replicate_do_table=test.t2
注意1:库级别的规则,只针对
binlog_format=‘STATEMENT or MIXED‘
注意2:binlog_format=‘ROW’
,不受库级别规则限制,只受表级别规则限制。
注意: 以下总结和测试,前提都是
binlog-format=‘MIXED‘
DB level:
binlog-format=statement
时,过滤以use DB为主(不允许跨库)
binlog-format=row
时:过滤不以use DB为主(允许跨库)
binlog-format=statement or row
,table level 的判断都是不以use DB为主(可以跨库的)
总的流程走向:
先判断 DB-level,如果 DB-level 判断完成后需要 exit,则退出。
如果 DB-level 判断完成后,没有 exit,则再判断Table-level。
DB-level:
如果有 replicate-do-db,则判断 replicate-do-db,将不会走到 replicate-ignore-db 这层。
如果判断 replicate-do-db 符合条件,则判断 table-level。 如果不符合,则exit。
如果没有 replicate-do-db,但是有 replicate-ignore-db 。
如果判断符合replicate-ignore-db规则,则exit。不符合,则走到 table-level 层继续判断。
Table-level:
判断逻辑顺序自上而下为:replicate-do-table -> replicate-ignore-table -> replicate-wild-do-table -> replicate-wild-ignore-table
从第一个阶段(replicate-do-table)开始,如果符合replicate-do-table判断规则,则exit。
如果不符合,则跳到下一层(replicate-ignore-table)。
以此类推,直到最后一层(replicate-wild-ignore-table)都不符合,则最后判断是否有(replicate-do-table or replicate-wild-do-table),如果有,则 ignore & exit。如果没有,则execute & exit
说明:以下测试,均以statement格式为例。 rows模式参见原理同样可以证明。
设置replicate_do_DB=A,B
结论:A和B都没有在slave上执行。因为mysql将‘A,B‘作为一个库名。
只有库级别的规则
do-db
replicate_do_DB=A replicate_do_DB=B
ignoare-db
replicate_ignore_DB=A replicate_ignore_DB=B
do-db & ignore-db
replicate_do_DB=A replicate_do_DB=B replicate-ignore-db=mysql replicate-ignore-db=test
只有表级别的规则
do-table
ignore-table
wild-do-table
wild-ignore-table
do-table & ignore-table
do-table & wild-ignore-table
wild-do-table & wild-ignore-table
库和表级别的规则混用
do-DB & do-table
replicate_do_DB=A replicate_do_DB=B replicate-do-table=table1 replicate-do-table=table2
do-DB & wild-do-table
replicate_do_DB=A replicate_do_DB=B replicate-wild-do-table=mysql.% replicate-wild-do-table=test.%
do-DB & ignore-table
replicate_do_DB=A replicate_do_DB=B replicate-ignore-table=table1 replicate-ignore-table=table2
do-DB & wild-ignore-table
replicate_do_DB=A replicate_do_DB=B replicate-wild-ignore-table=mysql.% replicate-wild-ignore-table=test.%
最常见场景: db-db & do-ignore-db & wild-do-table & wild-ignore-table
常见场景:将master上的A,B库 拆分到 新的一组机器上。
特点:
1) slave 不复制 master 的 mysql,test 库
2) slave 只复制 master 的 A,B 库所有操作
?
replicate-ignore-db=mysql
replicate-ignore-db=test
replicate-wild-ignore-table=mysql.%
replicate-wild-ignore-table=test.%
replicate_do_DB=A
replicate_do_DB=B
replicate-wild-do-table=A.%
replicate-wild-do-table=B.%
误区:
1) 如果我的 default database 不是A或者B,那么接下来的操作就不会被slave 执行,然后悲剧就产生了。
master> use C;insert into A.id values(1);
2)所以,以上cnf配置,只适合 default database 是 A,B 的情况。
?
如果要完成这种需求,应该这样配置[前提:开发没有权限登陆到mysql,test库]:
?
replicate-ignore-db=mysql replicate-ignore-db=test replicate-wild-ignore-table=mysql.% replicate-wild-ignore-table=test.% replicate-wild-do-table=A.% replicate-wild-do-table=B.%
实战: wild-do-table & ignore-table & wild-ignore-table
需求: 将老服务器上的某个库,迁移到新机器上
old_master[库: A , B , mysql] ---->(同步) new_maser[A]
验证单库(A)复制的正确性: 规则=> slave 只复制A库,不复制B库
Replicate_Wild_Do_Table: A.% Replicate_Ignore_DB: mysql Replicate_Wild_Ignore_Table: mysql.% a)use A/B; insert A.a select B.b from B ; --err:同步报错,slave没有B库的内容 b) use A/B; insert A.a select B.b from A,B where A.b=B.b; --err:同步报错,slave没有B库的内容 c) use mysql; insert into A.a values(‘a‘); --err: 同步不报错,但是老master的binlog没有在slave执行,因为Replicate_Ignore_DB: mysql,Replicate_Wild_Ignore_Table: mysql.% d) use 空库; insert into A.a values(‘a‘); --ok: 可以同步复制下来 e) use B; insert into A.a values(‘a‘); --ok: 可以同步复制下来
产生情景:
需求:主从复制非常擅长解决物理损坏,但是没办法处理逻辑损坏,例如主库有个误删除写入的操作,正常情况下从库也会同步这个错误,怎么能避免这个情况?
做法:建立延时从库,delay(延时)从节点同步数据。可以处理逻辑损坏,但只能做备用库。
原理:对SQL线程回放流程,进行延时设置。
建议:一般企业建议3-6小时,具体看公司运维人员对于故障的反应时间
查看延时时间
show slave status\G
# 延时时间,单位秒
SQL_Delay: 0
# 延时剩余时间,单位秒
SQL_Remaining_Delay: NULL
查看中继日志
show relaylog events in ‘db01-relay-bin.000002‘;
在线配置:
stop slave SQL_THREAD; change master to master_delay = 300; start slave sql_thread;
故障场景:一主一从,从库延时5分钟,主库误删1个库
故障模拟:主库操作
create database relay charset utf8; use relay; create table t1 (id int); insert into t1 values(1); commit; drop database relay;
故障恢复操作:
5分钟之内,侦测到误删除操作
从库停止SQL线程:
stop slave SQL_THREAD;
从库查找截取relaylog的起点和终点
起点:停止SQL线程时,relay最后应用的位置
mysql> show slave status\G ... ... Relay_Log_File: db02-relay-bin.000002 Relay_Log_Pos: 321 ... ...
终点:误删除之前的Position(GTID)
mysql> show relaylog events in ‘db02-relay-bin.000002‘;
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
... ...
| m01-relay-bin.000002 | 988 | Anonymous_Gtid | 1 | 1020 | SET @@SESSION.GTID_NEXT= ‘ANONYMOUS‘ |
| db01-relay-bin.000002 | 1065 | Query | 1 | 1127 | drop database relay /* xid=81 */
|
从库截取relaylog
mysqlbinlog --start-position=321 --stop-position=988 /data/3306/data/db02-relay-bin.000002 > /tmp/relay.sql
从库确认截取文件
tail -10 /tmp/relay.sql
从库恢复截取的日志
source /tmp/relay.sql
从库身份解除,替代主库工作
stop slave; reset slave all;
业务改用从库
5分钟之内,侦测到误删除操作
从库停止SQL线程:
stop slave SQL_THREAD;
关闭延迟从库
CHANGE MASTER TO MASTER_DELAY = 0;
从库查询误删除之前的Position(GTID)
mysql> show slave status\G
... ...
Relay_Log_File: db02-relay-bin.000002
... ...
mysql> show relaylog events in ‘db02-relay-bin.000002‘;
| Log_name | Pos | Event_type | Server_id | End_log_pos | Info |
... ...
| m01-relay-bin.000002 | 988 | Anonymous_Gtid | 1 | 1020 | SET @@SESSION.GTID_NEXT= ‘ANONYMOUS‘ |
| db01-relay-bin.000002 | 1065 | Query | 1 | 1127 | drop database relay /* xid=81 */
|
从库SQL线程自动回放,直到DROP操作之前。
binlog方式UNTIL
START SLAVE SQL_THREAD UNTIL RELAY_LOG_FILE = ‘db01-relay-bin.000002‘, RELAY_LOG_POS = 988 ;
GTID方式UNTIL
START SLAVE UNTIL SQL_BEFORE_GTIDS = "1aa38bc6-1cbc-11eb-a6b8-000c29caebef:4";
从库身份解除,替代主库工作
stop slave; reset slave all;
业务改用从库
从 MYSQL 5.5 开始,支持半同步复制(Semi synchronous Replication),一定程度上保证提交的事务已经传给了至少一个备库。解决主从数据不一致问题,提供一般一致性。可使用多从库提高ACK接收率。
之前版本的MySQL Replication都是异步(asynchronous)的,主库在执行完一些事务后,是不会管备库的进度的。如果备库不幸落后,而更不幸的是主库此时又出现Crash(例如宕机),这时备库中的数据就是不完整的。如果主库发生故障,此时我们无法使用备库来继续提供数据一致的服务了。
5.5 出现概念,但是不建议使用,性能太差 5.6 出现
group commit
组提交功能,来提升开启半同步复制的性能 5.7 更加完善了,在group commit
基础上出现了MGR
5.7 增强半同步复制的新特性:after commit
;after sync
;
主库执行新的事务,commit
时阻塞
更新 show master status
信息,触发一个信号给 binlog dump
binlog dump
通知从库日志更新了
从库IO线程请求新的二进制日志事件
主库通过binlog dump
线程,传送新的二进制日志事件,给从库IO线程
从库IO线程接收到binlog
,当日志写入到磁盘上的relaylog
文件时,给主库ACK_receiver
线程响应
ACK_receiver
线程触发一个事件,告诉主库commit
可以成功了
如果ACK_receiver
等待,达到了预设的超时时间还没有收到响应,半同步复制会切换为原始的异步复制
配置主库
在线配置:
# 查看是否有动态支持
show global variables like ‘have_dynamic_loading‘;
# 安装自带插件
INSTALL PLUGIN rpl_semi_sync_master SONAME‘semisync_master.so‘;
# 启动插件
SET GLOBAL rpl_semi_sync_master_enabled = 1;
# 设置超时时间
SET GLOBAL rpl_semi_sync_master_timeout = 1000;
永久配置:
vim /etc/my.cnf [mysqld] rpl_semi_sync_master_enabled=1 rpl_semi_sync_master_timeout=1000
查看运行状态
show status like ‘Rpl_semi_sync_master_status‘;
配置从库
在线配置:
# 安装自带插件
INSTALL PLUGIN rpl_semi_sync_master SONAME‘semisync_master.so‘;
# 启动插件
SET GLOBAL rpl_semi_sync_master_enabled = 1;
# 重启io线程使其生效
STOP SLAVE IO_THREAD; START SLAVE IO_THREAD;
永久配置:
vim /etc/my.cnf [mysqld] rpl_semi_sync_master_enabled=1
查看运行状态
show status like ‘Rpl_semi_sync_slave_status‘;
rpl_semi_sync_master_enabled =ON rpl_semi_sync_master_timeout =1000 rpl_semi_sync_master_trace_level =32 rpl_semi_sync_master_wait_for_slave_count =1 rpl_semi_sync_master_wait_no_slave =ON rpl_semi_sync_master_wait_point =AFTER_SYNC rpl_semi_sync_slave_enabled =ON rpl_semi_sync_slave_trace_level =32 ? binlog_group_commit_sync_delay =1 binlog_group_commit_sync_no_delay_count =1000
GTID(Global Transaction ID)是对于一个已提交事务的唯一编号,并且是一个全局(主从复制)唯一的编号。
GTID =server_uuid : transaction_id
7E11FA47-31CA-19E1-9E56-C43AA21293967:29
注意:
mysqldump
备份开启GTID
的数据库,不能加--set-gtid-purged=OFF
选项。SET @MYSQLDUMP_TEMP_LOG_BIN = @@SESSION.SQL_LOG_BIN;
SET @@SESSION.SQL_LOG_BIN= 0;
总结:
gtid事务和 Position都增加了;
加了--set-gtid-purged=OFF时,在会记录binlog日志,如果不加,不记录binlog日志。
[mysqld] gtid-mode=on --启用gtid类型,否则就是普通的复制架构 enforce-gtid-consistency=true --强制GTID的一致性 log-slave-updates=1 --slave更新是否记入日志
配置主库(db01)
安装 mysql 8.0.20 二进制包
tar xf mysql-8.0.20-linux-glibc2.12-x86_64.tar.xz ln -s /opt/mysql-8.0.20-linux-glibc2.12-x86_64 /usr/local/mysql yum remove mariadb-libs -y useradd -M -r mysql mkdir -p /data/3306/data && chown -R mysql. /data/ echo export PATH=\$PATH:/usr/local/mysql/bin/ >> /etc/profile && . /etc/profile
配置文件
cat > /etc/my.cnf <<EOF [mysqld] user=mysql basedir=/usr/local/mysql datadir=/data/3306/data port=3306 socket=/tmp/mysql.sock server_id=51 log_bin=/data/3306/mysql-bin secure-file-priv=/tmp binlog_format=row gtid-mode=on enforce-gtid-consistency=true log-slave-updates=1 [client] socket=/tmp/mysql.sock [mysql] prompt=db01 [\\d]> EOF
初始化数据,加入systemctl服务管理,启动并开机自启
mysqld --initialize-insecure --user=mysql --basedir=/usr/local/mysql --datadir=/data/3306/data cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld systemctl enable mysqld systemctl start mysqld
创建复制专用用户并授权
create user repl@‘10.0.0.%‘ identified with mysql_native_password by ‘123‘; grant replication slave on *.* to repl@‘10.0.0.%‘;
查看主状态
show master status;
配置从库(db02 db03)
安装 mysql 8.0.20 二进制包
配置文件
cat > /etc/my.cnf <<EOF [mysqld] user=mysql basedir=/usr/local/mysql datadir=/data/3306/data port=3306 socket=/tmp/mysql.sock server_id=52 log_bin=/data/3306/mysql-bin secure-file-priv=/tmp binlog_format=row gtid-mode=on enforce-gtid-consistency=true log-slave-updates=1 [client] socket=/tmp/mysql.sock [mysql] prompt=db02 [\\d]> EOF cat > /etc/my.cnf <<EOF [mysqld] user=mysql basedir=/usr/local/mysql datadir=/data/3306/data port=3306 socket=/tmp/mysql.sock server_id=53 log_bin=/data/3306/mysql-bin secure-file-priv=/tmp binlog_format=row gtid-mode=on enforce-gtid-consistency=true log-slave-updates=1 [client] socket=/tmp/mysql.sock [mysql] prompt=db03 [\\d]> EOF
初始化数据,加入systemctl服务管理,启动并开机自启
配置主库连接信息(help change master to
)
CHANGE MASTER TO MASTER_HOST=‘10.0.0.51‘, MASTER_USER=‘repl‘, MASTER_PASSWORD=‘123‘, MASTER_AUTO_POSITION=1;
启动复制线程
start slave;
查看从状态
show slave status \G
查看监控信息:
Last_SQL_Error: Error ‘Can‘t create database ‘oldboy‘; database exists‘ on query. Default database: ‘oldboy‘. Query: ‘create database oldboy‘ ? Retrieved_Gtid_Set: 71bfa52e-4aae-11e9-ab8c-000c293b577e:1-3 Executed_Gtid_Set: 71bfa52e-4aae-11e9-ab8c-000c293b577e:1-2,
跳过报错事务(GTID),注入空事务:
stop slave; set gtid_next=‘71bfa52e-4aae-11e9-ab8c-000c293b577e:3‘; begin;commit; set gtid_next=‘AUTOMATIC‘;
CHANGE MASTER TO MASTER_HOST=‘10.0.0.51‘, MASTER_USER=‘repl‘, MASTER_PASSWORD=‘123‘, MASTER_PORT=3306, MASTER_LOG_FILE=‘binlog.000001‘, MASTER_LOG_POS=444, MASTER_CONNECT_RETRY=10; ? CHANGE MASTER TO MASTER_HOST=‘10.0.0.51‘, MASTER_USER=‘repl‘, MASTER_PASSWORD=‘123‘, MASTER_AUTO_POSITION=1;
在主从复制环境中,主库发生过的事务,在全局都是由唯一GTID记录的,更方便Failover
额外功能参数(3个)
change master to ...
时,不需要binlog文件名和position号,启用自动即可MASTER_AUTO_POSITION=1
;
在复制过程中,从库不再依赖master.info
文件,而是直接读取最后一个relaylog的GTID号
mysqldump备份时,默认包含事务操作的GTID,以SET @@GLOBAL.GTID_PURGED=‘8c49d7ec-7e78-11e8-9638-000c29ca725d:1‘;
形式告诉从库,我的备份中已经有以上事务,你就不用运行了,直接从下一个GTID开始请求binlog就行。
MySQL 5.7 之前只能支持一主一从,一主多从或者多主多从的复制。如果想实现多主一从,只能使用mariadb,但是mariadb又与官方的mysql版本不兼容。
MySQL 5.7 开始支持多主一从也就是多源复制(multi-source)。简单的说,多源复制就是将多个主库同步到一个从库,从而增加从的利用率,节省了机器。
应用场景:
数据分析部门会需要各个业务部门的部分数据做数据分析,这个时候就可以使用到多源复制把各个主数据库的数据复制到统一的数据库中。报表系统
在从服务器进行数据的汇总,如果我们的主服务器进行了分库分表的操作,为了实现后期的一些数据的统计功能,往往要把数据汇总在一起在进行统计。OLAP(在线分析处理)
在从服务器对所有主服务器的数据进行备份。
[mysqld] slow_query_log=ON -- 启用慢查询 slow_query_log_file=/data/3306/data/db01-slow.log -- 慢查询日志保存路径 long_query_time=0.1 -- 慢查询记录执行超过0.1秒的查询 log_queries_not_using_indexes -- 记录预期将检索所有行的查询 master_info_repository=TABLE -- 存储 master_info 到表中,更安全 relay_log_info_repository=TABLE -- 存储 relay_log_info 到表中,更安全 [mysql] prompt=db01 [\\d]> -- mysql命令行提示符
修改配置文件
cat > /etc/my.cnf <<EOF [mysqld] user=mysql basedir=/usr/local/mysql datadir=/data/3306/data port=3306 socket=/tmp/mysql.sock server_id=1 log_bin=/data/binlog/mysql-bin secure-file-priv=/tmp binlog_format=row gtid-mode=on enforce-gtid-consistency=true log-slave-updates=1 innodb_flush_method=O_DIRECT slow_query_log=ON slow_query_log_file=/data/3306/data/db01-slow.log long_query_time=0.1 log_queries_not_using_indexes master_info_repository=TABLE relay_log_info_repository=TABLE [client] socket=/tmp/mysql.sock [mysql] prompt=db01 [\\d]> EOF cat > /etc/my.cnf <<EOF [mysqld] user=mysql basedir=/usr/local/mysql datadir=/data/3306/data port=3306 socket=/tmp/mysql.sock server_id=2 log_bin=/data/binlog/mysql-bin secure-file-priv=/tmp binlog_format=row gtid-mode=on enforce-gtid-consistency=true log-slave-updates=1 innodb_flush_method=O_DIRECT slow_query_log=ON slow_query_log_file=/data/3306/data/db01-slow.log long_query_time=0.1 log_queries_not_using_indexes master_info_repository=TABLE relay_log_info_repository=TABLE [client] socket=/tmp/mysql.sock [mysql] prompt=db02 [\\d]> EOF cat > /etc/my.cnf <<EOF [mysqld] user=mysql basedir=/usr/local/mysql datadir=/data/3306/data port=3306 socket=/tmp/mysql.sock server_id=3 log_bin=/data/binlog/mysql-bin secure-file-priv=/tmp binlog_format=row gtid-mode=on enforce-gtid-consistency=true log-slave-updates=1 innodb_flush_method=O_DIRECT slow_query_log=ON slow_query_log_file=/data/3306/data/db01-slow.log long_query_time=0.1 log_queries_not_using_indexes master_info_repository=TABLE relay_log_info_repository=TABLE [client] socket=/tmp/mysql.sock [mysql] prompt=db03 [\\d]> EOF
重启mysql服务
systemctl restart mysql
清除原来主从关系(db02 db03)
stop slave; reset slave all;
多源复制从库配置主库信息(db03)并启动
CHANGE MASTER TO MASTER_HOST=‘10.0.0.51‘,MASTER_USER=‘repl‘,
MASTER_PASSWORD=‘1‘, MASTER_AUTO_POSITION=1 FOR CHANNEL ‘Master_1‘; CHANGE MASTER TO MASTER_HOST=‘10.0.0.52‘,MASTER_USER=‘repl‘,
MASTER_PASSWORD=‘1‘, MASTER_AUTO_POSITION=1 FOR CHANNEL ‘Master_2‘; start slave for CHANNEL ‘Master_1‘; start slave for CHANNEL ‘Master_2‘;
多源复制从库监控
-- 查看单一信道的复制的详细状态
SHOW SLAVE STATUS FOR CHANNEL ‘Master_1‘\G SHOW SLAVE STATUS FOR CHANNEL ‘Master_2‘\G
-- 查看视图中复制配置,状态
use performance_schema; show tables like ‘%repl%‘; select * from performance_schema.replication_connection_configuration\G SELECT * FROM performance_schema.replication_connection_status WHERE CHANNEL_NAME=‘master_1‘\G
-- 查看所有复制信道的复制状态概况
select * from performance_schema.replication_applier_status_by_worker;
多源复制配置过滤
CHANGE REPLICATION FILTER REPLICATE_WILD_DO_TABLE = (‘db1.%‘) FOR CHANNEL "master_1"; CHANGE REPLICATION FILTER REPLICATE_WILD_DO_TABLE = (‘db2.%‘) FOR CHANNEL "master_2";
检查测试
-- 在主库(10.0.0.51)实例创建一些数据。
create database master1; use master1; CREATE TABLE `test1` (`id` int(11) DEFAULT NULL,`count` int(11) DEFAULT NULL); insert into test1 values(1,1);
-- 在主库(10.0.0.52)实例创建一些数据。
create database master2;
use master2;
CREATE TABLE `test2` (`id` int(11) DEFAULT NULL,`count` int(11) DEFAULT NULL);
insert into test2 values(1,1);
-- 在从库(10.0.0.53)实例检查数据是否成功复制。
select * from master1.test1; select * from master2.test2;
主主复制
主主复制:互为主从 (1)容易产生的问题:数据不一致;因此慎用 (2)考虑要点:自动增长id
配置一个节点使用奇数id
auto_increment_offset=1 开始点 auto_increment_increment=2 增长幅度
另一个节点使用偶数id
auto_increment_offset=2 auto_increment_increment=2
(1) 各节点使用一个惟一server_id
(2) 都启动binary log和relay log
(3) 创建拥有复制权限的用户账号
(4) 定义自动增长id字段的数值范围各为奇偶
(5) 均把对方指定为主节点,并启动复制线程
vim /etc/my.cnf [mysqld] server-id=1 binlog_format=ROW plugin-load-add=mysql_clone.so clone=FORCE_PLUS_PERMANENT auto_increment_offset=1 auto_increment_increment=2
重启db01机器mysql服务器
systemctl reatart mysqld mysql> select @@log_bin; mysql> select @@log_bin_basename; mysql> create user repl@‘10.0.0.%‘ identified with mysql_native_password by ‘123‘; mysql> grant replication slave on *.* to repl@‘10.0.0.%‘; 创建远程clone用户 # 捐赠者(source)授权 mysql> reset master; create user test_s@‘%‘ identified by ‘123‘; grant backup_admin on *.* to test_s@‘%‘; mysql > show databases; mysql > CHANGE MASTER TO mysql > start slave; 开启slave mysql > show slave status\G ? mysql> create table t1(id int auto_increment primary key,name char(10)); 创建表t1 Query OK, 0 rows affected (0.03 sec) mysql> insert t1(name)value(‘a‘); 插入a信息 Query OK, 1 row affected (0.01 sec) mysql> insert t1(name)value(‘b‘); 插入b信息 Query OK, 1 row affected (0.00 sec) mysql> select * from t1; +----+------+ | id | name | +----+------+ | 1 | a | | 3 | b | +----+------+
vim /etc/my.cnf [mysqld] server-id=2 binlog_format=ROW auto_increment_offset=2 auto_increment_increment=2 plugin-load-add=mysql_clone.so clone=FORCE_PLUS_PERMANENT
重启
systemctl restart mysqld SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE ‘clone‘;
# 接受者(target)授权
mysql> reset master;
create user test_t@‘%‘ identified by ‘123‘;
grant clone_admin on *.* to test_t@‘%‘;
远程clone(目标端)
# 开始克隆
SET GLOBAL clone_valid_donor_list=‘10.0.0.51:3306‘;
mysql -utest_t -p123 -h10.0.0.52 -P3306
CLONE INSTANCE FROM test_s@‘10.0.0.51‘:3306 IDENTIFIED BY ‘123‘;
==========================================================
f. 告诉从库连接信息,从什么位置点开始自动复制 change master to
mysql> select * from performance_schema.clone_status\G mysql> CHANGE MASTER TO MASTER_HOST=‘10.0.0.51‘, MASTER_USER=‘repl‘, MASTER_PASSWORD=‘123‘, MASTER_PORT=3306, MASTER_LOG_FILE=‘binlog.000001‘, MASTER_LOG_POS=156, MASTER_CONNECT_RETRY=10;
g. 启动专用复制线程 start slave;
mysql> start slave ;
mysql> show slave status \G;
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
mysql > show databases;
查看二进制日志情况
mysql > show master logs;
插入表
mysql > insert t1(name)value(‘a‘); 在B主机上插入a信息 Query OK, 1 row affected (0.01 sec) mysql > insert t1(name)value(‘b‘); 在B主机上插入b信息 Query OK, 1 row affected (0.00 sec) mysql > select * from t1; 查看此时未出现冲突情况,但是ID顺序会比较乱 +----+------+ | id | name | +----+------+ | 1 | a | | 3 | b | | 4 | a | | 6 | b | +----+------+
主-中间主(change master to)-从1(change master to中间主)-从2(change master to中间主)-从3(change master to中间主)
一主多从 主 ----从1(-change master to主)-从2-change master to主
MySQL之七---Mysql实现数据库主从复制、主主复制、级联复制、半同步复制及复制监控
标签:核心 completed maria pass 基于 主从切换 got semi sync like
原文地址:https://www.cnblogs.com/strugger-0316/p/14477144.html