MySQL day7 主从复制

一、前言

1.两台或以上数据库实例,通过二进制日志,实现数据的“同步”关系。
2.主从复制前提(搭建过程)

  • 1.需要2台以上实例,时间同步,网络通畅,Server_id不同,区分不同角色(主库,从库)
  • 2.主库开binlog,建立专用复制用户。
  • 3.从库需要提前 “补课”
  • 4.从库:主库的连接信息,确认复制起点
  • 5.从库:开启专用的复制线程

二、主从复制搭建

前提:
先创建实例 3307 3308 3309。详细看这个
7.多实例的应用

大致思路:
(12台MySQL,server_id不重复
(2)主库开启binlog,建用户
(3)全备份主库到从库
(4)通过change master to IP、Port、User、Password、复制起点。 在从库执行这些信息
(5)启动线程SQL,IO线程。  start slave;

1.检查关键信息
假设主库是3307,从库是3308、3309

mysql -S /tmp/mysql3307.sock -e "select @@server_id";

在这里插入图片描述

2.检查主库binlog

mysql -S /tmp/mysql3307.sock -e "select @@log_bin";

在这里插入图片描述
3.主库建立复制用户

mysql -S /tmp/mysql3307.sock -e "grant replication slave on *.* to [email protected]'192.168.93.%' identified by '123'";
mysql -S /tmp/mysql3307.sock -e "select user,host from mysql.user"

在这里插入图片描述
4.主库备份恢复到从库
创建全备

mysqldump -S /tmp/mysql3307.sock -A --master-data=2 --single-transaction > /tmp/all.sql

恢复到3308,3309内

mysql -S /tmp/mysql3308.sock </tmp/all.sql
mysql -S /tmp/mysql3308.sock </tmp/all.sql

5.告知从库复制信息

mysql> help change master to

CHANGE MASTER TO
  MASTER_HOST='192.168.93.146',
  MASTER_USER='repl',
  MASTER_PASSWORD='123',
  MASTER_PORT=3307,
  MASTER_LOG_FILE='mysql-bin.000001',
  MASTER_LOG_POS=448,
  MASTER_CONNECT_RETRY=10;

和上面参数对应
[root@localhost 3307]# grep "\-- CHANGE MASTER TO" /tmp/all.sql
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=448;

mysql -S /tmp/mysql3308.sock 登录到3308执行
在这里插入图片描述
同理,3309
在这里插入图片描述
6.在两个从库中开启专用复制线程

[root@localhost ~]# mysql -S /tmp/mysql3308.sock
mysql>start slave;

[root@localhost ~]# mysql -S /tmp/mysql3309.sock
mysql>start slave;

7.验证主从状态

mysql -S /tmp/mysql3308.sock -e "show slave status\G" | grep Running;
mysql -S /tmp/mysql3309.sock -e "show slave status\G" | grep Running;

在这里插入图片描述
在这里插入图片描述
如果搭建不成,可以重新来过。
出现Slave_IO_Running:NO还有一个原因是slave上没有权限读master上的数据。

清空主从环境
mysql -S /tmp/mysql3308.sock -e “stop slave;reset slave all;”
 

三、主从复制原理

把主库发生新的binlog截取后发到从库source
在这里插入图片描述
3.1 主从中涉及到的资源
文件

  • 主库:binlog文件
  • 从库:
relay-log文件
作用:存储接收的binlog
位置:默认从库的数据目录下 db01-relay-bin.000001

手工定义:mysql>show variables like '%relay%'
relay_log_basename=/data/3308/data/db01-relay-bin
master.info文件
作用:连接主库的信息,已经接收binlog位置点信息。
位置:默认存储在从库的数据路径下/data/3308/data/,

手工定义:mysql>show variables like '%master%'
master_info_repository = FILE/TABLE
relay-log.info
作用:记录从库回放到的relay-log的位置点
位置:默认在从库的数据路径下 

手工定义:mysql>show variables like '%relay%'
relay_log_info_repository=FILE/TABLE

3.2 线程
主库:
Binlog_dump_Thread:
作用:用来接收从库请求,并且投递binlog给从库。
在主库中:mysql>show processlist

从库:
IO线程:请求日志,接收日志
SQL线程:回放relay日志

3.3 原理图
在这里插入图片描述
文字说明:
1.slave:change master to IP,Port,USER,PASSWORD,binlog位置信息写入到master.info
2.slave:连接主库
3.Master:分配dump线程,专门和从库的IO线程通信。 show processlist;
4.slave:IO线程请求新日志
5.Master:dump线程接收请求,截取日志,返回给slave_IO
6.slave:IO线程接收到binlog,日志放在TCP/IP,此时网络层层面而返回ACK给主库
7.slave:IO将binlog最终写入到relaylog中,并更新master.info,IO线程工作结束
8.slave:SQL线程读取R.info,获取上次执行到的位置点
9.slave:SQL线程向后执行新的relay-log,再次更新R.info

小细节:
1.slave的relay-log 参数:relay_log_purge=ON,定期删除应用过的relay-log
2.master的dump线程实时监控主库的binlog变化,如果有新变化,发信号给从库

MySQL 主从复制原理描述

搭建大致思路:
(12台MySQL,server_id不重复
(2)主库开启binlog,建用户
(3)全备份主库到从库
(4)通过change master to IP、Port、User、Password、复制起点。 在从库执行这些信息
(5)启动线程SQL,IO线程。  start slave;

简要原理:
1.start slave语句后,从库获取主库复制信息,启动复制线程
2.IO线程,读取master.info 获取连接信息,连接主库,主库分配DUMP
3.IO线程,通过master.info 获取复制信息,向主库Dump请求
4.Dump返回日志。
5.IO线程,接收日志。TCP/IP缓存
6.IO线程写日志到relaylog,更新master.info
7.SQL线程读取relay.info,执行新的relay。更新relay.info
8.relaylog定期自动删除
9.主库通知从库有新日志产生。

整体上来说,复制有3个步骤:
A.master将改变记录到二进制日志(binary log)中(这些记录叫做二进制日志事件,binary log events);
B.slave将master的binary log events拷贝到它的中继日志(relay log);
C.slave重做中继日志中的事件,将改变反映它自己的数据。

Mysql复制的基本原理过程如下:
(1)Slave上面的IO线程连接上Master,并请求从指定日志文件的指定位置(或者从最开始的日志)之后的日志内容;
(2)Master接收到来自Slave的IO线程的请求后,通过负责复制的IO线程根据请求信息读取指定日志指定位置之后的日志信息,返回给Slave端的IO线程。返回信息中除了日志所包含的信息之外,还包括本次返回的信息在Master端binary log文件的名称以及在Binary log中的位置;
(3)Slave的IO线程收到信息后,将接收到的日志内容依次写入到Slave端的RelayLog文件(mysql-relay-lin.xxxxx)的最末端,并将读取到的Master端的bin-log的文件名和位置记录到master-info文件中,以便在下一次读取的时候能够清楚的告诉master“我需要从某个bin-log的哪个位置开始往后的日志内容,请发给我”
(4)Slave的SQL线程检测到Relay Log中新增加了内容后,会马上解析该Log文件中的内容成为在Master端真实执行时候的那些可执行的查询或操作语句,并在自身执行那些查询或操作语句,这样,实际上就是在master端和Slave端执行了同样的查询或操作语句,所以两端的数据是完全一样的。

补充:mysql主从复制的优点:
1.如果主服务器出现问题,可以快速切换到从服务器提供的服务
2.可以在从服务器上执行查询操作,降低主服务器的访问压力
3.可以在从服务器上执行备份,以避免备份期间影响主服务器的服务
注意一般只有更新不频繁的数据或者对实时性要求不高的数据可以通过从服务器查询,实时性要求高的数据仍然需要从主服务器获得

 

四、主从监控

show processlist;
show slave hosts;
在这里插入图片描述
在登录从库后
mysql> show slave status \G

mysql> show slave status \G
*************************** 1. row ***************************
主库相关信息,来自master.info
               Slave_IO_State: Waiting for master to send event
               Master_Host: 192.168.93.146
               Master_User: repl
               Master_Port: 3307
               Connect_Retry: 10
              Master_Log_File: mysql-bin.000003
              Read_Master_Log_Pos: 154


从库的relay-log的执行情况,来自于relay.info,一般用作判断主从延时。
这里表示 从库执行到的位置点是6号文件的367。。 对应主库的文件的是3号文件。
实际上,从内容来看,从库的Relay_Log_Pos=367 和 主库的Read_Master_Log_Pos=154是一样的
               Relay_Log_File: localhost-relay-bin.000006
               Relay_Log_Pos: 367
               Relay_Master_Log_File: mysql-bin.000003
               Exec_Master_Log_Pos: 154
			   Seconds_Behind_Master: 0 主从延时相关状态(非人为)


从库线程状态:具体报错信息
            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: 


延时从库有关的状态(人为)
SQL_Delay: 0
SQL_Remaining_Delay: NULL

GTID 复制有关的状态
Retrieved_Gtid_Set: 
Executed_Gtid_Set: 
Auto_Position: 0

五、故障分析

1.主从故障分析及处理

Linux MySQL 常见无法启动或启动异常的解决方案
Linux MySQL 常见无法启动或启动异常的解决方案

其实什么问题都可以通过重新搭建,备份恢复,change master to解决。 万能

1.1 主库连接故障

1)用户 密码  IP  port
[root@db01 ~]# mysql -urepl  -p123333  -h 192.168.93.146 -P 3307
ERROR 1045 (28000): Access denied for user 'repl'@'db01' (using password: YES)

mysql -S /tmp/mysql3309.sock

原因:
密码错误 
用户错误 
skip_name_resolve
地址错误
端口


处理方法:
stop  slave  先停止
reset slave all  把之前故障信息清理掉
change master to   执行正确的master to语句
start slave
show slave  staus \G  查看从库状态

start slave sql_thread; 单独启动SQL线程
start slave io_thread; 单独启动io线程

 

2)主库连接数上线,或者是主库太繁忙
show slave  staus \G  查看从库状态
Last_IO_Errno: 1040
Last_IO_Error: error reconnecting to master '[email protected]:3307' - retry-time: 10  retries: 7

