【 MySQL集群架构与实践1】使用Docker实现简单主从复制
目录
一. MySQL集群
1.1 简介
1.2 单机模式
1.3 集群模式
1.4 主从架构
1.5 高性能架构
二.搭建MySQL集群的环境准备
2.1. 安装Docker
2.2 修改镜像源
2.3 Docker常用命令
三. 实践:搭建主从复制
3.1.应用场景
3.2 主从复制模式
3.3 主从复制配置
3.3.1.主节点配置
3.3.2 从节点1配置
3.3.3.从节点2配置
3.3.4 启动主从复制
3.3.6 测试
3.3.7.常⽤命令
1. 本节目标
-
掌握MySQL单机模式和集群模式的应用场景
-
掌握MySQL主从架构的特点和实现原理
-
掌握MySQL高性能架构的分类
-
掌握主从复制架构形式与分类
-
掌握如何配置一个MySQL主从复制集群
-
掌握MySQL主从复制集群环境中的常见命令
-
掌握如何查看MySQL主从复制集群中主机和从机的状态
-
了解MySQL主从复制集群环境中的常见问题
2. 本章节可以解决的问题(面试题)
-
知道MySQL集群吗?为什么要使用集群架构?
-
介绍一下MySQL主从复制的原理?
-
如何配置MySQL主从复制?
-
MySQL主从复制中常用的SQL指令?
-
MySQL主从复制模式中从机的IO线程与SQL线程的作用是什么?
-
二进制日志与中继日志的作用是什么?
-
MySQL集群中server_id的作用是什么?
一. MySQL集群
集群是由多台数据库服务器组成的,统一对象提供数据库服务。
1.1 简介
在当前互联网环境下,网站业务量不断增长,对系统可用性和性能提出了更高的要求。MySQL集群是一个高可用、高性能的数据库解决方案,旨在满足大规模应用程序对数据访问的需求。MySQL集群主要为了解决以下几个关键问题:
-
性能提升:通过将负载分散到多个服务器,集群可以显著提升数据库的读、写的性能。
-
高可用性:MySQL集群通过数据冗余和故障转移机制确保高可用性。即使某个节点发生故障,其他节点仍能继续提供服务。
-
扩展性:集群可以通过添加更多节点,来水平扩展系统的容量和处理能力。
-
数据一致性:通过复制和同步技术,集群模式可以确保数据在多个节点间的一致性。
-
读写分离:通过主从复制,可以将写操作集中在主库,读操作分散到多个从库,进一步提升数据库的读性能。
-
分库分表:为了解决单一数据库性能瓶颈,提高数据库扩展性,可以采用分库分表的集群模式,这通常需要借助中间件或框架来透明地处理数据的分布和路由。
-
负载均衡:在集群中,可以通过负载均衡技术,将请求合理分配到不同的节点上,防止单个节点过载。
-
适用场景:MySQL集群适用于需要高可用性、高性能和高并发的应用场景,如电信、在线游戏、电子商务和社交网络等。
MySQL集群的使用是为了应对大数据量和高并发访问的需求,通过提升性能、保证高可用性、实现数据的一致性和扩展性,以及通过读写分离和分库分表等技术手段,来满足互联网业务的快速发展。
1.2 单机模式
最快且最省成本的方式就是使用非常少量的服务器来部署应用程序和数据库,在这种场景数据库服务器可以只有一台,多个应用程序服务器(业务服务器)都访问同一台数据库服务器。
-
当应用程序的访问量和数据量比较少的时候,可以使用单机模式
-
快速部署一个系统上线,也是可以使用单机模式
-
所有的数据都要从单台数据库服务器获取,当访问量增加,数据库服务器的访问压力也会增加,如果数据库服务器出现异常(如网络、IO或系统故障)会导致整个业务系统无法正常工作。
-
当应用程序的访问量越来越多,数据量越来越大,单台数据库服务器已无法支持业务系统,为了解决这个问题可以把数据库部署成集群。
1.3 集群模式
-
多台数据库服务器共同完成整个系统的数据读写负载。
一主二从部署示例:写入数据时只往主服务器写,从服务器通过数据同步复制主库数据,所有查询操作访问从服务器。
集群将读/写操作分散到不同服务器,有效降低单台服务器压力,提高业务系统性能。
主服务器也叫主节点,从服务器也叫从节点。
集群部署可以是一主一从、一主多从、多主多从等,具体根据业务场景选择(主要讲解一主多从)。
1.4 主从架构
角色定义
-
主服务器 (Master):
-
核心职责:处理所有的数据写入操作(INSERT、UPDATE、DELETE)。
-
次要职责:可以处理简单的数据查询(SELECT)请求(但在高负载或读写分离严格场景下,通常只处理写操作)。
-
-
从服务器 (Slave):
-
核心职责:处理复杂的数据查询(SELECT)请求,分担主库的读负载。
-
重要职责:作为主库数据的实时或近实时备份副本,提供数据冗余和高可用性。
-
其他职责:可用于数据报表生成、数据挖掘等离线任务,避免影响主库性能。
-
主从复制核心原理
主从复制的核心目标是保证从服务器的数据最终与主服务器保持一致。其基本原理是:
-
日志记录: 主服务器在执行任何数据定义语言(DDL,如 CREATE、ALTER、DROP)或数据操作语言(DML,如 INSERT、UPDATE、DELETE)操作时,会将这些操作按执行顺序记录到其 二进制日志 (Binary Log, 简称 binlog) 中。
-
日志传输与重放: 从服务器连接到主服务器,获取并复制这些 binlog 事件,然后在从服务器上将这些事件转换回对应的 SQL 语句,并在从服务器的数据库上顺序执行(回放)这些 SQL 语句。
整体复制流程(线程协作)
主从复制过程主要涉及三个核心线程协同工作:
-
Master 端:Binlog Dump Thread
-
Slave 端:I/O Thread (Relay Log I/O Thread)
-
Slave 端:SQL Thread (Relay Log SQL Thread)
详细流程步骤:
-
Slave 初始化连接: 从服务器(Slave)根据配置信息(主库地址、用户、密码、起始复制位置等)主动连接到主服务器(Master)。
-
注册与信息同步:
-
Slave 向 Master 发送连接请求。
-
Slave 会报告自己当前的复制状态(例如,如果之前复制过,会告知上次接收到的 binlog 文件名和位置点;如果是首次复制,则从指定位置或最新位置开始)。现代复制(如使用 GTID)则通过全局事务标识符来同步位置。
-
这相当于 Slave 在 Master 端进行“注册”,告知 Master 需要从哪个点开始发送 binlog。
-
-
Master 创建转储线程: Master 接收到 Slave 的连接请求和位置信息后,为每个连接的 Slave 创建一个独立的 Binlog Dump Thread。
-
Master 写入 Binlog: 当 Master 上有 DDL/DML 操作提交时,这些操作严格按照提交顺序被写入 Master 的 binlog 文件。
-
Binlog 变更通知与推送:
-
一旦 binlog 有新的内容写入(事件),Binlog Dump Thread 被唤醒。
-
Binlog Dump Thread 读取 Master 上 binlog 文件中自 Slave 请求位置点之后的新增事件。
-
Binlog Dump Thread 将这些增量 binlog 事件通过网络发送给连接它的 Slave 的 I/O Thread。
-
-
Slave 接收与中继日志写入 (I/O Thread):
-
Slave 端的 I/O Thread 持续监听来自 Master 的 Binlog Dump Thread 发送的数据。
-
I/O Thread 接收到 binlog 事件数据后。
-
I/O Thread 将接收到的 binlog 事件顺序写入 Slave 服务器本地的中继日志 (Relay Log) 文件中。这个步骤主要是为了缓冲和持久化接收到的日志事件。
-
-
Slave 重放中继日志 (SQL Thread):
-
Slave 端的 SQL Thread 持续监控本地的 Relay Log 文件。
-
一旦 Relay Log 中有新的事件写入,SQL Thread 读取这些事件。
-
SQL Thread 解析 Relay Log 中的事件,将其还原成对应的 SQL 语句。
-
SQL Thread 在 Slave 的数据库引擎中顺序执行(回放) 这些 SQL 语句,从而将数据变更应用到从库,最终使 Slave 的数据与 Master 保持一致(存在延迟,见注意事项)。
-
关键特性与注意事项
-
异步复制 (Asynchronous Replication): 默认情况下,主从复制是异步的。Master 提交事务并写入 binlog 后即可响应客户端,不等待 Slave 接收和重放完成。这意味着 Slave 的数据相对于 Master 存在一定延迟(Replication Lag)。
-
数据最终一致性: 由于异步特性,主从之间是最终一致性模型,而非强一致性。
-
单线程回放瓶颈: 传统复制中,Slave 的 SQL Thread 是单线程执行 Relay Log 中的事件。如果 Master 并发写很高,单线程重放可能成为瓶颈,导致 Slave 延迟增大(MySQL 5.6+ 引入了基于库/表的并行复制以缓解此问题)。
-
Relay Log 作用: 作为 Slave 端的缓冲区,使 I/O Thread 接收日志和 SQL Thread 重放日志可以解耦,提高效率和稳定性。Relay Log 在 SQL Thread 执行完对应事件后会被自动清理(可配置保留策略)。
1.5 高性能架构
分为读写分离与数据库分片:
-
读写分离:上⾯主从架构的图例中描述的就是读写分离架构,通常是指写操作和读操作分发在不同 的服务器上。写操作分发到主服务器,读操作分发到从服务器,从服务器的数据通过数据同步的⽅ 式从主服务器获取。
-
数据库分片:由原来每个数据库服务中保存完整的数据,拆分为每个数据库服务保存⼀部分数据(分 ⽚),多个数据库服务共同组成完整的数据。如下图所⽰:
后⾯会详细讲解读写分离与数据库分⽚这两种架构的特点与搭建过程。在实际的⼯作中不论读写分 离还是数据库分⽚,都需要搭建MySQL集群。
二.搭建MySQL集群的环境准备
首先我们需要确定集群中包含多少台服务器,确定好了之后我们就开始搭建
我们需要准备服务器
- 云服务器(生产环境中推荐)
- 虚拟机(依赖宿主机,宿主机一崩溃,服务崩溃)
- Docker(依赖宿主机,宿主机一崩溃,服务崩溃)
我们接下来将使用Docker进行搭建
2.1. 安装Docker
什么是Docker?什么是镜像?
接下来我将在Ubuntu系统安装Docker
1.确认操作系统
cat /etc/*release*
更新 apt 包索引
sudo apt-get update
2.添加Docker官方密钥
sudo apt install apt-transport-https ca-certificates curl software-properties-common -y
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
一定需要看到这个OK,才算是添加好了密钥
3 添加阿里云Docker APT源
sudo add-apt-repository "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu $(lsb_release -cs) stable"
注意:如果出现了下面这种报错,请按照下面这个图这么干
4 更新APT包索引
sudo apt update
注意:
5 安装Docker CE
sudo apt install docker-ce docker-ce-cli containerd.io -y
6 查看Docker服务状态
sudo systemctl status docker
这个就是已经在运行当中了
如果没有在启动,我们就执行下面这个命令
# 如果Docker未启动则启动Docker服务
sudo systemctl start docker
7 查看Docker版本
sudo docker version
8 设置开机自启动
# 设置开机⾃启动
sudo systemctl enable docker
# 查看是否开机启动
sudo systemctl list-unit-files|grep docker.service
9 关闭防火墙
# 停止防火墙
sudo systemctl stop ufw
# 查看防⽕墙
sudo systemctl status ufw
# 禁⽤防⽕墙开机⾃启动
sudo systemctl disable ufw
10 重启、停止和卸载
# 重启
sudo systemctl restart docker
# 关闭
sudo systemctl stop docker
# 卸载
sudo apt-get purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras -y
# 删除两个相关目录
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd
2.2 修改镜像源
注意:我们现在还是不能使用Docker,因为它的镜像源默认是在国外的,我们得修改一下镜像源。
创建或修改 /etc/docker/daemon.json
:
vim /etc/docker/daemon.json
然后添加下面这个即可
{"registry-mirrors": ["https://docker.m.daocloud.io","https://dockerhub.timeweb.cloud","https://huecker.io"]
}
重启服务:
#重新加载服务配置
sudo systemctl daemon-reload
#重启Docker服务
sudo systemctl restart docker
#验证镜像源配置
docker info
我们这就算是配置好了。
2.3 Docker常用命令
# ================================
# Docker 容器生命周期管理
# ================================# 启动已停止运行的容器(容器需已存在)
docker start 容器名# 重启正在运行的容器(会停止后重新启动)
docker restart 容器名# 停止运行中的容器(优雅停止,发送SIGTERM信号)
docker stop 容器名# 修改容器重启策略(容器退出时自动重启)
docker update --restart=always 容器名
# --restart 参数选项说明:
# no - 容器退出时,不重启容器(默认值)
# on-failure - 只有在非0状态退出时才重启容器
# always - 无论退出状态如何,总是重启容器(适合生产环境关键服务)# ================================
# Docker 镜像管理
# ================================# 查看本地所有 Docker 镜像(包含镜像ID、仓库、标签、大小等信息)
docker images# 强制删除一个或多个 Docker 镜像
docker rmi -f [镜像名或镜像ID]
# 示例删除多个镜像:
# docker rmi -f nginx:latest mysql:8.0# ================================
# Docker 容器管理
# ================================# 查看正在运行的容器列表(简略信息)
docker ps# 查看所有容器列表(包含已停止的容器)
docker ps -a# 仅显示所有容器的ID(常用于批量操作)
docker ps -aq# 强制删除一个或多个容器
docker rm -f 容器ID/容器名
# 示例删除多个容器:
# docker rm -f container1 container2# ================================
# 日志与监控
# ================================# 查看容器的日志输出(默认显示最后日志)
docker logs 容器ID/容器名# 实时跟踪容器日志(类似 tail -f)
docker logs -f 容器ID/容器名# 查看容器最近30分钟的日志
docker logs --since 30m 容器ID/容器名# ================================
# 其他常用命令补充
# ================================# 进入正在运行的容器(启动交互式终端)
docker exec -it 容器名 /bin/bash# 查看容器资源使用情况(CPU、内存、网络等)
docker stats 容器名# 查看容器详细信息(包含配置、网络、挂载等)
docker inspect 容器名# 将容器保存为新的镜像(持久化修改)
docker commit 容器名 新镜像名:标签
三. 实践:搭建主从复制
3.1.应用场景
当业务增长导致数据库负载激增时,主从复制成为最常用的分布式架构解决方案。该模式通过在多个数据库服务器间维护数据一致性,将负载分散到不同节点,满足以下核心需求:
核心应用场景
-
实时数据备份与灾难恢复
-
主服务器持续将数据变更同步至从服务器,实现秒级数据冗余
-
主服务器故障时,从服务器可立即接管服务,确保业务连续性与数据完整性
-
-
读写分离优化性能
-
写操作集中路由至主服务器,读操作分发至多个从服务器
-
有效缓解主服务器压力,提升系统并发处理能力
-
支持高并发场景下数据安全,消除单点故障风险
-
-
动态负载均衡
-
基于预设策略将请求智能分发至集群节点
-
充分利用多服务器资源,显著提升系统吞吐量
-
架构核心优势
-
高可用性:主节点故障时从节点自动切换,保障服务零中断
-
数据可靠性:多副本数据存储机制,规避单点故障导致的数据丢失风险
-
弹性扩展:通过横向增加从节点,无缝应对业务规模增长
数据存储架构特性
所有数据库节点保存完全一致的数据副本,形成分布式数据服务集群:
-
主数据库:唯一接收写操作节点,通过二进制日志(binlog)实时推送数据变更
-
从数据库集群:多个节点同步主库数据,并行提供读服务
-
数据一致性保障:基于事务日志的复制机制确保所有节点数据最终一致
服务架构原则
-
多节点并行服务
-
所有数据库节点均可对外提供数据查询服务
-
客户端请求通过中间件自动路由至可用节点
-
-
故障自动转移
-
主节点失效时,集群自动选举新主节点(需配合高可用方案)
-
从节点故障不影响整体服务,流量自动重定向至健康节点
-
-
横向扩展能力
-
根据业务压力动态增减从节点数量
-
扩展过程不影响线上服务连续性
-
3.2 主从复制模式
一主一从:⼀台主服务器主要负责读写操作,⼀台从服务器主要负责读操作或备份
一主多从:⼀台主服务器负责写操作,多台从服务器负责读操作和备份。从节点从主节点同步数据
多主多从:部署多套主从避免单点故障。
3.3 主从复制配置
架构图
一主两从架构:主库写数据自动同步到从库,查询可在任意节点进行。
服务器规划
在单台服务器上使⽤ Docker 模拟多台服务器的场景
主从服务器IP⼀致,端⼝号不同
- • 主服务器:容器名 bit-mysql-master 端⼝号 53306
- • 从服务器1:容器名 bit-mysql-slave1 ,端⼝号 53307
- • 从服务器2:容器名 bit-mysql-slave2 ,端⼝号 53308
注意:启动docker之前需要关闭防火墙
sudo systemctl status ufw
3.3.1.主节点配置
我们先思考一个问题:
如果说我们配置了一个docker,我们如何去配置Docker上的mysql呢?
在 Docker 中配置 MySQL 的过程,与在原生 Linux 环境下配置 MySQL 的思路是相似的——都是通过修改其配置文件来实现。
Docker 容器虽然共享宿主机的内核,但拥有自己独立的文件系统。
每个 MySQL Docker 镜像内部,都预置了标准的 MySQL 目录结构,包括关键的配置文件目录(如 /etc/mysql
或 /etc/mysql/conf.d
)以及数据存储目录(如 /var/lib/mysql
)。
为了能够方便地管理和持久化 MySQL 的配置(以及数据),Docker 提供了强大的卷(Volume) 或 绑定挂载(Bind Mount) 功能。具体来说,最常用的方法是将容器内部的 MySQL 配置文件目录(例如 /etc/mysql
或 /etc/mysql/conf.d
)映射(挂载) 到宿主机上的一个指定目录。
怎么理解这个呢?我们看看下面这个
-
“里” - Docker 容器内部:
-
每个 Docker 容器(比如你拉取的
mysql
官方镜像启动的容器)就像一个小型、独立的 Linux 电脑。 -
这个小电脑里,MySQL 程序也像在真电脑上一样运行。
-
它的配置文件(最重要的通常是
my.cnf
或者放在/etc/mysql/conf.d/
目录下的.cnf
文件)就在这个小电脑的/etc/mysql/
或/etc/mysql/conf.d/
文件夹里。 -
它的数据(你存的数据库、表)默认放在这个小电脑的
/var/lib/mysql
文件夹里。
-
-
痛点:
-
这个小电脑是临时的!如果你把它删了(
docker rm
),里面的所有东西(包括你辛辛苦苦改好的配置和存的数据)就全没了! -
你想改配置,难道每次都要钻进这个小电脑(
docker exec -it ... bash
)里去用vi
编辑?太麻烦!
-
-
“外” - 宿主机(你的真 Linux 服务器/电脑):
-
这是运行 Docker 的那个实实在在的物理机或虚拟机。
-
它上面的文件系统是持久的,除非你主动删除或者硬盘坏了,否则文件一直在。
-
-
“合” - Docker 的魔法:映射(挂载)
-
Docker 提供了一个超级好用的功能:可以把宿主机上的一个真实文件夹,“映射”或者说“变成”容器内部的一个文件夹。
-
怎么理解? 想象你在宿主机上有个文件夹
/home/yourname/mysql_config
。通过 Docker 的命令,你可以让容器里的/etc/mysql/conf.d
这个文件夹,直接变成你宿主机上/home/yourname/mysql_config
的“入口”或者“窗口”。你在宿主机上对这个文件夹做的任何修改(增删改文件),立刻、实时地在容器内部的/etc/mysql/conf.d
里就能看到,完全同步!
-
核心思想就是通过作目录的映射,将Docker容器的目录映射到宿主机!!
创建并启动MySQL主服务器
- Docker中的MySQL服务的端口号3306映射到宿主机端口53306
- Docker中的配置文件路径映射到宿主机的 /bit/mysql/master/conf 目录
- Docker中的数据目录映射到宿主机的 /bit/mysql/master/mysql 目录
- Docker中MySQL的root密码为123456
- Docker中MySQL主库容器命名为 bit-mysql-master
- Docker中的MySQL版本为mysql:8.0.42
首先我们需要在宿主机上创建这些映射的目录
# 创建目录
mkdir -p /bit/mysql/master/conf
mkdir -p /bit/mysql/master/mysql
接下来我们需要在Docker里面安装mysql
docker run -d \-p 53306:3306 \-v /bit/mysql/master/conf:/etc/mysql/conf.d \-v /bit/mysql/master/mysql:/var/lib/mysql \-e MYSQL_ROOT_PASSWORD=123456 \--name bit-mysql-master \mysql:8.0.42
1. -d
含义:以后台模式(分离模式)运行容器。
作用:容器启动后不会占用当前终端,你可以在终端继续执行其他命令。
2. -p 53306:3306
含义:将宿主机的 53306 端口 映射到容器的 3306 端口。
作用:
- 容器内部 MySQL 使用默认端口 3306。
- 通过宿主机的 53306 端口可以访问容器内的 MySQL 服务。
- 避免与其他服务(如本地 MySQL)的端口冲突。
3. -v /bit/mysql/master/conf:/etc/mysql/conf.d
含义:将宿主机目录 /bit/mysql/master/conf 挂载到容器内的 /etc/mysql/conf.d。
作用:
- 容器内的 MySQL 配置文件(如 my.cnf)会从宿主机的目录加载。
- 修改宿主机的配置文件后,容器内的 MySQL 会自动应用更改。
4. -v /bit/mysql/master/mysql:/var/lib/mysql
含义:将宿主机目录 /bit/mysql/master/mysql 挂载到容器内的 /var/lib/mysql。
作用:
- MySQL 的数据文件(如数据库、表结构)会存储在宿主机的目录中。
- 即使容器被删除或重建,数据仍然保留在宿主机上。
5. -e MYSQL_ROOT_PASSWORD=123456
含义:设置环境变量 MYSQL_ROOT_PASSWORD,值为 123456。
作用:
- 容器启动时会自动创建 MySQL 的 root 用户,并设置密码为 123456。
- 这是 MySQL 容器初始化的必要步骤。
6. --name bit-mysql-master
含义:为容器指定名称 bit-mysql-master。
作用:
- 后续可通过名称直接管理容器(如启动、停止、删除)。
- 避免使用默认的随机生成的容器名称。
7. mysql:8.0.42
含义:使用 MySQL 8.0.42 版本的镜像启动容器。
作用:确保使用特定版本的 MySQL,避免版本差异导致的问题。
我们等待一会。下面这样子就是安装完了
注意:如果下载不了,这是因为没有修改镜像源
我们现在就需要去修改一下镜像源,参考2.2小节
# 查看容器状态
docker ps -a
#查看docker镜像
docker images
进入Docker容器
我们进入Docker容器看看
# 进入Docker容器,env LANG=C.UTF-8避免中文乱码问题
docker exec -it bit-mysql-master env LANG=C.UTF-8 /bin/bash
# 运行Mysql客户端
mysql -uroot -p
我们可以执行一些命令
测试外部连接
我们尝试使用命令行连接宿主机的53306端口
mysql -h 117.72.80.239 -P 53306 -u root -p
注意:如果你的宿主机是云服务器,请记得去开放云服务器的防火墙端口号和设置安全组
事实上,除了上面那个ufw命令的防火墙之外,云服务器商家还设置了另外2层保护——防火墙+安全组,这里的防火墙是云服务器商家另外加上的一组防火墙,我们还需要把他的端口开放一下
下面我以京东云为例,开放8080端口号
![]()
这里就是我们云服务器商家另外加的一层防火墙。
我们现在开放8080端口号
现在服务器的防火墙端口算是开放了
- ubuntu20.04云服务器开放安全组
注意:除了防火墙要开放端口外,还要在云服务器官网设置安全组
接下来我将以京东云为例,讲讲如何设置安全组
按保存即可
创建配置文件
在宿主机的主服务器配置映射目录中创建配置文件 my.cnf
vim /bit/mysql/master/conf/my.cnf
接下来我们执行下面这个即可
把下面这个复制进去
下面这些都是关于
# MySQL服务器节点
[mysqld]
# 服务器唯一id,默认值为1
# 作用:标识主从服务器的唯一身份,主从服务器的server-id必须不同
# 注意:生产环境需手动设置为全局唯一值(通常使用IP地址4部分里的最后一部分与端口号的组合)
# 例如宿主机的ip地址是117.28.83.239,然后这个主节点映射的端口号是53306,所以server-id应该是23953306
server-id=23953306# 二进制日志基本名,Linux下默认为binlog,window下默认为"机器名-bin"
# 作用:定义二进制日志文件的命名规则
# 生产环境推荐自定义日志路径(如 /var/log/mysql/binlog)
log-bin=binlog# 二进制日录的格式,默认为ROW,生产环境也推荐用ROW
# 作用:定义二进制日志记录事件的方式
# ROW模式:记录每一行数据的变化(更安全,但日志体积较大)
# STATEMENT模式:记录SQL语句(可能因上下文差异导致不一致)
# MIXED模式:混合模式
binlog_format=ROW# 二进制日志过期时间,指定10天,默认30天
# 作用:自动清理过期的二进制日志文件(单位:秒)
# 864000 = 10天 × 24小时 × 3600秒
binlog_expire_logs_seconds=864000# 在事务提交之前把二进制日志写入磁盘
# 作用:控制二进制日志的刷盘策略
# 1:每次事务提交都强制刷盘(最安全,但性能开销较大)
# 0:依赖系统决定刷盘时机(性能高,但可能丢失部分日志)
sync-binlog=1# 指定需要复制的数据库,默认复制全部数据库
# 作用:限制只复制指定的数据库(可配置多行)
# 示例:binlog-do-db=mydb1
# 注意:该配置仅在启用主从复制时生效,且需与replicate-do-db配合使用
# binlog-do-db=db_name# 设置不需要复制的数据库,每行指定一个数据库,可以配置多行
# 作用:排除某些数据库的复制操作(如系统库)
# 示例:
# binlog-ignore-db=mysql
# binlog-ignore-db=information_schema
# 注意:忽略数据库时需谨慎,避免误操作导致数据不一致
# binlog-ignore-db=db_name1
# binlog-ignore-db=db_name2
. 重启主库MySQL容器,使配置生效
# 重启容器
docker restart bit-mysql-master
我们也可以进去看看
# 进入Docker容器,env LANG=C.UTF-8避免中文乱码问题
docker exec -it bit-mysql-master env LANG=C.UTF-8 /bin/bashmysql -u root -p
配置主服务器
在主服务器里面为从服务器创建访问账号并设置密码,用于从服务器登录主服务器
-- 创建用于主从复制的用户
-- 'bit_slave'@'%':用户名为 bit_slave,允许从任意主机(% 表示任意IP)连接
-- mysql_native_password:指定使用 MySQL 本地密码认证方式(兼容性较高)
-- '123456':为该用户设置密码(生产环境需更换为强密码)
CREATE USER 'bit_slave'@'%' IDENTIFIED WITH mysql_native_password BY '123456';-- 授予用户 REPLICATION SLAVE 权限
-- REPLICATION SLAVE:允许该用户作为从库连接主库,读取二进制日志
-- *.*:表示授予所有数据库的所有权限(此处仅针对复制权限)
-- 注意:该权限仅用于主从复制,无需额外授予其他权限
GRANT REPLICATION SLAVE ON *.* TO 'bit_slave'@'%';-- 刷新权限表,使新配置立即生效
-- 所有涉及用户或权限修改的操作后都需要执行此命令
FLUSH PRIVILEGES;
此外,我们需要去查看一下这个用户有没有远程复制权限?
select u.host, u.user, u.Repl_slave_priv from mysql.user u;
我们也需要去验证一下我们能不能远程登陆啊
很明显是可以的了。
我们现在需要去查询一下主机状态
-- 查看主库当前的二进制日志状态
-- 输出包含以下关键信息:
-- File:当前正在使用的二进制日志文件名(如 binlog.000001)
-- Position:当前日志文件的写入位置(从库需从该位置开始同步)
-- Binlog_Do_DB/Binlog_Ignore_DB:配置的复制数据库规则(如果有)
-- 该信息用于配置从库时指定同步起点
SHOW MASTER STATUS;
这个是主从复制的起始位置。我们等会会在从节点中使用到。
3.3.2 从节点1配置
创建并启动MySQL从服务器
- Docker中的MySQL服务的端口号3306映射到宿主机端口53308
- Docker中的配置文件路径映射到宿主机的 /bit/mysql/slave2/conf 目录
- Docker中的数据目录映射到宿主机的 /bit/mysql/slave2/mysql 目录
- Docker中MySQL的root密码为123456
- Docker中MySQL从库容器命名为 bit-mysql-slave2
- Docker中的MySQL版本为mysql:8.0.42
首先我们需要在宿主机上创建这些映射的目录
# 创建目录
mkdir -p /bit/mysql/slave1/conf
mkdir -p /bit/mysql/slave1/mysql
安装MySQL镜像
docker run -d \-p 53307:3306 \-v /bit/mysql/slave1/conf:/etc/mysql/conf.d \-v /bit/mysql/slave1/mysql:/var/lib/mysql \-e MYSQL_ROOT_PASSWORD=123456 \--name bit-mysql-slave1 \mysql:8.0.42
1. -d
含义:以后台模式(分离模式)运行容器。
作用:容器启动后不会占用当前终端,你可以在终端继续执行其他命令。
2. -p 53307:3306
含义:将宿主机的 53307 端口 映射到容器的 3306 端口。
作用:
- 容器内部 MySQL 使用默认端口 3306。
- 通过宿主机的 53307 端口可以访问容器内的 MySQL 服务。
- 避免与其他服务(如本地 MySQL)的端口冲突。
3. -v /bit/mysql/slave1/conf:/etc/mysql/conf.d
含义:将宿主机目录 /bit/mysql/slave1/conf 挂载到容器内的 /etc/mysql/conf.d。
作用:
- 容器内的 MySQL 配置文件(如 my.cnf)会从宿主机的目录加载。
- 修改宿主机的配置文件后,容器内的 MySQL 会自动应用更改。
4. -v /bit/mysql/slave1/mysql:/var/lib/mysql
含义:将宿主机目录 /bit/mysql/slave1/mysql 挂载到容器内的 /var/lib/mysql。
作用:
- MySQL 的数据文件(如数据库、表结构)会存储在宿主机的目录中。
- 即使容器被删除或重建,数据仍然保留在宿主机上。
5. -e MYSQL_ROOT_PASSWORD=123456
含义:设置环境变量 MYSQL_ROOT_PASSWORD,值为 123456。
作用:
- 容器启动时会自动创建 MySQL 的 root 用户,并设置密码为 123456。
- 这是 MySQL 容器初始化的必要步骤。
6. --name bit-mysql-slave1
含义:为容器指定名称 bit-mysql-slave1。
作用:
- 后续可通过名称直接管理容器(如启动、停止、删除)。
- 避免使用默认的随机生成的容器名称。
7. mysql:8.0.42
含义:使用 MySQL 8.0.42 版本的镜像启动容器。
作用:确保使用特定版本的 MySQL,避免版本差异导致的问题。
这次执行会非常快,因为我们之前已经把镜像下载下来了。
# 查看容器状态
docker ps -a
创建配置文件
vim /bit/mysql/slave1/conf/my.cnf
在宿主机的从服务器配置映射目录 /bit/mysql/slavel/conf 中创建配置文件 my.cnf,并完成以下配置
# MySQL服务器节点
[mysqld]
# 服务器唯一id,默认值为1
server-id=23953307
# 二进制日志基本名,Linux下默认为binlog,window下默认为"机器名-bin"
# 生产环境推荐自定义日志路径
log-bin=binlog
# 二进制日志的格式,默认为ROM,生产环境也推荐用ROM
binlog_format=ROW
# 二进制日志过期时间,指定10天,默认30天
binlog_expire_logs_seconds=864000
# 在事务提交之前把二进制日志写入磁盘
sync-binlog=1# 中断日志基本名,默认为"机器名-relay-bin",也可以指定自定义路径
relay-log=relay-bin
# 服务器启动时不启动复制,稍后手动启动使用start REPLICA语句。
# MySQL8.0.26之前用skip-slave-start=ON,稍后手动启动使用start SLAVE语句。
skip-replica-start=ON
# SQL线程执行的更新写入副本自己的二进制日志,MySQL8.0.26之前用log_slave_updates=ON
# 如果要实现 "服务器 <-- B服务器 <-- C服务器" 这种模式日志同步,则B服务器即是主又是从,需要开启该选项
# log-replica-updates=ON# 禁用二进制日志
# skip-log-bin# 指定需要复制的数据库,默认复制全部数据库
# binlog-db-db=db_name
# 设置不需要复制的数据库,每行指定一个数据库,可以配置多行
# binlog-ignore-db-db_name1
# binlog-ignore-db-db_name2
注意:server-id不能和主节点的一样!!!
# 重启容器
docker restart bit-mysql-slave1
# 查看容器状态
docker ps -a
# 进入Docker容器,env LANG=C.UTF-8避免中文乱码问题
docker exec -it bit-mysql-slave1 env LANG=C.UTF-8 /bin/bash# 运行mysql客户端
mysql -uroot -p# 查看配置是否生效
select @@server_id;
测试外部连接
我们现在尝试远程连接宿主机的53307端口
mysql -h 117.72.80.239 -P 53307 -u root -p
如果宿主机是云服务器,请去云服务厂商那里的防火墙和安全组开放53307端口,具体过程我已经在上面讲过了
我们在另外一台机器上面进行连接
连接上之后我们需要在从节点执行下面这个命令
CHANGE MASTER TO
MASTER_HOST = '117.72.80.239',
MASTER_PORT = 53306,
MASTER_USER = 'bit_slave',
MASTER_PASSWORD = '123456',
MASTER_LOG_FILE = 'binlog.000003',
MASTER_LOG_POS = 837;
CHANGE MASTER TO
是 MySQL 从库(Slave)配置命令,用于设置从库连接主库(Master)并同步数据的参数。该命令会将从库的复制配置更新为指定的主库信息,包括主库地址、认证信息、同步起点等。
参数详解
1. MASTER_HOST = '117.72.80.239'
-
含义:指定主库的 IP 地址。
-
作用:从库需要通过该地址连接到主库的 MySQL 服务。
-
注意:
-
确保主库的 IP 地址正确,并且从库能够访问主库的 MySQL 端口(
53306
)。 -
如果主库部署在 Docker 容器中,需确认容器已映射端口(如
53306:3306
),且宿主机防火墙允许外部访问。
-
2. MASTER_PORT = 53306
-
含义:指定主库 MySQL 服务的端口号。
-
作用:从库通过该端口与主库通信。
-
注意:
-
确保主库的 MySQL 服务正在监听该端口。
-
如果主库运行在 Docker 容器中,需确认容器已将端口映射到宿主机(如
53306:3306
)。
-
3. MASTER_USER = 'bit_slave'
-
含义:指定用于主从复制的用户名。
-
作用:从库使用该用户连接到主库,并读取二进制日志(Binlog)。
-
注意:
-
该用户需在主库上存在,并且具有
REPLICATION SLAVE
权限。 -
我们在上面配置主库的时候已经创建了这么一个用户
-
4. MASTER_PASSWORD = '123456'
-
含义:指定主从复制用户的密码。
-
作用:从库使用该密码验证连接主库的用户。
-
注意:
-
生产环境需使用强密码(如
Aa1!@#qwertY
),避免使用简单密码(如123456
)。 -
确保密码与主库创建用户时设置的密码一致。
-
5. MASTER_LOG_FILE = 'binlog.000003'
-
含义:指定从库开始同步的二进制日志文件名。
-
作用:从库会从主库的该文件中读取 Binlog 记录。
-
来源:
-
该值需通过主库执行
SHOW MASTER STATUS;
获取,输出中的File
字段即为当前正在写入的 Binlog 文件名。 - 我们在上面配置主库的时候查询过:
-
6. MASTER_LOG_POS = 837
-
含义:指定从库开始同步的二进制日志位置(偏移量)。
-
作用:从库会从主库的该文件的 837字节位置开始读取 Binlog。
-
来源:
-
该值需通过主库执行
SHOW MASTER STATUS;
获取,输出中的Position
字段即为当前 Binlog 的写入位置。
-
我们来执行一下
这就算是从节点1就算是配置成功了。
3.3.3.从节点2配置
其实我说白了,步骤和上面一模一样
但是我还是有必要给大家看看
创建并启动MySQL从服务器
- Docker中的MySQL服务的端口号3306映射到宿主机端口53308
- Docker中的配置文件路径映射到宿主机的 /bit/mysql/slave2/conf 目录
- Docker中的数据目录映射到宿主机的 /bit/mysql/slave2/mysql 目录
- Docker中MySQL的root密码为123456
- Docker中MySQL从库容器命名为 bit-mysql-slave2
- Docker中的MySQL版本为mysql:8.0.42
首先我们需要在宿主机上创建这些映射的目录
# 创建目录
mkdir -p /bit/mysql/slave2/conf
mkdir -p /bit/mysql/slave2/mysql
安装MySQL镜像
docker run -d \-p 53308:3306 \-v /bit/mysql/slave2/conf:/etc/mysql/conf.d \-v /bit/mysql/slave2/mysql:/var/lib/mysql \-e MYSQL_ROOT_PASSWORD=123456 \--name bit-mysql-slave2 \mysql:8.0.42
1. -d
含义:以后台模式(分离模式)运行容器。
作用:容器启动后不会占用当前终端,你可以在终端继续执行其他命令。
2. -p 53308:3306
含义:将宿主机的 53308 端口 映射到容器的 3306 端口。
作用:
- 容器内部 MySQL 使用默认端口 3306。
- 通过宿主机的 53308 端口可以访问容器内的 MySQL 服务。
- 避免与其他服务(如本地 MySQL)的端口冲突。
3. -v /bit/mysql/slave2/conf:/etc/mysql/conf.d
含义:将宿主机目录 /bit/mysql/slave2/conf 挂载到容器内的 /etc/mysql/conf.d。
作用:
- 容器内的 MySQL 配置文件(如 my.cnf)会从宿主机的目录加载。
- 修改宿主机的配置文件后,容器内的 MySQL 会自动应用更改。
4. -v /bit/mysql/slave2/mysql:/var/lib/mysql
含义:将宿主机目录 /bit/mysql/slave2/mysql 挂载到容器内的 /var/lib/mysql。
作用:
- MySQL 的数据文件(如数据库、表结构)会存储在宿主机的目录中。
- 即使容器被删除或重建,数据仍然保留在宿主机上。
5. -e MYSQL_ROOT_PASSWORD=123456
含义:设置环境变量 MYSQL_ROOT_PASSWORD,值为 123456。
作用:
- 容器启动时会自动创建 MySQL 的 root 用户,并设置密码为 123456。
- 这是 MySQL 容器初始化的必要步骤。
6. --name bit-mysql-slave2
含义:为容器指定名称 bit-mysql-slave2。
作用:
- 后续可通过名称直接管理容器(如启动、停止、删除)。
- 避免使用默认的随机生成的容器名称。
7. mysql:8.0.42
含义:使用 MySQL 8.0.42 版本的镜像启动容器。
作用:确保使用特定版本的 MySQL,避免版本差异导致的问题。
这次执行会非常快,因为我们之前已经把镜像下载下来了。
# 查看容器状态
docker ps -a
创建配置文件
vim /bit/mysql/slave2/conf/my.cnf
在宿主机的从服务器配置映射目录 /bit/mysql/slavel/conf 中创建配置文件 my.cnf,并完成以下配置
# MySQL服务器节点
[mysqld]
# 服务器唯一id,默认值为1
server-id=23953308
# 二进制日志基本名,Linux下默认为binlog,window下默认为"机器名-bin"
# 生产环境推荐自定义日志路径
log-bin=binlog
# 二进制日志的格式,默认为ROM,生产环境也推荐用ROM
binlog_format=ROW
# 二进制日志过期时间,指定10天,默认30天
binlog_expire_logs_seconds=864000
# 在事务提交之前把二进制日志写入磁盘
sync-binlog=1# 中断日志基本名,默认为"机器名-relay-bin",也可以指定自定义路径
relay-log=relay-bin
# 服务器启动时不启动复制,稍后手动启动使用start REPLICA语句。
# MySQL8.0.26之前用skip-slave-start=ON,稍后手动启动使用start SLAVE语句。
skip-replica-start=ON
# SQL线程执行的更新写入副本自己的二进制日志,MySQL8.0.26之前用log_slave_updates=ON
# 如果要实现 "服务器 <-- B服务器 <-- C服务器" 这种模式日志同步,则B服务器即是主又是从,需要开启该选项
# log-replica-updates=ON# 禁用二进制日志
# skip-log-bin# 指定需要复制的数据库,默认复制全部数据库
# binlog-db-db=db_name
# 设置不需要复制的数据库,每行指定一个数据库,可以配置多行
# binlog-ignore-db-db_name1
# binlog-ignore-db-db_name2
注意:这里的server-id不能和主节点还有从节点1的一样!!!
# 重启容器
docker restart bit-mysql-slave2
# 查看容器状态
docker ps -a
# 进入Docker容器,env LANG=C.UTF-8避免中文乱码问题
docker exec -it bit-mysql-slave2 env LANG=C.UTF-8 /bin/bash# 运行mysql客户端
mysql -uroot -p# 查看配置是否生效
select @@server_id;
测试外部连接
我们现在尝试远程连接宿主机的53308端口
mysql -h 117.72.80.239 -P 53308 -u root -p
如果宿主机是云服务器,请去云服务厂商那里的防火墙和安全组开放53308端口,具体过程我已经在上面讲过了
我们在另外一台机器上面进行连接
连接上之后我们需要在从节点2执行下面这个命令 ,注意这个命令和在从节点1里面是一模一样的。
CHANGE MASTER TO
MASTER_HOST = '117.72.80.239',
MASTER_PORT = 53306,
MASTER_USER = 'bit_slave',
MASTER_PASSWORD = '123456',
MASTER_LOG_FILE = 'binlog.000003',
MASTER_LOG_POS = 837;
CHANGE MASTER TO
是 MySQL 从库(Slave)配置命令,用于设置从库连接主库(Master)并同步数据的参数。该命令会将从库的复制配置更新为指定的主库信息,包括主库地址、认证信息、同步起点等。
参数详解
1. MASTER_HOST = '117.72.80.239'
-
含义:指定主库的 IP 地址。
-
作用:从库需要通过该地址连接到主库的 MySQL 服务。
-
注意:
-
确保主库的 IP 地址正确,并且从库能够访问主库的 MySQL 端口(
53306
)。 -
如果主库部署在 Docker 容器中,需确认容器已映射端口(如
53306:3306
),且宿主机防火墙允许外部访问。
-
2. MASTER_PORT = 53306
-
含义:指定主库 MySQL 服务的端口号。
-
作用:从库通过该端口与主库通信。
-
注意:
-
确保主库的 MySQL 服务正在监听该端口。
-
如果主库运行在 Docker 容器中,需确认容器已将端口映射到宿主机(如
53306:3306
)。
-
3. MASTER_USER = 'bit_slave'
-
含义:指定用于主从复制的用户名。
-
作用:从库使用该用户连接到主库,并读取二进制日志(Binlog)。
-
注意:
-
该用户需在主库上存在,并且具有
REPLICATION SLAVE
权限。 -
我们在上面配置主库的时候已经创建了这么一个用户
-
4. MASTER_PASSWORD = '123456'
-
含义:指定主从复制用户的密码。
-
作用:从库使用该密码验证连接主库的用户。
-
注意:
-
生产环境需使用强密码(如
Aa1!@#qwertY
),避免使用简单密码(如123456
)。 -
确保密码与主库创建用户时设置的密码一致。
-
5. MASTER_LOG_FILE = 'binlog.000003'
-
含义:指定从库开始同步的二进制日志文件名。
-
作用:从库会从主库的该文件中读取 Binlog 记录。
-
来源:
-
该值需通过主库执行
SHOW MASTER STATUS;
获取,输出中的File
字段即为当前正在写入的 Binlog 文件名。 - 我们在上面配置主库的时候查询过:
-
6. MASTER_LOG_POS = 837
-
含义:指定从库开始同步的二进制日志位置(偏移量)。
-
作用:从库会从主库的该文件的 837字节位置开始读取 Binlog。
-
来源:
-
该值需通过主库执行
SHOW MASTER STATUS;
获取,输出中的Position
字段即为当前 Binlog 的写入位置。
-
我们来执行一下
这就算是从节点2就算是配置成功了。
3.3.4 启动主从复制
我们需要在两个从节点分别启动从服务器复制功能,也就是分别执行下面这个命令
-- 启动复制,语法 START {REPLICA; | SLAVE};
START REPLICA;
查看从节点状态
-- 查看从服务器状态,语法 SHOW {REPLICA | SLAVE} STATUS;
SHOW REPLICA STATUS\G
我们只看上面那个Replica_IO_Running和Replica_SQL_Running,只有这两个都是Yes才算是成功了。如果有其中一个显示是No,则是失败了。
我们注意两台从节点都必须去查询一下
查看主服务器进程列表
在主服务器上验证从服务器是否连接成功
show processlist;
在从服务器上也可以通过 processlist 命令查看状态
show processlist;
我们看到有4个并行复制的线程
并⾏复制的线程数
查看默认的设复制线程数,也可以根据实际需求使⽤SET语句进⾏调整
show variables like '%replica_parallel_workers%';
3.3.6 测试
在主库中构造数据
首先我们需要在主节点里面构造一些数据
-- 查看服务器ID
SELECT @@server_id;-- 查看所有数据库
SHOW DATABASES;-- 创建数据库
CREATE DATABASE IF NOT EXISTS bit_db CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;-- 选择数据库
USE bit_db;-- 创建表
CREATE TABLE IF NOT EXISTS t_user (id BIGINT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(20) NOT NULL
);-- 查看库中所有的表
SHOW TABLES;-- 写入记录
INSERT INTO t_user (name) VALUES ('张三');-- 写入记录,值为服务器Id(正确引用系统变量)
INSERT INTO t_user (name) VALUES (@@server_id);-- 查询
SELECT * FROM t_user;
从节点1查看
我们来到从节点1看看有没有跟着主节点一起变化
-- 查看服务器ID
SELECT @@server_id;
-- 查看所有数据库,bit_db已同步
show databases;
-- 选择数据库
use bit_db;
-- 查看数据库中所有的表
show tables;
-- 查询记录
select * from t_user;
从节点2查看
我们来到从节点2看看有没有跟着主节点一起变化
-- 查看服务器ID
SELECT @@server_id;
-- 查看所有数据库,bit_db已同步
show databases;
-- 选择数据库
use bit_db;
-- 查看数据库中所有的表
show tables;
-- 查询记录
select * from t_user;
很好啊!!!
到现在,主从复制我们就算是搭建完成了。
3.3.7.常⽤命令
-- 查看已连接到主服务器的小服务器节点,在主服务器执行
SHOW SLAVE HOSTS | SHOW REPLICAS;-- 查看线程列表
SHOW PROCESSLIST;-- 停止从服务器复制功能,在从机上执行 MySQL8.0.22之后使用stop replica;
stop {replica | slave};-- 删除当前从服务器上的relaylog文件,并重新启用新的relaylog文件
reset {replica | slave};-- 删除并重置主服务器上的所有binlog文件和索引,并重新启用新的binlog文件索引
-- 需要主服务器上执行
reset master