主从复制架构
主从复制架构
主从、也就是有一个master机器、以及一个、或者多个slave机器,用于数据的同步、备份。
MySQL数据库的主从复制技术与使用scp/rsync等命令进行的异机文件级别复制类似,都是数据的远程传输,只不过MySQL的主从复制技术是其软件自身携带的功能,无须借助第三方工具
MySQL主从复制介绍
MySQL数据库支持单向、双向、链式级联、环状等不同业务场景的主从复制。
在复制过程中,一台服务器(严格来讲是实例)作为主数据库(Master),接收来自用户的、对其内容的更新,而一个或多个其他的服务器则作为从服务器(Slave),接收来自主服务器binlog文件的日志内容,然后将该日志内容解析出的SQL语句重新应用到其他从服务器中,使得主从服务器数据达到一致。
官网mysql复制架构图
1.为什么用主从复制
MySQL主从复制集群技术使得MySQL数据库支持大规模高并发的读写操作成为可能,同时又能有效地解决物理服务器宕机场景的数据备份和进行快速业务切换的问题。
slave作为master实时数据备份
主从服务器架构的设计,可以大大加强MySQL数据库架构的健壮性。例如,当主服务器出现问题时,我们可以人工切换或设置成自动切换到从服务器继续提供服务,此时从服务器的数据和宕机时的主数据库几乎是一致的。
这有些类似于NFS存储数据通过inotify+rsync将数据同步到备份的NFS服务器,只不过MySQL的复制方案是其自带的工具,实现的方式是逻辑的复制,而非文件层级的复制。
缺点
利用MySQL的主从复制技术进行数据备份,在硬件故障、软件故障、人为在数据库外误操作的场景下,该数据备份是有效的;
但对于人为地在数据库中执行drop、delete等语句删除数据的情况,从库的备份功能就没有用了,因为从服务器也会执行删除的语句。
2.主从复制原理(重要)面试常问
MySQL的主从复制是一个异步的复制过程(虽然一般情况下感觉是实时的),数据将从一个MySQL数据库(我们称之为Master)复制到另一个MySQL数据库(我们称之为Slave),在Master与Slave之间实现整个主从复制的过程是由三个线程参与完成的。
其中有两个线程(SQL线程和IO线程)在Slave端,另外一个线程(binlog dump线程)在Master端(MySQL 5及以前是3个线程完成复制,从MySQL 6起SQL线程可以是多个)。
要实现MySQL的主从复制功能,首先必须打开Master端的binlog日志功能。
因为整个复制过程实际上就是Slave从Master端获取binlog日志,然后再在Slave上以相同的顺序执行获取的binlog日志中所记录的各种SQL操作,从而实现主从数据一致的功能。
图解详细原理过程
1、slave机器 start slave,开启主从复制
2.slave机器I/O线程会通过master上已经授权的复制用户,连接master服务器。通过该用户从指定的binlog日志文件的指定位置,发送binlog日志的内容。 (binlog文件名,pos值,都通过change master命令指定了)
3.master服务器接收到slave的I/O线程请求后,负责复制的binlog dump线程会根据slave服务器的I/O线程的请求信息,进行读取binlog,以及pos值之后的日志信息
4.然后返回给slave的I/O线程,返回的信息除了binlog日志内容外,以及master服务端新的binlog文件,以及POS值
5.slave此时的I/O线程接收到master发来的日志信息后,将binlog日志内容写入到slave本身的relay-log中继日志中,如mysql_relay-bin XXXXX的末端。并记录新的binlog文件信息,名字,pos值,写入master-info文件中,用于下一次读取binlog数据时,可以明确知道数据读取的起点。
6.salve服务器的SQL线程会实时监测本地的relay log新增的日志内容,然后将relay log文件中的内容,解析为SQL语句,且在自身的slave按顺序执行这些SQL
经过这些,就可以确保,master和slave执行了同样的SQL
在复制状态正常的情况下,master和slave的数据是完全一样的
复制原理小结
主从复制是异步的进行SQL语句的复制
复制时,主库有一个binlog dump 线程,从库有2个线程I/O线程、SQL线程
在MySQL5.6之后,slave的SQL线程有多个
实现主从复制的必要条件、主库开启binlog,基于binlog复制
用于复制的所有mysql节点,server-id不能相同
binlog文件只记录数据库有更改的SQL,(主数据库有变化),对select、show以及未修改数据库的语句不会记录
主从复制实践
准备3台机器
实现1主2从部署,mysql安装不多赘述,准备配置文件即可
注意server_id的区别
以及只有主库开启了binlog日志
https://downloads.mysql.com/archives/community/
同学们可以下载好如下rpm包,谁还能有于超老师的笔记细心?还有谁?
https://cdn.mysql.com/archives/mysql-5.7/mysql-5.7.28-linux-glibc2.12-x86_64.tar.gz
[root@db-51 /opt]#ll
total 707688
-rw-r--r-- 1 root root 724672294 Jul 18 13:48 mysql-5.7.28-linux-glibc2.12-x86_64.tar.gz
2.创建mysql目录
mkdir -p /www.yuchaoit.cn/soft/
mkdir -p /www.yuchaoit.cn/mysql_3306/
mkdir -p /opt/mysql5.7.28/
cd /www/yuchaoit.cn/soft/
wget https://cdn.mysql.com/archives/mysql-5.7/mysql-5.7.28-linux-glibc2.12-x86_64.tar.gz
tar -xf mysql-5.7.28-linux-glibc2.12-x86_64.tar.gz -C /opt/
mv /opt/mysql-5.7.28-linux-glibc2.12-x86_64 /opt/mysql5.7.28/
[root@db-51 /opt]#ln -s /opt/mysql5.7.28/ /opt/mysql
[root@db-51 /opt]#ls /opt/
mysql mysql5.7.28 mysql-5.7.28-linux-glibc2.12-x86_64
3. 设置环境变量
echo 'export PATH=$PATH:/opt/mysql/bin' >> /etc/profile
source /etc/profile
[root@db-51 /opt]#mysql -V
mysql Ver 14.14 Distrib 5.7.28, for linux-glibc2.12 (x86_64) using EditLine wrapper
4.清除无用依赖
[root@db-51 /opt]#rpm -qa |grep mariadb
[root@db-51 /opt]#yum remove mariadb-libs.x86_64 -y
rm -f /etc/my.cnf
5.安装mysql5.7的依赖包
[root@db-51 /opt]#yum install libaio-devel -y
6.创建mysql用户与目录授权
useradd -s /sbin/nologin -M mysql
chown -R mysql.mysql /www.yuchaoit.cn/
chown -R mysql.mysql /www.yuchaoit.cn/mysql_3306/
chown -R mysql.mysql /opt/mysql*
7.初始化数据库
mysqld --initialize-insecure --user=mysql --basedir=/opt/mysql --datadir=/www.yuchaoit.cn/mysql_3306
db-51
cat > /etc/my.cnf<<EOF
[mysqld]
user=mysql
datadir=/linux0224/mysql_3306
basedir=/opt/mysql/
socket=/tmp/mysql.sock
port=3306
log_error=/var/log/mysql/mysql.err
server_id=51
log_bin=/binlog/mysql-bin
[mysql]
socket=/tmp/mysql.sock
[client]
socket=/tmp/mysql.sock
EOF
db-52,db-53
# db-52配置
cat > /etc/my.cnf<<EOF
[mysqld]
user=mysql
datadir=/linux0224/mysql_3306
basedir=/opt/mysql/
socket=/tmp/mysql.sock
port=3306
log_error=/var/log/mysql/mysql.err
server_id=52
[mysql]
socket=/tmp/mysql.sock
[client]
socket=/tmp/mysql.sock
EOF
db-51主库操作
[root@db-51 /linux0224/mysql_3306]$mysql -e "show variables like 'log_bin'"
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| log_bin | ON |
+---------------+-------+
前面原理说过,slave和master连接同步,得有一个账号进行连接master,允许同步数据
1.主库设置个密码
mysqladmin password linux3306
2.创建复制用户
mysql -uroot -plinux3306 -e "grant replication slave on *.* to 'repl'@'10.0.0.%' identified by 'linux3306';"
3.查看用户
mysql -uroot -plinux3306 -e "select user,host,plugin from mysql.user"
4.查看权限
mysql -uroot -linux3306 -e "show grants for repl@'10.0.0.%'"
[root@db-51 /linux0224/mysql_3306]$mysqladmin password linux3306
mysqladmin: [Warning] Using a password on the command line interface can be insecure.
Warning: Since password will be sent to server in plain text, use ssl connection to ensure password safety.
[root@db-51 /linux0224/mysql_3306]$mysql -uroot -plinux3306 -e "grant replication slave on *.* to 'repl'@'10.0.0.%' identified by 'linux3306';"
mysql: [Warning] Using a password on the command line interface can be insecure.
[root@db-51 /linux0224/mysql_3306]$mysql -uroot -plinux3306 -e "select user,host,plugin from mysql.user"
mysql: [Warning] Using a password on the command line interface can be insecure.
+---------------+-----------+-----------------------+
| user | host | plugin |
+---------------+-----------+-----------------------+
| root | localhost | mysql_native_password |
| mysql.session | localhost | mysql_native_password |
| mysql.sys | localhost | mysql_native_password |
| repl | 10.0.0.% | mysql_native_password |
+---------------+-----------+-----------------------+
[root@db-51 /linux0224/mysql_3306]$mysql -uroot -linux3306 -e "show grants for repl@'10.0.0.%'"
mysql: [ERROR] mysql: unknown option '-l'
[root@db-51 /linux0224/mysql_3306]$mysql -uroot -plinux3306 -e "show grants for repl@'10.0.0.%'"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-----------------------------------------------------+
| Grants for repl@10.0.0.% |
+-----------------------------------------------------+
| GRANT REPLICATION SLAVE ON *.* TO 'repl'@'10.0.0.%' |
+-----------------------------------------------------+
备份主库数据,发给slave
# 备份命令
# -A 备份所有库表
# --single-transaction,给所有数据库加锁,防止数据写入,导致备份错误
# --master-data=2 将binlog的信息以注释形式备份
# -R 导出mysql自定义函数
# -E 导出events事件
# --triggers 导出所有数据表的触发器
mysqldump -uroot -plinux3306 -A --master-data=2 --single-transaction -R -E --triggers --max_allowed_packet=64M > /data/full.sql
# 发给slave
for i in 52 53 ;do scp /data/full.sql 10.0.0.$i:/opt/;done
Slave从库操作
[root@db-52 ~]#mysql < /opt/full.sql
[root@db-52 ~]#
[root@db-53 /opt]#
[root@db-53 /opt]#mysql < /opt/full.sql
[root@db-53 /opt]#
连接master
change master to
master_host='10.0.0.51',
master_port=3306,
master_user='repl',
master_password='linux3306',
master_log_file='mysql-bin.000008',
master_log_pos=704,
master_connect_retry=10;
# 启动slave复制
start slave;
#查看slave复制状态结果
show slave status\G;
线程解释
Slave_IO_Running:Yes,这个表示I/O的线程状态,I/O线程负责从主库中读取Binlog日志,并将Binlog日志写入从库的中继日志中,状态为Yes表示I/O线程工作正常,否则异常。
Slave_SQL_Running:Yes,这个表示SQL的线程状态,SQL线程负责读取中继日志(relay-log)中的数据并转换为SQL语句应用到从数据库中,状态为Yes表示I/O线程工作正常,否则异常。
Seconds_Behind_Master:0,这个表示在复制过程中,从库比主库延迟的秒数,这个参数很重要,但企业里有更准确地判断主从延迟的方法:在主库中写时间戳,然后通过从库读取时间戳,与当前数据库时间进行比较,从而认定是否真的延迟。
测试主从效果
主从复制原理
主库的线程
binlog_dump_thread
1.负责接收slave请求
2.传送主库binlog发给slave进行同步
从库的线程
IO线程 连接主库dump线程,请求master的binlog,接收master的日志,存储到从库本地的日志(relay-log)
SQL线程 回放relaylog,写入slave机器数据
mysql> show processlist;
+----+-------------+-----------+------+---------+------+--------------------------------------------------------+------------------+
| Id | User | Host | db | Command | Time | State | Info |
+----+-------------+-----------+------+---------+------+--------------------------------------------------------+------------------+
| 3 | root | localhost | NULL | Query | 0 | starting | show processlist |
| 4 | system user | | NULL | Connect | 513 | Waiting for master to send event | NULL |
| 5 | system user | | NULL | Connect | 293 | Slave has read all relay log; waiting for more updates | NULL |
+----+-------------+-----------+------+---------+------+--------------------------------------------------------+------------------+
3 rows in set (0.00 sec)
关于slave线程重点日志
Slave_IO_State: Waiting for master to send event
Master_Host: 10.0.0.51
Master_User: repl
Master_Port: 3306
Connect_Retry: 10
Master_Log_File: mysql-bin.000008
Read_Master_Log_Pos: 704
Relay_Log_File: db-52-relay-bin.000002
Relay_Log_Pos: 320
Relay_Master_Log_File: mysql-bin.000008
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
主从复制涉及的文件
主库
[root@db-51 /linux0224/mysql_3306]$ls /binlog
mysql-bin.000001 mysql-bin.000002 mysql-bin.000003 mysql-bin.000004 mysql-bin.000005 mysql-bin.000006 mysql-bin.000007 mysql-bin.000008 mysql-bin.index
binlog日志文件
从库
从库
中继日志 relay-log
命名方式
datadir/hostname-relay-bin.xxxxx
[root@db-52 /linux0224/mysql_3306]$ls /linux0224\/mysql_3306/ -l |grep relay
-rw-r----- 1 mysql mysql 207 Aug 11 16:55 db-52-relay-bin.000001
-rw-r----- 1 mysql mysql 476 Aug 11 16:59 db-52-relay-bin.000002
-rw-r----- 1 mysql mysql 50 Aug 11 16:55 db-52-relay-bin.index
-rw-r----- 1 mysql mysql 59 Aug 11 16:59 relay-log.info
[root@db-52 /linux0224/mysql_3306]$
作用:
存储获取到的binlog信息
主库信息文件
[root@db-52 /linux0224/mysql_3306]$cat /linux0224/mysql_3306/master.info
25
mysql-bin.000008
860
10.0.0.51
repl
linux3306
3306
10
0
0
30.000
0
a3bcd21a-194e-11ed-9f8f-000c2947d442
86400
0
作用:
记录主库ip,port,user,密码,binlog位置点等信息
relay-log.info
[root@db-52 /linux0224/mysql_3306]$cat /linux0224/mysql_3306/relay-log.info
7
./db-52-relay-bin.000002
476
mysql-bin.000008
860
0
0
1
主从复制监控
如下日志是排查主从故障的核心思路
主库
查看复制线程状态
show processlist;
查看slave节点信息
mysql> show slave hosts;
+-----------+------+------+-----------+--------------------------------------+
| Server_id | Host | Port | Master_id | Slave_UUID |
+-----------+------+------+-----------+--------------------------------------+
| 53 | | 3306 | 51 | 97630496-0def-11ed-8051-000c291bb766 |
| 52 | | 3306 | 51 | 96c4afb2-0dee-11ed-bcc5-000c294c7d18 |
+-----------+------+------+-----------+--------------------------------------+
2 rows in set (0.00 sec)
从库(重点)
# 查看从库复制状态
show slave status \G
# 查看主库连接信息、以及binlog、pos值等
mysql> show slave status\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 10.0.0.51
Master_User: repl
Master_Port: 3306
Connect_Retry: 10
Master_Log_File: mysql-bin.000004
Read_Master_Log_Pos: 485
# 擦看relay-log回放的信息
Relay_Log_File: db-53-relay-bin.000005
Relay_Log_Pos: 698
Relay_Master_Log_File: mysql-bin.000004
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
# 线程状态信息,这个状态不对,复制就有问题
[root@db-53 /data/mysql_3306]#mysql -uroot -pwww.yuchaoit.cn -e "show slave status\G" |grep -E 'IO|SQL'
mysql: [Warning] Using a password on the command line interface can be insecure.
Slave_IO_State: Waiting for master to send event
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Last_IO_Errno: 0
Last_IO_Error:
Last_SQL_Errno: 0
Last_SQL_Error:
SQL_Delay: 0
SQL_Remaining_Delay: NULL
Slave_SQL_Running_State: Slave has read all relay log; waiting for more updates
Last_IO_Error_Timestamp:
Last_SQL_Error_Timestamp:
# 提取复制相关信息
[root@db-53 /data/mysql_3306]#mysql -uroot -pwww.yuchaoit.cn -e "show slave status\G" |grep -E 'Replicate'
mysql: [Warning] Using a password on the command line interface can be insecure.
Replicate_Do_DB:
Replicate_Ignore_DB:
Replicate_Do_Table:
Replicate_Ignore_Table:
Replicate_Wild_Do_Table:
Replicate_Wild_Ignore_Table:
Replicate_Ignore_Server_Ids:
Replicate_Rewrite_DB:
# 落后主库的秒数
[root@db-53 /data/mysql_3306]#mysql -uroot -pwww.yuchaoit.cn -e "show slave status\G" |grep -E 'Behind'
mysql: [Warning] Using a password on the command line interface can be insecure.
Seconds_Behind_Master: 0
# 关于GTID的信息
[root@db-53 /data/mysql_3306]#mysql -uroot -pwww.yuchaoit.cn -e "show slave status\G" |grep -E 'Gtid|Auto'
mysql: [Warning] Using a password on the command line interface can be insecure.
Retrieved_Gtid_Set:
Executed_Gtid_Set:
Auto_Position: 0
故障常见原因
网络波动
master 连接信息错误,如端口,用户,密码,授权规则错误,复制无权限
防火墙拒绝请求
主机连接数到达上限
[root@db-53 /data/mysql_3306]#mysql -uroot -pwww.yuchaoit.cn -e "select @@max_connections;"
mysql: [Warning] Using a password on the command line interface can be insecure.
+-------------------+
| @@max_connections |
+-------------------+
| 151 |
+-------------------+
master、slave版本不一,5.7 、8.0、 5.6
解决思路
1. 网络是否通
2. 确认复制的change master配置正确
3. 主从的server_id是否正常
4. 主从的server_uuid是否正常
5.一般情况下,最直接暴力的解决办法,重新搭建主从
备份数据+重新构建主从关系,能最快解决问题。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构