MySQL 数据库传统方式部署主从架构的实现很详细
概述(先了解传统的实现在了解docker 和 k8s的部署方式)
文章内容概述
- 案例 MySQL 主从配置架构(重点练习)
- 本人思考的一点问题
- MySQL主从的排错和解决方案
一,主从复制配置部署
环境准备说明
角色 | IP | 主机名 |
主库 | 192.168.1.100 | mysql-master |
从库 | 192.168.1.101 | mysql-slave |
🧱 1. 安装 MySQL(主从都执行)
# 安装 yum 源(以 CentOS 为例)
sudo yum install -y wget
wget https://dev.mysql.com/get/mysql80-community-release-el7-1.noarch.rpm
sudo rpm -ivh mysql80-community-release-el7-1.noarch.rpm
sudo yum install -y mysql-server# 启动并设置开机启动
sudo systemctl start mysqld
sudo systemctl enable mysqld# 获取初始密码
sudo grep 'temporary password' /var/log/mysqld.log # 注意这个只有sentos 有这个文件
# 安装 apt源 (以 ubuntu为例) 如果下面的工具和包都有的话 可以直接使用sudo apt update && apt install mysql-server -y
sudo apt update
sudo apt install -y wget gnupg lsb-release
wget https://dev.mysql.com/get/mysql-apt-config_0.8.29-1_all.deb
sudo dpkg -i mysql-apt-config_0.8.29-1_all.deb
sudo apt update
sudo apt install -y mysql-server
sudo systemctl start mysql
sudo systemctl enable mysql
sudo mysql_secure_installation # 操作系统初始化
注意:::生产环境时是需要 初始化的
🏗️ 2. 配置主库 my.cnf
#ubuntu 是 /etc/mysql/mysql.conf.d/mysqld.cnf
sudo vim /etc/my.cnf
添加如下配置:
[mysqld]
bind-address = 0.0.0.0 #生产环境要注意了,还要做一些安全配置:
server-id=1 # 用于标识 主节点 还是 从节点 注意主从的server-id 的值绝对不能相同。
log-bin=mysql-bin #binlog日志(log-bin) 的日志前缀 注意这个配置完成后 MySQL 的 /var/lib/mysql 下面会生成名为mysql-bin.000001的二进制文件
binlog_format=ROW #逐行复制主从服务
# 开启 GTID 模式(推荐)
gtid_mode=ON #开启主从服务::
enforce_gtid_consistency=ON #
然后重启服务:
sudo systemctl restart mysqld
🧑🔧 3. 主库创建复制用户
-- 登录主库
mysql -uroot -p-- 创建复制用户(强烈建议使用强密码)创建一个 repl用户只允许来自 192.168.1.0/24(%) 网段连接 是 设置密码 repl123!
CREATE USER 'repl'@'192.168.1.%' IDENTIFIED BY 'repl123!';授予从库可以到主库 复制的命令的权限 ,所有库所有表。。。
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.1.%';
FLUSH PRIVILEGES;-- 查看当前二进制日志信息(用于传统复制,不是 GTID)
SHOW MASTER STATUS;-- 或查看 GTID 状态(用于 GTID 模式复制)
SHOW GLOBAL VARIABLES LIKE 'gtid_mode';
🛠️ 4. 配置从库 my.cnf
sudo vim /etc/my.cnf
添加:
[mysqld]
server-id=2 # 不能和主重复
relay_log=relay-log #中继日志的文件前缀 他是和主的binlog进行配合的日志(其实我理解的他们都是二进制日志的存储日志) 通常是 /var/lib/mysql/
log_bin=mysql-slave-bin #从库生成自己的 binlog 是在从库上开启 binlog 功能的配置,常用于支持级联复制、GTID 主从切换、主从对等转换等场景,是从库“升级为主库”的基础前提
gtid_mode=ON # gtid 开启
enforce_gtid_consistency=ON
重启:
sudo systemctl restart mysqld
🔄 5. 配置从库复制主库
-- 登录从库
mysql -uroot -p-- 停止已有复制(如果配置过)
STOP SLAVE;-- 配置复制
CHANGE MASTER TOMASTER_HOST='192.168.1.100',MASTER_PORT=3306,MASTER_USER='repl',MASTER_PASSWORD='repl123!',MASTER_AUTO_POSITION=1; -- GTID 必须配置:告诉从库:使用 GTID 模式来自动定位主库同步点,不再使用 binlog 文件名 + 位置(file + pos)来定位复制位置。解释!!!
注意: 使用 MASTER_AUTO_POSITION=1 的前提条件
条件 要求
主从都启用了 GTID gtid_mode=ON,enforce_gtid_consistency=ON
主库开启了 binlog log_bin=xxx
从库开启了 log_bin + log_slave_updates(建议) 便于主从切换
复制账号权限正确 REPLICATION SLAVE 权限
主从 server-id 不一样 否则冲突
MASTER_AUTO_POSITION=1 是 GTID 模式复制的标志性配置,它告诉从库“自动根据 GTID 接着复制”,省去了手动指定位置的麻烦。
必须为 1,才能启用
不用再配置 binlog 文件名和位置(file/pos)是高可用复制和自动故障切换的基础设置之一-- 启动复制
START SLAVE;-- 查看复制状态
SHOW SLAVE STATUS\G
🔍 重点关注字段:
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
只要这两个都是 Yes,就表示主从复制成功 ✅
📌 补充建议
项目 | 建议 |
防火墙 | 开放 3306 端口(主库必须对从库可访问) |
SELinux | 测试环境建议关闭 |
主从一致性检查 | 可以使用 工具 |
数据初始化 | 大数据量建议用 |
🧪 测试主从是否同步
在主库执行:
CREATE DATABASE test_db;
USE test_db;
CREATE TABLE users (id INT PRIMARY KEY, name VARCHAR(50));
INSERT INTO users VALUES (1, '张三');
在从库:
USE test_db;
SELECT * FROM users;
看到数据说明同步成功!
二,个人问题:
我有几个问题
1,为什么要从新获取 MySQL 的安装包 用 yum 中自带的不可以吗 (太老)
2,msyql 一定要获取密码登录吗,不可以用mysql -u 直接登录吗 (不能)
3,sudo grep 'temporary password' /var/log/mysqld.log 这种获取密码登录 默认是用root 登录的吗 ?(是的)
1. 为什么要重新获取 MySQL 安装包?不能用 yum
自带的吗?
总结:自带的太老,可能和环境不太匹配
✅ 回答:
默认 yum
源(比如 CentOS 自带的 base)里的 MySQL 版本比较旧(比如 5.7、5.6),不一定适配你当前环境需求。
🔧 具体情况说明:
- 默认源:
yum list | grep mysql
可能只显示 mysql-libs
、mariadb
(不是官方MySQL!)
- 通过添加官方源:
wget https://dev.mysql.com/get/mysql80-community-release-el7-1.noarch.rpm
rpm -ivh mysql80-community-release-el7-1.noarch.rpm
这样可以获得:
-
- 最新的 MySQL 8.0.x
- 自动拉取依赖
- 长期更新支持(适合生产)
🧠 建议:
测试环境可以临时用 yum
默认的;但正式部署一定推荐用官方源或 tar.gz
二进制包部署,这样版本、配置可控。
🔍 2. MySQL 一定要获取密码登录吗?不能 mysql -u root
就登录吗?
注意 :这个问题 只有 sentos 才有/var/log/mysqld.log 文件 去读取 初始密码
ubuntu 是没有的但是 ubuntu的mysql安装包 安装完成 是可以直接 mysql 登录的(因为他设置auth_sokect )不需要密码 但是两种系统化再生产环境时都需要 初始化!!! 操作才行。
回答:
默认情况 是需要密码的,不能直接 mysql -u root
登录,尤其是在 MySQL 5.7 及以后版本。
🔐 原因说明:
- 从 MySQL 5.7 开始,安装后会自动生成一个 root 初始密码,为了安全。
- 必须通过
grep 'temporary password'
去/var/log/mysqld.log
读取这个初始密码。 - 登录后系统会强制你修改密码(否则无法执行任何命令)。
🎯 示例:
mysql -uroot
# 会报错:ERROR 1045 (28000): Access denied for user 'root'@'localhost'...
🔍 3. grep 'temporary password'
查到的密码是哪个用户的?默认是 root 吗?
✅ 回答:
是的,查到的临时密码是 root@localhost
的初始登录密码。
示例输出:
2025-06-29T08:31:23.123456Z 1 [Note] A temporary password is generated for root@localhost: 9fE>mhU8#aVz
✔️ 说明:
- 这是 MySQL 安装完成时自动生成的 root 账户密码。
- 登录后你需要执行:
ALTER USER 'root'@'localhost' IDENTIFIED BY '你的新密码';
🚀 补充建议(实战角度):
项目 | 建议 |
安装方式 | 正式环境可考虑用二进制方式部署(更干净更灵活),你会学到很多系统知识 |
密码管理 | 建议用密码保存在运维自动化工具(如 Ansible Vault 或 secrets)中 |
提权方式 | 有时候 root@localhost 不能远程连接,要用 或特定 IP 授权访问 |
问题四
没明白 读写分离不应该 是一个读一个写吗,我们说 msyql 从库 是用来读的 ,主库是用来写的 那么 我们是 让后端程序 访问 从库对吗
总结:MySQL的主从复制的原理:是满足了 1,读写分离 2,主从复制 数据备份 3,高可用
他是由 开发编写的 连接主还是从 ------
操作场景 | 访问哪个库? | 原因 |
查询历史列表、公共数据 | 从库 | 读压力大,数据同步慢无所谓 |
提交表单后立即查询、个人资料等 | 主库 | 避免主从延迟引发数据不一致 |
写操作 | 主库 | 只能写主库(主从复制是单向的) |
问题核心是:
“读写分离是不是就是让后端程序访问从库来读,访问主库来写?”
答案是:**是的,本质上就是这样!**但实现上有一些“套路”我们来细说:
📌 一句话解释什么是读写分离
👉 后端程序中的读操作(SELECT)发往从库,写操作(INSERT/UPDATE/DELETE)发往主库。
为什么要这么做?为的是减轻主库压力,提升系统整体性能。
✅ 那谁来判断“读”和“写”呢?
有三种选择:
实现方式 | 谁判断 SQL 是读还是写? |
方式一:程序代码自己分流 | 程序员自己判断,写操作用主库连接,读操作用从库连接 |
方式二:中间件分流 | 中间件自动判断,例如 ProxySQL、MyCat |
方式三:ORM 框架支持 | 框架帮你判断,如 MyBatis-Plus、ShardingSphere |
💡 举个最简单的例子(程序员自己判断方式):
# 假设你有两个连接:一个连主库,一个连从库
conn_master = connect(host="主库IP", user="xxx", ...)
conn_slave = connect(host="从库IP", user="xxx", ...)# 写入数据:走主库
cursor = conn_master.cursor()
cursor.execute("INSERT INTO users(name) VALUES ('白先生')")# 读取数据:走从库
cursor = conn_slave.cursor()
cursor.execute("SELECT * FROM users")
就是这么简单!
你可以在程序里封装一下,用统一接口判断是否是读或写,内部自动选择库连接。
🧠 那么问题来了:是不是所有读操作都可以走从库呢?
❗不是的,有例外!最典型的:
1. 用户刚提交表单(INSERT)
2. 页面立刻跳转查询用户数据(SELECT)
如果这时从库还没同步完数据,用户看到的就是“旧数据”或“查无此人”。
✅ 所以实际中会这样分流:
操作场景 | 访问哪个库? | 原因 |
查询历史列表、公共数据 | 从库 | 读压力大,数据同步慢无所谓 |
提交表单后立即查询、个人资料等 | 主库 | 避免主从延迟引发数据不一致 |
写操作 | 主库 | 只能写主库(主从复制是单向的) |
读写分离就是:
- 主库负责写
- 从库负责读
- 程序(或中间件)决定 SQL 该走哪台机器
问题四:从库是怎么 在主库获取信息的
一句话总结:
从库通过网络连接主库的 MySQL 协议
接口,用专用的复制账号(如 repl),拉取主库的 binlog(事务日志)来同步数据。
就是这句话的作用
CHANGE MASTER TO MASTER_HOST='主库IP', MASTER_USER='repl', MASTER_PASSWORD='xxx', MASTER_AUTO_POSITION=1;
✅ 详细过程分解(关键点 + 技术细节)
我们从「谁干了什么」的角度讲清楚 👇
✅ 第一步:从库发起连接主库
从库的 IO 线程⤷ 使用账号:'repl'@'主库IP'⤷ 使用命令:COM_BINLOG_DUMP(MySQL 协议内的指令)⤷ 发起 TCP 连接 到主库的 3306 端口
📌 这个连接行为相当于:
CHANGE MASTER TO MASTER_HOST='主库IP', MASTER_USER='repl', MASTER_PASSWORD='xxx', MASTER_AUTO_POSITION=1;
✅ 如果使用 GTID,同步点是“从库本地已执行的 GTID”
❌ 如果用传统复制,需要指定 binlog 文件名和位置
✅ 第二步:主库授权验证,确认可以复制
主库检查:
mysql.user
表中是否有'repl'@'从库IP'
- 是否具有
REPLICATION SLAVE
权限 - 是否允许连接(例如防火墙、bind-address 配置)
验证通过后,主库就开始 发送 binlog 日志流
✅ 第三步:主库发送 binlog 数据包
主库将 binlog 内容以 网络数据包形式(通过 MySQL 协议)发送给从库的 IO 线程。
例如:
INSERT INTO users(name) VALUES ('白先生');
对应 binlog event 会被“打包发送”给从库。
✅ 第四步:从库 IO 线程写入中继日志(relay log)
从库本地会生成:
- relay-log.000001
- relay-log.000002
这些是 binlog 的本地副本,中继日志(relay log),方便断点续传和故障恢复。
✅ 第五步:SQL 线程读取 relay log,执行
从库的 SQL 线程会解析 relay log 中的事件,把里面的操作在从库本地一条条重放出来,变成从库的真实数据。
📌 相当于“主库执行过的操作,我在从库也执行一遍”,保持数据一致 ✅
🧠 补充知识点
项目 | 说明 |
binlog 格式 |
(推荐), , |
GTID 复制 | 从库根据 GTID 自动判断从哪开始同步 |
网络协议 | 基于 MySQL 原生协议的 COM_BINLOG_DUMP / DUMP_GTID |
延迟查看 |
查看主从同步延迟 |
文件查看 |
可以查看 relay log 内容 |
✅ 主从复制示意图:
(写操作)
客户端 ─────> 主库(写入 binlog)│┌────────────┘▼从库 IO 线程│ 拉取 binlog▼relay log(本地副本)│▼SQL 线程 读取并执行│▼数据同步完成!
🛠 总结:
步骤 | 描述 |
1. 建立连接 | 从库用 指定主库、账号 |
2. 授权验证 | 主库验证复制账号的权限 |
3. 拉取 binlog | 主库将 binlog 实时推送给从库 |
4. 写入 relay log | 从库 IO 线程保存为本地中继日志 |
5. 执行 relay log | SQL 线程重放日志,实现同步 |
问题五 MySQL初始化 初始了什么东西
初始化 都完成了那些操作。我不进行初始化直接 用alter 命令修改 root 密码直接使用可以吗
🎯 问题回顾
Ubuntu 安装 MySQL 后,不运行 mysql_secure_installation
,直接使用 ALTER USER
来修改 root 密码,这样可以吗?会不会有问题?
完全没问题!
你可以跳过 mysql_secure_installation
,直接使用 ALTER USER
修改 root 密码并生效使用。
🔍 但重点在于:你还缺少了一些安全初始化工作!
我们来详细看看:
🧱 一、mysql_secure_installation
这个命令都做了什么?
它不是必须的,但做了很多安全方面的“善后处理”,包括:
步骤 | 功能 | 建议 |
✔ 设置 root 密码 | 如果没设置 | 强烈推荐 |
❌ 移除匿名用户 | 关闭匿名访问 | 安全考虑必须做 ✅ |
❌ 禁止 root 远程登录 | 关闭远程 root | 非必要建议关闭 |
❌ 删除测试数据库 | 删除 test 数据库 | 没用可以删掉 |
✔ 刷新权限表 | 应用以上修改 | 必须做 ✅ |
✅ 所以,如果你直接用 ALTER USER
修改密码:
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'YourPassword123!';
FLUSH PRIVILEGES;
你只是完成了 “设置密码” 这一步 ✅
🧠 二、那是否建议直接改密码而跳过初始化?
✅ 开发/测试环境:
- 直接用
ALTER USER
没问题 - 甚至可以不设密码,用
auth_socket
登录更方便
❗ 生产环境(强烈建议):
- 🔒 一定要执行
mysql_secure_installation
- 防止被匿名用户登录、root 被远程爆破、test 数据库泄漏等问题
- 它其实是“安全初始化向导”,不是功能必须,但安全必须
🧪 三、最佳实践推荐操作流程(Ubuntu 安装后)
# 1. 登录数据库(当前是 root 用户,可以免密)
sudo mysql# 2. 改 root 密码 + 切换认证方式
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'YourStrongPass!';FLUSH PRIVILEGES;
exit;# 3. 启动安全初始化流程(建议!)
sudo mysql_secure_installation
# 对匿名用户、远程 root、test 库一键清理
📌 总结一句话:
直接用 ALTER USER
改密码是没问题的 ✅,但你跳过了 mysql_secure_installation
的安全优化步骤,在生产环境中还是建议执行一下
三,排错和解决方案
🛠️ MySQL 主从复制故障排查清单(错误 → 原因 → 解决方法)
错误/症状 | 可能原因 | 解决方法 |
❌ | 没有授权从库 IP 或 用户不存在 | ✅ 在主库上执行:
|
❌ 从库连接主库失败, | 主库未监听外网(bind-address设置不对) | ✅ 修改主库配置:
|
❌ 无法连接主库(端口被拒绝) | 主库的防火墙未开放 3306 端口 | ✅ 执行防火墙命令: (Ubuntu) (CentOS) |
❌ 中:
|
用户密码错误或无权限 | ✅ 确保 中的密码正确 |
❌ 且有 错误 | 主从数据不一致 | ✅ 使用 暂时跳过 |
❌ | 从库指定的 binlog 文件不存在或已被主库清理 | ✅ 使用新的 + 重新配置 同步后重新开始复制 |
❌ | 主库和从库的 相同 | ✅ 修改从库配置文件: (必须唯一) |
❌ 主库未开启 binlog,无法同步 | 主库未配置 | ✅ 修改主库配置:
|
❌ 从库无法获取主库 GTID 信息 | 主库未启用 | ✅ 主库开启:
|
❌ |
损坏或权限问题 | ✅ 停止复制:
文件后再 |
✅ 附加建议(持续监控 + 守护)
工具 | 用途 | 建议 |
| 查看主从复制状态 | 经常用来看 / 状态 |
Zabbix / Prometheus | 监控主从复制延迟与状态 | 使用 指标预警 |
shell 脚本守护进程 | 自动检测复制异常并发邮件/钉钉告警 | 定期运行 `show slave status\G |
🧩 提示:主从复制健康状态检查三项核心指标
项目 | 理想状态 |
| Yes ✅ |
| Yes ✅ |
| 0 或接近 0 ✅(否则是延迟) |