码迷,mamicode.com
首页 > 数据库 > 详细

MySQL之七---Mysql实现数据库主从复制、主主复制、级联复制、半同步复制及复制监控

时间:2021-03-04 13:19:58      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:核心   completed   maria   pass   基于   主从切换   got   semi sync   like   

MySQL复制

(1)扩展方式: Scale Up ,Scale Out

(2)MySQL的扩展

 读写分离
 复制:每个节点都有相同的数据集
 向外扩展
 二进制日志
 单向

(3)复制的功用:

 数据分布
 负载均衡读
 备份
 高可用和故障切换
 MySQL升级测试

一主多从  

技术图片

 

主从复制介绍

两台或两台以上实例,通过binlog实现最终数据同步关系;

主从复制前提(搭建过程)

 a.至少两台MySQL实例,server_id,server_uuid不同;
 b.主库要开binlog
 c.专用的复制用户和权限
 d.预同步主库数据到从库
 e.告诉从库连接\同步起点
 f.启动复制线程

主从复制搭建(Classic replication)

配置主库

  1. 安装 mysql 8.0.20 二进制包

  2. 配置二进制文件路径,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
  1. 重启MySQL

 systemctl restart mysqld
  1. 验证二进制日志,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‘;
  1. 创建复制专用用户并授权

 create user repl@‘10.0.0.%‘ identified with mysql_native_password by  ‘123‘;
 grant replication slave on *.* to repl@‘10.0.0.%‘;
  1. 创建给予端用户并授权

 CREATE USER ‘donor_clone_user‘@‘%‘ IDENTIFIED BY ‘123‘;
 GRANT BACKUP_ADMIN on *.* to ‘donor_clone_user‘@‘%‘;
  1. 查看主状态

 show master status;

配置从库

  1. 安装 mysql 8.0.20 二进制包

  2. 配置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
  1. 重启MySQL

 systemctl restart mysqld
  1. 验证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‘;
  1. 创建接受端用户并授权

 CREATE USER ‘recipient_clone_user‘@‘%‘ IDENTIFIED BY ‘123‘;
 GRANT CLONE_ADMIN on *.* to ‘recipient_clone_user‘@‘%‘;
  1. 设置主库IP:端口加入给予主机列表

SET GLOBAL clone_valid_donor_list=‘10.0.0.51:3306‘;
  1. 使用克隆用户连接新数据库

 mysql -urecipient_clone_user -p1 -h10.0.0.61
  1. 执行远程克隆

 CLONE INSTANCE FROM ‘donor_clone_user‘@‘10.0.0.51‘:3306 IDENTIFIED BY ‘123‘;
  1. 克隆完成,新数据库自动重启

  2. 使用root用户连接新数据库

 mysql -uroot -p123
  1. 查看克隆状态信息

 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)
  1. 告诉从库连接信息,从什么位置点开始自动复制(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_FILEMASTER_LOG_POS必须和主库中show master status;查到的一致

  1. 启动复制线程

 start slave;
  1. 查看从状态

 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)原理描述:异步复制

  1. 从库执行 change master to ... 时,将主库连接信息和binlog位置信息写入master.info文件或者slave_master_info表中

  2. 从库执行 start slave 时,从库启动IO线程和SQL线程

  3. IO线程读取master.info,获取主库信息连接主库

  4. 主库会生成一个DUMP线程(自动监控binlog变化),来响应从库

  5. IO线程根据master.info记录的binlog文件名和position号,请求主库DUMP最新日志

  6. DUMP线程检查主库的binlog日志,如果有新的,传送给从从库的IO线程,主库不关心投递的结果(异步)。

  7. IO线程将收到的日志存储到了TCP/IP 缓存

  8. IO线程将缓存中的数据,存储到relay-log日志文件,更新master.info文件或者slave_master_info表的binlog 文件名和postion,IO线程工作完成

  9. SQL线程读取relay-log.info文件或者slave_relay_log_info表,获取到上次执行到的db02-relay-bin的位置,作为起点,回放db02-relay-bin

  10. SQL线程回放完成之后,会更新relay-log.info文件。

  11. 回放过的db02-relay-binrelay_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.

