MySQL 数据库传统方式部署主从架构的实现很详细

概述(先了解传统的实现在了解docker 和 k8s的部署方式)

文章内容概述

  • 案例 MySQL 主从配置架构(重点练习)
  • 本人思考的一点问题
  • MySQL主从的排错和解决方案

一,主从复制配置部署

环境准备说明

|----|---------------|--------------|
| 角色 | IP | 主机名 |
| 主库 | 192.168.1.100 | mysql-master |
| 从库 | 192.168.1.101 | mysql-slave |


🧱 1. 安装 MySQL(主从都执行)

bash 复制代码
# 安装 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 有这个文件
bash 复制代码
# 安装 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

bash 复制代码
#ubuntu 是 /etc/mysql/mysql.conf.d/mysqld.cnf
sudo vim /etc/my.cnf 

添加如下配置:

bash 复制代码
[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. 主库创建复制用户

bash 复制代码
-- 登录主库
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. 配置从库复制主库

bash 复制代码
-- 登录从库
mysql -uroot -p

-- 停止已有复制(如果配置过)
STOP SLAVE;

-- 配置复制
CHANGE MASTER TO
  MASTER_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 | 测试环境建议关闭 setenforce 0 |
| 主从一致性检查 | 可以使用 pt-table-checksum 工具 |
| 数据初始化 | 大数据量建议用 mysqldump + --set-gtid-purged=ON |


🧪 测试主从是否同步

在主库执行:

复制代码
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-libsmariadb(不是官方MySQL!)

这样可以获得:

    • 最新的 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 格式 | ROW (推荐),STATEMENTMIXED |
| GTID 复制 | 从库根据 GTID 自动判断从哪开始同步 |
| 网络协议 | 基于 MySQL 原生协议的 COM_BINLOG_DUMP / DUMP_GTID |
| 延迟查看 | Seconds_Behind_Master 查看主从同步延迟 |
| 文件查看 | SHOW RELAYLOG EVENTS; 可以查看 relay log 内容 |


✅ 主从复制示意图:

复制代码
             (写操作)
客户端  ─────> 主库(写入 binlog)
                    │
        ┌────────────┘
        ▼
     从库 IO 线程
        │ 拉取 binlog
        ▼
     relay log(本地副本)
        │
        ▼
     SQL 线程 读取并执行
        │
        ▼
     数据同步完成!

🛠 总结:

|-----------------|--------------------------------|
| 步骤 | 描述 |
| 1. 建立连接 | 从库用 CHANGE MASTER TO 指定主库、账号 |
| 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 主从复制故障排查清单(错误 → 原因 → 解决方法)

|---------------------------------------------------------------------------------------------------------------|---------------------------|---------------------------------------------------------------------------------------------------------------------------------------|
| 错误/症状 | 可能原因 | 解决方法 |
| ❌ ERROR 1130 (HY000): Host 'xxx' is not allowed to connect to this MySQL server | 没有授权从库 IP 或 GRANT 用户不存在 | ✅ 在主库上执行: CREATE USER 'repl'@'从库IP' IDENTIFIED BY 'repl123'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'从库IP'; FLUSH PRIVILEGES; |
| ❌ 从库连接主库失败,ERROR 2003 (HY000): Can't connect to MySQL server on '主库IP' | 主库未监听外网(bind-address设置不对) | ✅ 修改主库配置:bind-address = 0.0.0.0 重启服务后再测试连接 |
| ❌ 无法连接主库(端口被拒绝) | 主库的防火墙未开放 3306 端口 | ✅ 执行防火墙命令: sudo ufw allow 3306 (Ubuntu) firewall-cmd --add-port=3306/tcp --permanent && firewall-cmd --reload (CentOS) |
| ❌ SHOW SLAVE STATUS\G 中: Slave_IO_Running: No Last_IO_Error: ERROR: Access denied for user 'repl'@'xxx' | repl 用户密码错误或无权限 | ✅ 确保 CHANGE MASTER TO 中的密码正确 ✅ 重新授权 repl 用户 |
| ❌ Slave_SQL_Running: No 且有 Duplicate entry 错误 | 主从数据不一致 | ✅ 使用 SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1; START SLAVE; 暂时跳过 ⚠️ 推荐重新同步主从数据 |
| ❌ Got fatal error 1236: "Could not find first log file name in binary log index file" | 从库指定的 binlog 文件不存在或已被主库清理 | ✅ 使用新的 MASTER_LOG_FILE + MASTER_LOG_POS 重新配置 或用 mysqldump 同步后重新开始复制 |
| ❌ Server id conflicts | 主库和从库的 server-id 相同 | ✅ 修改从库配置文件: server-id = 2 (必须唯一) 然后重启服务 |
| ❌ 主库未开启 binlog,无法同步 | 主库未配置 log-bin | ✅ 修改主库配置: log-bin = mysql-bin + server-id = 1 重启服务 |
| ❌ 从库无法获取主库 GTID 信息 | 主库未启用 gtid_mode | ✅ 主库开启: gtid_mode = ON enforce-gtid-consistency = ON 重启服务 |
| ❌ ERROR 1201: Could not initialize master info structure | relay-log 损坏或权限问题 | ✅ 停止复制:STOP SLAVE; 删除 relay-log* 文件后再 START SLAVE; |


✅ 附加建议(持续监控 + 守护)

|-----------------------|-------------------|---------------------------------------------------|
| 工具 | 用途 | 建议 |
| SHOW SLAVE STATUS\G | 查看主从复制状态 | 经常用来看 Slave_IO_Running / Slave_SQL_Running 状态 |
| Zabbix / Prometheus | 监控主从复制延迟与状态 | 使用 Seconds_Behind_Master 指标预警 |
| shell 脚本守护进程 | 自动检测复制异常并发邮件/钉钉告警 | 定期运行 `show slave status\G |


🧩 提示:主从复制健康状态检查三项核心指标

|-------------------------|------------------|
| 项目 | 理想状态 |
| Slave_IO_Running | Yes ✅ |
| Slave_SQL_Running | Yes ✅ |
| Seconds_Behind_Master | 0 或接近 0 ✅(否则是延迟) |