MySQL主从复制

第1章 企业高可用标准

1.1 全年无故障率(非计划内故障停机)

99.9%                 ----> 0.001*365*24*60=525.6  min   一般互联网公司级别
99.99%                ----> 0.0001*365*24*60=52.56 min
99.999%               ----> 0.0001*365*24*60=5.256 min    金融级别

第2章 主从复制(MySQL Replication)

1.1 简介

1.1. 基于二进制日志复制的
1.2. 主库的修改操作会记录二进制日志
1.3. 从库会请求新的二进制日志并回放,最终达到主从数据同步
1.4. 主从复制核心功能:
辅助备份,处理物理损坏                   
扩展新型的架构:高可用,高性能,分布式架构等

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

1.2个数据库实例,server_id、server_uuid
2.主库需要开启二进制日志
3.主库中建立专用的复制用户(权限是replication slave)
4.主库全备,类似于“补课”的过程,适用于主库用了很长时间了,需要搭建从库时
5.change master to 告诉从库—主库的IP、port、user、password、复制的起点
6.start slave 开启专用的复制线程(主库:binlog_fump_therd、从库:IO_therd、SQL_therd)

1.3 面试题:如何评判主从复制可以替代备份功能

不能,因为主从复制是基于二进制日志的,如果主库执行了删库的操作,从库也会执行的,所以主从复制不能用于恢复逻辑损坏,适合用物理恢复

第3章 主从复制的工作过程(异步复制)

3.1 主从复制的工作过程

1.从库执行change master info时,会把IP、port、user、password、binlog文件名、position号写入msater.info文件中
2.从库执行start slave时,会立即生成IO线程和SQL线程
3.从库IO线程会读取master.info文件中的信息,获取主库的IP、port、binlog文件名、position号,连接主库
4.主库会生成一个专用的dump线程来和从库的IO线程交互
5.IO线程根据master.info文件中的binlog文件名和position号,去请求主库最新的binlog日志信息
6.主库的dump线程会去检查binlog的信息,如果有就通过网络传输给IO线程
7.IO线程会立即将接收过来的binlog信息转存到TCP/IP缓存,并且更新master.info文件中的信息,同时返回ACK给主库表示确认收到了(此时主库的工作完成)
8.IO线程把TCP/IP缓存中的binlog信息存储到relay-log日志文件.(此时IO线程的工作完成)
9.SQL线程读取relay-log.info文件中的信息,获取上一次回放relay-log位置信息作为起点,开始回放relay-log
10.SQL线程回放完成之后,会立即更新relay-log.info文件中的信息(为下一次回放做准备)
11.从库会自动清理应用过的relay-log
补充说明:
主库的dump线程会监控着binlog信息,当有新的binlog生成时,会发送信号给IO线程,IO线程立即发出申请

第4章 主从复制搭建流程

1.1主从复制前提

1 两台以上mysql实例 ,server_id,server_uuid不同
2 主库开启二进制日志
3 专用的复制用户
4 保证主从开启之前的某个时间点,从库数据是和主库一致(补课)
5 告知从库,复制user,passwd,IP port,以及复制起点(change master to)
6 线程(三个):Dump thread  IO thread  SQL thread 开启(start slave)

1.2环境规划

# 主库
ip:10.0.1.25 port:3306 server_id=25
软件目录 /soft
数据目录 /data
二进制日志目录 /data/binlog
错误日志目录   /data/error
# 从库
ip:10.0.1.26 port:3306 server_id=26
软件目录 /soft
数据目录 /data
二进制日志目录 /data/binlog
错误日志目录   /data/error

1.3 主库的操作

1.1 创建相应的目录

mkdir /soft
mkdir /data/binlog -p
mkdir /data/error

1.2 编写配置文件

vim /etc/my.cnf
#服务端
[mysqld]
user=mysql
#软件安装路劲
basedir=/soft/mysql5726
#数据路劲
datadir=/data/mysql/data
#服务端socket文件位置
socket=/tmp/mysql.sock
#关闭自动提交机制
autocommit=0
#服务器ID号
server_id=25
#二进制日志
log_bin=/data/binlog/mysql-bin
#二进制日志记录模式
binlog_format=row
#错误日志路劲
log_error=/data/error/mysql.log
log_timestamps=system
#端口号
port=3306
#客户端
[mysql]
#客户端socket文件位置
socket=/tmp/mysql.sock

1.3 启动mysql

systemctl start mysqld

1.4 从库的操作

1.1 创建相应的目录

mkdir /soft
mkdir /data/binlog -p
mkdir /data/error

1.2 编写配置文件

vim /etc/my.cnf
#服务端
[mysqld]
user=mysql
#软件安装路劲
basedir=/soft/mysql5726
#数据路劲
datadir=/data/mysql/data
#服务端socket文件位置
socket=/tmp/mysql.sock
#服务器ID号
server_id=26
#关闭自动提交机制
autocommit=0
#二进制日志
log_bin=/data/binlog/mysql-bin
#二进制日志记录模式
binlog_format=row
#错误日志路劲
log_error=/data/error/mysql.log
log_timestamps=system
#端口号
port=3306
#客户端
[mysql]
#客户端socket文件位置
socket=/tmp/mysql.sock