处理思路:
拿复制用户,手工连接一下

[root@db01 ~]# mysql -urepl -p123 -h 192.168.93.146 -P 3307 
mysql: [Warning] Using a password on the command line interface can be insecure.	
ERROR 1040 (HY000): Too many connections
处理方法:
查看连接数上限:mysql>select @@max_connections;
修改连接数上限:mysql>set global max_connections=300;3)防火墙,网络不通
(4)版本不统一

1.2 请求日志,接收日志

❤故障原因:
主库二进制日志不完成:损坏,不连续。。
从库请求的起点问题。
主从的server_id(server_uuid) 相同。
relaylog 问题

主库模拟故障:
mysql -S /tmp/mysql3307.sock  主库登录
mysql> reset master;   删文件会阻塞一些新事物操作
从库登录后,show slave status \G;会发现日志丢失报错, Got fatal error 1236 
处理:要重新调整change master.info
步骤:
主库中:
mysql> reset master;   在业务停止或不繁忙时操作
mysql> show master status;

等待从库重放完所有主库日志
从库中:
mysql> stop slave;
mysql> reset slave all;
CHANGE MASTER TO
  MASTER_HOST='192.168.93.146',
  MASTER_USER='repl',
  MASTER_PASSWORD='123',
  MASTER_PORT=3307,
  MASTER_LOG_FILE='mysql-bin.000001',
  MASTER_LOG_POS=154,  这两个参数具体看主库 show master status;展示出来的参数
  MASTER_CONNECT_RETRY=10;