SQL 线程

正常状态:

 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‘

解决方案:

  1. 以主库为准

    1. 冲突操作回退回去

    2. 从库跳过错误

      1. pt-checksum/pt-sync

      2. 从库跳过指定错误代码

       vim /etc/my.cnf
       [mysqld]
       slave-skip-errors = 1032,1062,1007
       常见错误代码:
       1007: 对象已存在
       1032: 无法执行DML
       1062: 主键冲突,或约束冲突
      1. 将同步指针向下移动一个,如果多次不同步,可以重复操作。

       stop slave;
       set global sql_slave_skip_counter=1;
       start slave;
    3. 删除从库中有冲突的数据,有风险

    4. 最安全的做法就是重新构建主从

  2. 从库配置只读

 show variables like ‘%read_only%‘;
 select @@read_only;
 select @@super_read_only;
?
 -- 普通用户只读
 set @@read_only=1;
 -- 管理员用户只读
 set @@super_read_only=1;
  1. 双主结构,屏蔽多写

  2. 加中间件,读写分离。

主从延时故障分析和处理

主从延时:主库做的操作,从库很久才做。

主从延时带来的延伸问题:

  • 读写分离架构,依赖主从环境。主库作为写节点,从库作为读节点。要是过高,导致读的不及时。

  • 高可用架构,依赖主从环境。主库宕机,故障切换时,可能会丢失较多数据。


监控

时间差,主从延时的秒数(非人为)

 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

对比主从日志执行位置点,可以找到故障操作点,计算延时日志量


外在原因

  • 主从硬件差异

  • 主从版本差异

  • 网络问题:延时、阻塞、攻击

  • 资源耗尽

    • 大事务(尽量切割)大事务拆成多个小事务,可以有效的减少主从延时。5.7 并行事务

    • 全表扫描

    • 存储过程

    • DDL阻塞

    • ...

  • 其他原因

    • 过度追求安全:从库关闭“双一”

    • 锁冲突:RR隔离级别,锁冲突严重;调整为RC隔离级别,保证索引主从一致


主库原因

产生场景:

  1. 主库并发大量事务

  2. 从库个数多

binlog_dump 线程以事件为单元,串行传输二进制日志给从库IO,串行阻塞后续的事务(5.6 5.5),导致主从延时。


解决方案:

  • 5.6 版本:开启GTID,实现GC(group commit)机制,将多个事务redo log的刷盘动作合并,减少磁盘顺序写,提高性能。

     技术图片

     

     5.7 版本:不开启GTID,也会自动维护匿名的GTID,也能实现GC,建议开启GTID

从库原因

产生场景:

主库并发大量事务,从库默认只有一个SQL线程,串行回放relay-log中的事务,阻塞后续的事务运行,导致主从延时。


解决方案:

  1. 5.6 版本:开启GTID,加入SQL多线程的特性,但是只能针对不同库(database)下的事务进行并发回放。

  2. 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

更改复制过滤器语句


Database-Level Replication 流程图

注意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;

故障恢复操作:

  1. 5分钟之内,侦测到误删除操作

  2. 从库停止SQL线程:

     stop slave SQL_THREAD;
    
  3. 从库查找截取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 */   
                      |
  4. 从库截取relaylog

     mysqlbinlog --start-position=321 --stop-position=988 /data/3306/data/db02-relay-bin.000002 > /tmp/relay.sql
    
  5. 从库确认截取文件

     tail -10 /tmp/relay.sql
    
  6. 从库恢复截取的日志

     source /tmp/relay.sql
    
  7. 从库身份解除,替代主库工作

     stop slave;
     reset slave all;
    
  8. 业务改用从库


