文章目录
- 一、MySQL主从同步原理
- 二、主从同步的方式
-
- [2.1 全同步](#2.1 全同步)
- [2.2 异步方式](#2.2 异步方式)
- [2.3 半同步](#2.3 半同步)
- [2.4 增强版同步](#2.4 增强版同步)
- [2.5 组复制](#2.5 组复制)
- 三、MySQL主从架构的拓扑形式
-
- [3.1 一主一从](#3.1 一主一从)
- [3.2 一主多从](#3.2 一主多从)
- [3.3 多主一从](#3.3 多主一从)
- [3.4 双主复制](#3.4 双主复制)
- [3.5 级联复制](#3.5 级联复制)
- 四、mysql主从集群搭建步骤
- 五、实战示例
一、MySQL主从同步原理
是什么?
主从同步又叫主从复制,通过从一个MySQL主节点复制到一个或多个从节点,把数据实时同步给从节点。
为什么?
- 读写分离:主写,从读。主故障了,从还能正常读。就像注册网站故障,当浏览网站还能正常。
- 性能提升:读写分工,提高工作效率。
- 数据实时备份:一个库磁盘坏了,其他从库把数据恢复。
- 高可用:主节点不可用了,把从节点提升为主节点,快速恢复服务。
主从同步架构图

Binlog(二进制日志) 是MySQL服务器层面生成的一种逻辑日志,它以二进制的形式,顺序记录了所有对MySQL数据库进行修改的操作(数据或结构变更)。
三种日志格式:
-
Statement :记录原始 SQL 语句,会导致更新时间与原库不一致。
例如:
update_time=now() -
Row:记录每行数据的变化,保证了数据与原库一致,缺点是数据量较大。
-
Mixed:Statement 和 Row 的混合模式,默认采用 Statement 模式,涉及日期、函数相关的时候采用 Row 模式,既减少了数据量,又保证了数据一致性。
二、主从同步的方式
2.1 全同步
全同步是MySQL复制模式中最严格的一种,主库提交事务时,必须等待所有从库都成功写入并执行该事务后,才向客户端返回成功。
- 优点:强一致性。
- 缺点:延迟较大。而且一个从库挂掉,整个数据库系统就瘫痪。

2.2 异步方式
默认的复制模式,主库提交事务时不等待从库确认,写完本地binlog后立即向客户端返回成功。
- 优点:
- 主库写入速度最快。
- 从库故障或网络中断,主库照常工作。
- 缺点:
- 数据可能不一致。
- 主机宕机,数据会丢失。

2.3 半同步
介于异步和全同步之间的折中方案。主库提交事务时,必须等待至少一个从库接收并写入relay log后,才向客户端返回成功。
- 优点:一致性比异步好
- 缺点:
- 性能比异步差。
- 非强一致性:只保证数据到达从库,不保证执行完成。
- 主机宕机可能会出现数据不一致问题。

例:主节点写入从节点过程中挂了。从节点被提升为主节点,但数据并没有发过来。上一秒订单还在下一秒订单消失。
2.4 增强版同步
增强版半同步:先确保从库把数据存到磁盘,再提交主库事务;而传统半同步:先提交主库事务,再等从库确认。
优势:
- 真正的零数据丢失(事务提交在确认之后)
- 故障切换安全(从库总有最新数据)
- 性能损失极小(相比传统半同步)
代价:
- 比异步复制多一次网络往返
- 从库故障会短暂影响写入(超时降级)
2.5 组复制
组复制是让多个MySQL服务器像一个数据库一样工作的技术,所有节点数据实时同步,任何写入都需要得到多数节点同意。

Master 1执行:A账户-100,B账户+100
↓
certify阶段:问其他节点"可以这样改吗?"
↓
Master 2检查:A余额够吗?B账户存在吗?
Master 3检查:同一时间有别的人在改这些账户吗?
↓
都回答"可以" → Consensus层记录"已同意"
↓
三节点同时:写binlog记录这个操作
↓
三节点同时:实际修改A和B的余额
↓
Master 1告诉客户端:转账成功
三、MySQL主从架构的拓扑形式
3.1 一主一从

优点:
- 架构简单:配置维护最容易,成本最低
缺点
- 单点风险高:只有一个从库,从库故障就失去备份
应用场景
- 小型项目:预算有限,流量不大
- 数据备份:只需一个实时备份副本
3.2 一主多从

优点
- 强大的读扩展:多个从库分担读请求
- 负载均衡:通过代理实现读请求分发
- 高可用性:一个从库故障不影响整体
- 容灾能力强:多个备份副本
缺点
- 主库写瓶颈:所有写操作仍集中在主库
- 同步延迟差异:不同从库延迟可能不一致
- 资源消耗大:每个从库都需要完整数据副本
应用场景
- 高并发读业务:电商商品页、新闻网站
- 读写分离架构:应用层分离读写操作
- 多维度查询:不同从库承载不同查询类型
3.3 多主一从

优点
- 集中分析:便于数据仓库和BI分析
- 解耦业务库:各业务库独立,汇总库统一查询
- 资源隔离:生产库和分析库物理分离
缺点
- 数据冲突风险:不同主库可能有重复数据
- 数据一致性挑战:需要处理时延和冲突
- 性能瓶颈:汇总从库可能成为新的瓶颈
应用场景
- 中央报表系统:跨业务线数据汇总
- 统一查询平台:为多个系统提供查询接口
- 备份中心:集中备份多个业务库数据
- 历史数据分析:不影响在线业务性能
3.4 双主复制
互为主从

优点
- 高可用性:任何一台故障,另一台立即接管
- 写扩展潜力:理论上可分担写负载
缺点
- 数据冲突风险:两边同时写相同数据会冲突
- 同步延迟问题:网络延迟可能造成数据不一致
- 自增ID冲突:需要特殊处理自增主键
应用场景
- 同城双活数据中心:金融、支付核心系统
- 零停机升级:需要轮流升级不影响业务
- 负载均衡写操作:通过应用分片实现写扩展
3.5 级联复制

优点
- 减少主库压力:主库只需同步到一个从库
- 网络容错:单点网络故障影响范围有限
缺点
- 延迟累积:每级复制都增加延迟,末端从库数据延迟最大
- 维护成本高:排查困难、恢复复杂
应用场景
- 跨国企业:总部→大区→国家→城市多级同步
- 数据分析系统:主库接收数据,从库分发处理数据
四、mysql主从集群搭建步骤
- 创建主库,并在主库中创建单独的 MySQL 用户用于同步数据,授予该用户数据同步权限
- 创建从库,配置从库的数据同步的主库信息
- 启动从库,开始同步
五、实战示例
目录结构:
mysql_master-slave
├── docker-compose.yaml
├── master
│ ├── Dockerfile-master
│ └── master.sql
└── slave
├── Dockerfile-slave
└── slave.sql
master/master.sql:
sql
CREATE USER 'root'@'%' IDENTIFIED BY 'root';
GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'root'@'%';
FLUSH PRIVILEGES;
1.创建一个名为 root 的用户,允许从任何IP地址连接,密码设置为 root。
CREATE USER:创建新用户的命令
'root'@'%':
'root':用户名'%':允许连接的主机(通配符,表示所有IP地址)
格式:'用户名'@'主机名'
IDENTIFIED BY:指定用户密码
2.授予 'root'@'%' 用户对所有数据库的所有表的复制权限,使其能够:作为从库连接到主库并复制数据,查看和监控复制状态
GRANT:授予权限的命令REPLICATION SLAVE:允许该用户作为从库复制的权限REPLICATION CLIENT:允许用户查看复制状态的权限ON. :- 第一个 *:所有数据库
- 第二个 *:所有表
格式:数据库名.表名
TO 'root'@'%':将权限授予之前创建的用户
3.FLUSH PRIVILEGES:刷新/重新加载权限表
master/Dockerfile-master:
sql
FROM mysql:5.7
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
COPY ./master/master.sql /docker-entrypoint-initdb.d
slave/slave.sql:
sql
CHANGE MASTER TO MASTER_HOST='mysql-master', MASTER_USER='root', MASTER_PASSWORD='root', MASTER_PORT=3306;
START SLAVE;
1.配置从库连接到主库所需的所有参数。
CHANGE MASTER TO
CHANGE MASTER:配置主从复制的专用命令TO:指定配置参数
MASTER_HOST='mysql-master'
MASTER_HOST:主库的主机名或IP地址'mysql-master':Docker 容器名(如果是容器化部署)IP地址(如 '192.168.1.100')
MASTER_USER='root':连接主库的用户名
MASTER_PASSWORD='root':连接主库的密码
MASTER_PORT=3306:主库的MySQL服务端口(可省略,默认就是3306)
2.启动从库的复制进程。
slave/Dockerfile-slave:
FROM mysql:5.7
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
COPY ./slave/slave.sql /docker-entrypoint-initdb.d
docker-compose.yaml:
yaml
version: "3"
services:
mysql-master:
build:
context: ./
dockerfile: ./master/Dockerfile-master
image: mysqlmaster:vl.0
restart: always
container_name: mysql-master
volumes:
- ./mastervarlib:/var/lib/mysql
ports:
- 9306:3306
environment:
MYSQL_ROOT_PASSWORD: root
privileged: true
command: ['--server-id=1',
'--log-bin=master-bin',
'--binlog-ignore-db=mysql',
'--binlog_cache_size=256M',
'--binlog_format=mixed',
'--lower_case_table_names=1',
'--character-set-server=utf8',
'--collation-server=utf8_general_ci']
mysql-slave:
build:
context: ./
dockerfile: ./slave/Dockerfile-slave
image: mysqlslave:vl.0
restart: always
container_name: mysql-slave
volumes:
- ./slavevarlib:/var/lib/mysql
ports:
- 9307:3306
environment:
MYSQL_ROOT_PASSWORD: root
privileged: true
command: ['--server-id=2',
'--relay_log=slave-relay',
'--lower_case_table_names=1',
'--character-set-server=utf8',
'--collation-server=utf8_general_ci']
depends_on:
- mysql-master
mysql-slave2:
build:
context: ./
dockerfile: ./slave/Dockerfile-slave
image: mysqlslave:v1.0
restart: always
container_name: mysql-slave2
volumes:
- ./slavevarlib2:/var/lib/mysql
ports:
- 9808:3306
environment:
MYSQL_ROOT_PASSWORD: root
privileged: true
command: ['--server-id=3',
'--relay_log=slave-relay',
'--lower_case_table_names=1',
'--character-set-server=utf8',
'--collation-server=utf8_general_ci']
depends_on:
- mysql-master
容器编排
创建容器:docker compose build
运行容器:docker compose up -d