mysql> start slave;
mysql> show slave status \G;

登录主库后,show master status; 然后reset master;
在这里插入图片描述
登录从库后,show slave status \G;
Last_IO_Errno: 1236
Last_IO_Error: Got fatal error 1236 from master when reading data from binary log: ‘could not find next log; the first event ‘mysql-bin.000003’ at 154, the last event read from ‘/binlog/3307/mysql-bin.000004’ at 154, the last byte read from ‘/binlog/3307/mysql-bin.000004’ at 154.’

mysql>
CHANGE MASTER TO
MASTER_HOST=‘192.168.93.146’,
MASTER_USER=‘repl’,
MASTER_PASSWORD=‘123’,
MASTER_PORT=3307,
MASTER_LOG_FILE=‘mysql-bin.000001’,
MASTER_LOG_POS=154, 这两个参数具体看主库 show master status;展示出来的参数
MASTER_CONNECT_RETRY=10;

mysql> start slave;
mysql> show slave status \G;
在这里插入图片描述
 

1.3 SQL线程故障
(1)读写relay-log.info ,可以理解为执行relay-log SQL
(2)relay-log损坏,断节,找不到
(3)接收到的SQL无法执行

导致SQL线程故障原因分析:

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'



常见错误代码:
1007:对象已存在
1032:无法执行DML
1062:主键冲突,或约束冲突

例如:从库上创建了A数据库,又切换到主库发现没有再次创建A数据库。在从库上查看 show slave status;会报1007错误。 在下面有提到一劳永逸的方法
从库:create databse guo;
主库:create databse guo;
检查从库SQL状态:show slave status \G;
Slave_SQL_Running:No
Last_SQL_Error: Error ‘Can’t create database ‘guo’; database exists’ on query. Default database: ‘db’. Query: ‘create database guo’
 
处理故障:
思路1:一切以主库为准。
将从库进行反操作一下。重启线程
从库:mysql> drop database guo;
mysql> start slave;

思路2:以从库为准,跳过此次复制错误
处理方法(以从库为核心的处理方案):

如果,两个库名一样,字符属性不一样。不可用
从库:create databse guo charset=utf8;
主库:create databse guo charset=utf8mb4;