故障恢复思路二

  1. 5分钟之内,侦测到误删除操作

  2. 从库停止SQL线程:

     stop slave SQL_THREAD;
    
  3. 关闭延迟从库

     CHANGE MASTER TO MASTER_DELAY = 0;
    
  4. 从库查询误删除之前的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 */     
                  |
  5. 从库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";
    
  6. 从库身份解除,替代主库工作

     stop slave;
     reset slave all;
    
  7. 业务改用从库


半同步复制

从 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 commitafter sync


半同步复制工作原理的变化

  1. 主库执行新的事务,commit时阻塞

  2. 更新 show master status 信息,触发一个信号给 binlog dump

  3. binlog dump 通知从库日志更新了

  4. 从库IO线程请求新的二进制日志事件

  5. 主库通过binlog dump线程,传送新的二进制日志事件,给从库IO线程

  6. 从库IO线程接收到binlog,当日志写入到磁盘上的relaylog文件时,给主库ACK_receiver线程响应

  7. ACK_receiver 线程触发一个事件,告诉主库commit可以成功了

  8. 如果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 复制

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日志。


GTID核心参数

 [mysqld]
 gtid-mode=on                        --启用gtid类型,否则就是普通的复制架构
 enforce-gtid-consistency=true       --强制GTID的一致性
 log-slave-updates=1                 --slave更新是否记入日志
 

GTID 复制一主两从搭建

配置主库(db01)

  1. 安装 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
  1. 配置文件

 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
 
  1. 初始化数据,加入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
  1. 创建复制专用用户并授权

 create user repl@‘10.0.0.%‘ identified with mysql_native_password by  ‘123‘;
 grant replication slave on *.* to repl@‘10.0.0.%‘;
  1. 查看主状态

 show master status;

配置从库(db02 db03)

  1. 安装 mysql 8.0.20 二进制包

  2. 配置文件

 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

 

  1. 初始化数据,加入systemctl服务管理,启动并开机自启

  2. 配置主库连接信息(help change master to

 CHANGE MASTER TO
   MASTER_HOST=‘10.0.0.51‘,
   MASTER_USER=‘repl‘,
   MASTER_PASSWORD=‘123‘,
   MASTER_AUTO_POSITION=1;
  1. 启动复制线程

 start slave;
  1. 查看从状态

 show slave status \G

GTID 从库误写入操作处理

查看监控信息:

 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‘;

GTID 复制和普通复制的区别

 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;
  1. 在主从复制环境中,主库发生过的事务,在全局都是由唯一GTID记录的,更方便Failover

  2. 额外功能参数(3个)

  3. change master to ... 时,不需要binlog文件名和position号,启用自动即可MASTER_AUTO_POSITION=1;

  4. 在复制过程中,从库不再依赖master.info文件,而是直接读取最后一个relaylog的GTID号

  5. 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)。简单的说,多源复制就是将多个主库同步到一个从库,从而增加从的利用率,节省了机器。

技术图片

 

 

应用场景:

  1. 数据分析部门会需要各个业务部门的部分数据做数据分析,这个时候就可以使用到多源复制把各个主数据库的数据复制到统一的数据库中。报表系统

  2. 在从服务器进行数据的汇总,如果我们的主服务器进行了分库分表的操作,为了实现后期的一些数据的统计功能,往往要把数据汇总在一起在进行统计。OLAP(在线分析处理)

  3. 在从服务器对所有主服务器的数据进行备份。


 [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命令行提示符

GTID 两主一从 多源复制

  1. 修改配置文件

 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

 

  1. 重启mysql服务

 systemctl restart mysql
  1. 清除原来主从关系(db02 db03)

 stop slave;
 reset slave all;
  1. 多源复制从库配置主库信息(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‘;
  1. 多源复制从库监控

 -- 查看单一信道的复制的详细状态
 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;
  1. 多源复制配置过滤

 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) 均把对方指定为主节点,并启动复制线程

实验:主主复制

主1:db01配置

 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    |
 +----+------+

主2:db02配置

 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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!