1.3 启动mysql

systemctl start mysqld

1.5 主库中创建复制用户并授权

mysql -uroot -p 123
grant replication slave on *.* to repl@'10.0.1.%' identified by '123';
select user,host from mysql.user;

1.6 备份主库并恢复到从库(类似于”补课”的过程)

1.1 主库操作

mysqldump  -A --master-data=2 --single-transaction  -R -E --triggers >/data/backup/full.sql
#查看备份文件,查看此时的posation号
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000005', MASTER_LOG_POS=489;

1.2 从库操作

1. 登录从库 msyql -uroot -p
把主库的备份数据发到从库/data/backup/
scp -rp /data/backup/* 10.0.1.26:/data/backup
2. 把主库的备份数据导入从库
mysql> set sql_log_bin=0;
mysql> source /data/backup/full.sql
mysql> set sql_log_bin=1;
此时,从库在某个时间点和主库一致了

1.7 告知从库关键复制信息

1.1 从库操作

CHANGE MASTER TO
  MASTER_HOST='192.168.114.50',
  MASTER_USER='repl',
  MASTER_PASSWORD='456',
  MASTER_PORT=3306,
  MASTER_LOG_FILE='mysql-bin.000005',
  MASTER_LOG_POS=489,
  MASTER_CONNECT_RETRY=10;

1.8 开启线程

1.1 从库操作

mysql>start slave;

1.2 报错

The slave I/O thread stops because master and slave have equal MySQL server UUIDs; these UUIDs must be different for replication to work.
原因:因为是直接克隆的第一台,所以在数据目录auto.cof里面的uuid和主库的一样

1.3 解决办法

mv /data/mysql/auto.cnf /data/mysql/auto.cnf.bak
关闭MySQL
systemctl stop mysqld
启动MySQL
systemctl start mysqld
查看主从状态
show slave status 
可以看到解决了

1.9 主从中涉及到的文件和线程

1.1 线程

1. 主库
dump_thread
2. 从库
IO_thread
sql_thread

1.2 文件

1. 主库
二进制日志文件
例
mysql-bin.000002
2. 从库
db07-relay-bin.000003    #中继日志
master.info              #主库信息记录日志           
relay-log.info           #中继日志应用情况信息

第6章 主从异常

1.1 主从异常的2大方面

1. 主从故障
2. 主从延时

1.2 主从故障

1.1 IO线程故障

第一个方面的原因(连接原因)

常见原因大概一下这些:
1.	IP不对
2.	port不对
3.	复制用户的用户名和密码不对
4.	防火墙
5.	达到了连接上限数
6.	主库没有启动
原因有很多,有一个办法可以快速定位到具体是哪一个原因
直接拿复制用户去登录主库,看看会报什么错误

现象一:ip/port/复制用户的用户名和密码不对/主库没有启动的

密码不对:
[root@db01 data]# mysql -urepl -p12321321 -h 10.0.0.51 -P 3307
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied for user 'repl'@'db01' (using password: YES)
用户名不对:
[root@db01 data]# mysql -urep -p123 -h 10.0.0.51 -P 3307
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 1045 (28000): Access denied for user 'rep'@'db01' (using password: YES)
=================================================================================================
IP地址不对:
[root@db01 data]# mysql -urepl -p123 -h 10.0.0.52 -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.52' (113)
端口不对:
[root@db01 data]# mysql -urepl -p123 -h 10.0.0.51 -P 3309
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)
说明:这2个如果不对的话,敲下回车的时候会卡一下,然后出来报错信息

现象二:主库连接数上线限

show slave  staus G 
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
处理方法:
db01 [(none)]>set global max_connections=300;

处理方法

stop  slave            停止从库所有的线程
reset slave all        清空master.info里面的信息
change master to       重新把正确的主库信息写入master.info
start slave             开启线程

第二个方面的原因(请求和接收二进制原因)

主库缺失日志
从库方面,二进制日志位置点不对
报错现象如下:
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.000001' at 154, the last event read from '/data/3307/data/mysql-bin.000002' at 154, the last byte read from '/data/3307/data/mysql-bin.000002' at 154.'

解决办法:

重新搭建主从
注意: 在主从复制环境中,严令禁止主库中reset master; 可以选择expire 进行定期清理主库二进制日志

第三个方面的原因(存储binlog到relay-log中)

这种情况一般是relay-log.info没有写入的权限,把这个文件的权限改一下即可
1.停止线程
2.修改权限
3.启动线程

1.2 SQL线程故障

1.1 SQL线程故障原因

1. 主从安装的MySQL版本不同,参数设定不同!比如:数据类型的差异、SQL_MODE的影响
2. 要创建的数据库对象,已经存在
3. 要删除或修改的对象不存在
4. DML语句不符合表定义及约束时和主键冲突
归根揭底的原因都是由于从库发生了写入操作

1.2 主键冲突问题处理

报错原因:主键冲突报错
Last_Error: Could not execute Write_rows event on table yu.fen; Duplicate entry '1' for key 'PRIMARY', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the event's master log mysql-bin.000007, end_log_pos 950
对于表不是很复杂,最稳妥解决方案
第一步:把从库里面报主键冲突的那一行找出来
第二步:再把主库里面这一行主键的对应的值找出来,2者对比
第三步:然后在从库里面,把这一行值用update 改为和主库的一样
第四步:在从库里面跳过这个错误(1.stop slave 2. set global sql_slave_skip_counter = 1)
第五步:重启线程(start slave)

1.3 对于SQL线程出现故障,官方提供了一种以从库为核心的处理方案

方法一:
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.4 最好的处理方法

(1) 可以设置从库只读.=======这种方法基本不用了
db01 [(none)]>show variables like '%read_only%';
注意:
只会影响到普通用户,对管理员用户无效。
super_read_only  加上这个参数root用户 也无法写入了
(2)加中间件   =======最推荐使用的方法,即使是管理员也无法对从库进行写入
读写分离。

1.3 主从延时

1.1 什么是主从延时

主库做了操作,从库要比较久的时间才能追上

1.2 外在因素

1. 网络
2. 主从硬件差异大
3. 主从的版本不一致
4. 主从的参数配置有差异

1.3. 主库方面的原因

原因1:主库的二进制日志写入不及时

可以通过参数select @@sync_binlog;  5.7版本此参数默认就是1
说明:这个参数设置为0.有操作系统来决定什么时候把binlog写入磁盘
     这个参数设置为1,只要事务commit,立即写入磁盘

原因2:在传统的主从复制中,主库的binlog_dump线程,以事件的形式,串行传输binlog(5.6、5.5)

串行化的好处:不会出现逻辑上的混乱
由于是串行化的原因
 1. 当主库并发事务量大,主库可以并行执行,但是传送日志的是串行的,所以会导致从库的延时高
 2. 当主库有大事务时,由于是以事件的形式传送的,大事务会阻塞后续所有的事务,归根结底还是串行传送           日志的原因
 =======================================================================================
 解决串行传输日志的方案:
 5.6版本,开启GTID.实现了GC(group commit)机制,可以并行传输日志给IO_T线程
 5.7版本,即使不开GTID,会自动维护匿名的GTID,也能实现GC,但是建议还是手动开启
 解决大事务的方案:
 大事务拆分成多个小事务,可以有效的减少主从延时

1. 4 从库方面的原因

原因:SQL线程导致的主从延时

在传统主从复制模式中,从库默认只有一个SQL线程,只能串行回放事务。
1. 主库并发事务大,从库只能串行回放relay-log 
2. 主库发生大事务,主库开启了GTID并行传送过来了,由于从库只有一个SQL线程,会一直卡在这里执行这个大事务,    从而阻塞了后续所有的事务
=====================================================================================
解决方案:
对于从库串行回放relay-log
5.6版本,有了GTID,可以实现多SQL线程,但是只能基于不同库的事务进行并发回放====基于库的回放
例如:主库有三个库,都发生了事务,传送到从库,这种情况下,从库时可以并发回放的
     如果主库只是在一个库下,并发了事务,传送到从库,从库还是进行串行回放
5.7版本,有了增强的GTID,在SQL方面,提供了基于逻辑时钟(logical_clock),binlog加入了seq_no机制,真正实现了基于事务级别的并发回放,这种技术我们把它称之为MTS(enhanced multi-threaded slave)

第7章 主从延时的监控

1.1 监控命令

show slave  statusG
Seconds_Behind_Master: 0
用这种方式不太准确(只显示时间,不知道是主库还是从库)

1.2 主库方面原因的监控

主库:
mysql> show master status;
File                    Position
mysql-bin.000007      981
从库:
show slave statusG
Master_Log_File: mysql-bin.000007
Read_Master_Log_Pos: 981
查看2个号码的大小,如果主库的数值很大,从库的数字很小说明,主库传送的不及时,

1.3 从库方面原因的监控

1.1 首先查看从库拿了多少日志过来

Master_Log_File: mysql-bin.000007
Read_Master_Log_Pos: 981

1.2 在查看从库执行了多少日志

Relay_Log_File: db01-relay-bin.000012
Relay_Log_Pos: 320

1.3 查找2者之间的对应关系

拿过来的是binlog,回放的是relay-log2者可定对不上号,所以要找到它们之间的关系
Exec_Master_Log_Pos: 981   这个值就是记录relay-log回放的位置信息
Relay_Log_Space: 1566
如果Exec_Master_Log_Pos: 981比Read_Master_Log_Pos: 981这个值小很多
说明是卡在了这个位置,我们就找到这个号码对应的语句在干什么,来分析为什么延时了
学习的进阶之路
原文地址:https://www.cnblogs.com/yufenchi/p/12961554.html