仅限于比较简单的故障场景 主从数据执行一模一样。
方法一:手工方法
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:
IO故障:
Could not find first log file name in binary log index file
怀疑:从库无法获取正确的binlog位置信息
处理过程:

1.查看从库信息
mysql> show slave status \G; 
*************************** 1. row ***************************
Master_Log_File: mysql-bin.000001  #获取到的文件名
Read_Master_Log_Pos: 154  #获取到的位置点信息

2.主库出问题怎么办:
物理:
(1)主库是否能ssh上
(2)检查一下binlog是否完整
判断001文件在不在? show binary logs;
mysql> show binary logs;
+------------------+-----------+
| Log_name         | File_size |
+------------------+-----------+
| mysql-bin.000001 |       177 |
| mysql-bin.000002 |       177 |
| mysql-bin.000003 |       177 |
| mysql-bin.000004 |       154 |
+------------------+-----------+
4 rows in set (0.01 sec)

如果断截,Percona-toolkit工具。 
(3)手工追加日志到最新位置
(4)从库替代主库工作。
修复最新状态,取消从库身份,清空binlog日志信息,

逻辑:
只能通过备份去恢复。

3.双主问题
一个宕机了,但是不知道 过了很久,另一个主页宕机了,怎么恢复。    
备份 + binlog恢复

 
1.4 一劳永逸的方法

(防止重复写入导致的故障):

(1) 可以设置从库只读.
mysql>show variables like '%read_only%';
mysql>select @@read_only;  #普通用户只读
mysql>select @@super_read_only; #普通管理员只读
注意:
只会影响到普通用户,对管理员用户无效。
(2)加中间件
读写分离。

 

2.主从延时的概念

2.1 什么是主从延时?
主库发生了操作,从库很久才跟上来

2.2 主从延时怎么监控?
首先要查看 show slave status \G;
粗略:Seconds_Behind_Master:0 #从库落后于主库的时间

准确:日志量
其次,评估主从延时更加精确的指标是,延时了多少日志量,即主库binlog位置点从库执行的日志(即从relay执行)的位置点 进行对比。

2.3 如何计算延时的日志量
主库(取binlog位置点):show master status \G;
从库(取relaylog位置点):relay-log.info

7表示来自于哪个主库
320这个值是从库中已经执行到relay-log的位置点。
relay-log是由SQL线程执行,SQL线程首先要读取relay-log.info,获取上次已经执行到的位置点。
mysql-bin.000001 1117 表示这个relay-log对应着主库的哪一段二进制日志

主从位置对应的上的话表示是同步的
在这里插入图片描述
cat /data/3308/data/relay-log.info
在这里插入图片描述

3.主从延时问题的原因分析及处理网络

 
外在因素:
主从硬件差异较大
版本差异
参数因素
从库太多
 
主库业务繁忙:
1.拆分业务(分布式):组件分离,垂直,水平
2.大失误的拆分:比如,1000w业务 拆分为20次执行

内在因素:
主库

  • 二进制日志更新。 sync_binlog=1
    主库更新后,没有及时更新日志,导致Dump线程不知道,不知道也无法通知从库的IO,IO不知道也无法取新的日志。
(1) 二进制日志写入不及时
mysql>select @@sync_binlog;
(2) CR的主从复制中,binlog_dump线程,事件为单元,串行传送二进制日志(5.6 5.5)
5.7之前的版本,没有开GTID之前,主库可以并发事务,但是dump传输时是串行,所以会导致大事务会严重延时
1. 主库并发事务量大,主库可以并行,传送时是串行(一个个)
2. 主库发生了大事务,由于是串行传送,会产生阻塞后续的事务.


解决方案:
3. 5.6 开始,手工开启GTID,实现了GC(group commit)机制,可以并行传输日志给从库IO
4. 5.7 开始,无需手工开启,会自动维护匿名的GTID,也能实现GC,我们建议还是认为开启GTID
有了GTID之后,就可以实现并发传输binlog
6. 大事务拆成多个小事务,可以有效的减少主从延时.

怎么判断是主库传输不及时?
1.seconds_behind_master
2.cat /data/3308/data/master.info
3.主从库状态的日志信息是否一致
从库:show slave status \G; 看Master_Log_File 和 Read_Master_Log_Pos
主库:show master status;

 
从库
外部:网络,从库配置低,参数设定。
内部:
IO线程:写relay-log —> IO性能
SQL线程:回放SQL默认在非GTID模式下是串行的
解决方案:
1.开启GTID
2.串行改并行

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]

 

后续:
延时从库
特殊从库的应用
主从复制架构演变
高可用及读写分离
分布式架构
优化

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_39578545/article/details/106536832