news 2026/9/24 19:38:15

银河麒麟V10上安装MySQL与主从复制完整实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
银河麒麟V10上安装MySQL与主从复制完整实践

银河麒麟V10 桌面版上装 MySQL 这件事,最近被好多同事问过。业务方指定数据库必须是 MySQL,而且要主从复制,单独拆开都不复杂,但放到国产 Linux 系统上,坑一个接一个。这篇文章把我从下载安装包到主从复制跑通的完整过程记录下来,命令直接抄,配置直接复制,只要你环境的 CPU 架构和系统版本跟文中一致,基本能一次跑通。

文中的方法不依赖你机器能不能访问外网——只要你能把官网的通用二进制包拷进内网,离线一样能装。对于银河麒麟V10 这种系统源里没有官方 mysql-server 包的环境,这是目前最省心、最可控的一条路。

1. 为什么在银河麒麟V10上装MySQL要先解决“源”的问题

很多人在国产系统上装软件,第一反应就是apt install。但银河麒麟V10 的默认软件源里,mysql-server这个包是不存在的,有的只是mariadb-server。MariaDB 虽然是 MySQL 的分支,但业务方如果明确要求“必须官方 MySQL”,你用 MariaDB 顶上后面解释成本很高;而且有些运维脚本、备份工具、集群方案对 MySQL 官方版本有依赖,混着用很容易出幺蛾子。

另一个常用办法是添加 MySQL 官方 APT 源。MySQL 官网确实提供了mysql-apt-config这种仓库配置包,但它在麒麟系统上能不能顺利装上,完全随缘。我这里遇到过两个典型问题:一是仓库签名校验失败,二是依赖解析冲突。尤其 arm64 架构(飞腾、鲲鹏)的机器,官方 APT 源经常连二进制都找不到。如果你刚好拿到一台基于 Debian 系的 V10 变体,问题会更明显。

所以我的建议很直接:放弃 apt 这条路,用 MySQL 官方针对 Linux 发布的通用二进制包。这个包不依赖系统源,glibc 2.17 以上就能跑,x86_64 和 aarch64 都有对应版本,安装方式就是解压、初始化、配置、启动。它唯一的缺点是初始化、配 systemd 这些事得手动做,但这篇文章就是干这个的。

在动手之前,建议先花二十秒确认两件事:

cat /etc/os-release uname -m

第一个命令看系统基于什么发行版,第二个看 CPU 架构。uname -m输出x86_64就用 x86_64 的包,输出aarch64就用 aarch64 的包,这个千万别搞错,否则会直接提示 Illegal instruction 或者无法执行。常见情况是银河麒麟桌面版 V10 基于 Ubuntu 20.04 或 Debian 系列,但这不影响我们用通用二进制包的方案。

三种安装方式的对比,我简单列过一张表:

安装方式优点缺点适用场景
apt install mariadb-server命令短,装完就能跑不是官方 MySQL,版本和目录结构有差异不挑数据库实现,只求能用
MySQL 官方 APT 仓库自动处理依赖和升级麒麟源兼容性差,arm64 基本没戏基于 Ubuntu 且 x86_64,运气好才顺利
官方通用二进制包不依赖系统源,架构全,支持离线需要手动初始化和配置服务几乎所有场景,特别是内网离线机

我自己现在不管在麒麟、统信 UOS 还是纯 Ubuntu 上装 MySQL,都默认用通用二进制包。这套流程练熟了,换任何 Linux 发行版都是同一套操作,不用每次去研究那个发行版的源里有没有 mysql。

2. 二进制包安装MySQL的完整落地步骤

2.1 下载、解压与目录规划

去 MySQL 官网的 Downloads 页面,选择 MySQL Community Server,然后选 Linux - Generic。官网会提供 tar.xz 压缩包,文件名类似:

mysql-8.0.40-linux-glibc2.17-x86_64.tar.xz mysql-8.0.40-linux-glibc2.17-aarch64.tar.xz

下载之前注意一下 glibc 版本需求。最常见的通用包需要 glibc 2.17+,银河麒麟V10 基本都满足。如果真的在很老的系统上碰到version 'GLIBC_2.XX' not found,那就得换低版本 MySQL 或者用该发行版自带的 MariaDB,但我实际遇到这种情况的概率很低。

把包放到/opt目录下解压:

cd /opt tar -xJf mysql-8.0.40-linux-glibc2.17-x86_64.tar.xz mv mysql-8.0.40-linux-glibc2.17-x86_64 /usr/local/mysql

我习惯把 MySQL 固定放在/usr/local/mysql,然后通过软链或者 PATH 环境变量来调用。这样后续升级时只需要替换目录内容,业务路径不用变。如果你机器上/usr/local空间不够,放/opt/mysql也完全可以,但后面所有命令里的/usr/local/mysql都要对应改。

接着创建 mysql 系统用户和数据目录:

groupadd mysql useradd -r -g mysql -s /bin/false mysql mkdir -p /data/mysql chown -R mysql:mysql /data/mysql

数据目录我没有用默认的/var/lib/mysql,而是单独放在/data/mysql。原因很简单:把数据目录独立出来,方便单独挂载数据盘、做快照、扩容。万一系统盘满了或者系统重装,数据目录还在,恢复成本低很多。

2.2 先写一份实用的 /etc/my.cnf

很多教程是先初始化、再写配置,但我建议反过来。初始化数据目录的时候 mysqld 会读取配置文件里的字符集、排序规则这些参数,如果先初始化再改配置,你可能需要重建数据目录才能让字符集改动完全生效。

创建/etc/my.cnf,内容如下:

[mysqld] basedir=/usr/local/mysql datadir=/data/mysql port=3306 socket=/tmp/mysql.sock pid-file=/data/mysql/mysql.pid # 复制相关(先开好,后面不用返工) server-id=1 log-bin=mysql-bin binlog-format=ROW binlog-expire-log-seconds=604800 # 字符集与时区 character-set-server=utf8mb4 collation-server=utf8mb4_0900_ai_ci default-time-zone='+08:00' # 连接设置 bind-address=0.0.0.0 skip-name-resolve max_connections=1000 [client] port=3306 socket=/tmp/mysql.sock default-character-set=utf8mb4

这里有几个参数我先解释一下,后面基础配置章节还会细说:

  • server-id=1log-bin=mysql-bin是主从复制的命根子,主库必须开,从库作为主库的备份机可开可不开,但为了以后主从切换方便,建议都开。
  • binlog-format=ROW是我比较推荐的格式,数据一致性最好。虽然日志量比 STATEMENT 大,但现代磁盘和网络基本不在乎这点开销。
  • bind-address=0.0.0.0表示监听所有网卡,主从复制场景必须这么配,否则从库连不上主库。如果 MySQL 和应用在同一台机器,只想本机访问,可以改成127.0.0.1,但主从复制时这句别这样写。

写完后再把目录属主确认一次:

chown -R mysql:mysql /data/mysql

2.3 初始化数据目录,拿到 root 临时密码

执行初始化命令:

/usr/local/mysql/bin/mysqld --initialize --user=mysql --basedir=/usr/local/mysql --datadir=/data/mysql

--initialize会让 mysqld 帮你建好全新的数据目录,包括 mysql 系统库。初始化完成后,日志里会打印一行 root 临时密码:

[Note] A temporary password is generated for root@localhost: 8HkLp2!x9F

把这串临时密码记下来,后面首次登录要用。如果屏幕上没看到,就去数据目录下的.err文件里找:

grep 'temporary password' /data/mysql/mysql.err

注意.err文件具体名字和你的主机名相关,也可以直接ls -l /data/mysql/*.err查看。

很多朋友在这里会踩坑:初始化没报错,但启动服务的时候报[ERROR] --initialize specified but data directory exists。这是因为你之前手动执行过初始化,或者datadir目录里已经生成了空文件。解决方法是把/data/mysql清空(确保里面没有重要数据)再重新初始化。

2.4 注册 systemd 服务并设置开机自启

mysqld 自带 mysqld_safe 方式,但桌面版系统我更推荐注册成 systemd 服务,开机自启、日志管理都方便。

创建/etc/systemd/system/mysqld.service

[Unit] Description=MySQL Server After=network.target [Service] User=mysql Group=mysql Type=simple ExecStart=/usr/local/mysql/bin/mysqld --defaults-file=/etc/my.cnf LimitNOFILE=65535 [Install] WantedBy=multi-user.target

然后执行:

systemctl daemon-reload systemctl enable mysqld systemctl start mysqld systemctl status mysqld

注意 service 里User=mysql很重要,mysqld 不允许用 root 身份直接跑,如果你不带--user=mysql参数启动,它会自己切到 mysql 用户,但权限配置不对反而容易出问题。显式指定用户是更稳的做法。

启动后再确认一下 3306 端口在监听:

ss -lntp | grep 3306

看到LISTEN 0 128 0.0.0.0:3306就说明服务起来了。

2.5 首次登录改密码与安全加固

用刚才记下的临时密码登录:

/usr/local/mysql/bin/mysql -uroot -p

登录后第一件事改密码,MySQL 8 要求密码不能太弱,至少 8 位并包含大小写字母、数字和特殊字符:

ALTER USER 'root'@'localhost' IDENTIFIED BY 'Root@2024Strong';

然后建议把 mysql 命令加入 PATH,后面用起来方便:

echo 'export PATH=/usr/local/mysql/bin:$PATH' > /etc/profile.d/mysql.sh source /etc/profile.d/mysql.sh

之后直接敲mysql -uroot -p就能进客户端。

安全加固方面,官方提供了一条交互命令mysql_secure_installation。执行后它会依次问你是否设置密码校验强度、是否移除匿名用户、是否禁用 root 远程登录、是否删除 test 库、是否刷新权限。我的建议是:匿名用户删掉,test 库删掉,root 远程登录禁止,密码校验强度看场景。如果是内网测试环境,密码校验强度可以选低一点,否则你后面建业务账号时随便一个强度不够的密码都会被拒。

3. 基础配置不只是“能连上就行”,这些参数直接影响复制

3.1 端口、监听地址与数据目录

port=3306是 MySQL 默认端口,一般不用改。如果 3306 被别的程序占了,可以换,但改端口意味着所有客户端连接串、防火墙规则、从库的 MASTER_PORT 都要跟着改,没必要就别动。

bind-address=0.0.0.0放开了所有网卡监听。这里有个安全权衡:如果 MySQL 只给本机应用用,127.0.0.1确实更安全;但只要你有主从复制的需求,就必须允许主库被从库访问,这种情况下稳妥做法不是把 bind-address 改成具体 IP,而是先把 MySQL 的账号权限控制好,再从防火墙层面放行指定来源 IP 的 3306 端口。顺序不能反——你先把账号建得乱七八糟,再把端口全放开,那跟裸奔没区别。

还有一个容易忽略的参数是skip-networking。这个参数一旦开启,MySQL 就只监听 unix socket,所有 TCP 连接全部失效。网上很多配置文件模板里会加它做安全优化,但主从复制场景下千万别开。我排查过好几次从库连不上主库的问题,最后发现是某个调优脚本把这个参数加进去了。

3.2 字符集和时区必须落地

字符集用utf8mb4,不要用utf8。MySQL 的utf8实际上是 utf8mb3,最多只能存 3 字节,像 emoji 和一些生僻汉字存不进去,会报Incorrect string value。而utf8mb4是完整的四字节 UTF-8,也是 MySQL 8.0 的默认字符集。

排序规则utf8mb4_0900_ai_ci是 MySQL 8.0 新增的,支持 Unicode 9.0,性能也更好。如果你之后要从 MySQL 5.7 迁移数据,或者和 5.7 实例做主从,建议排序规则统一用utf8mb4_general_ci,兼容性更稳。但如果你都是 8.0 实例,直接用utf8mb4_0900_ai_ci没问题。

时区必须显式设置。很多机器系统时区是 CST(China Standard Time),但 MySQL 的system_time_zone可能不一定是 +08:00。如果你不设置default-time-zone,timestamp 类型的字段存储和展示可能出现 8 小时偏差。在/etc/my.cnf里写死:

default-time-zone='+08:00'

也可以写成default-time-zone='Asia/Shanghai',但前提是 MySQL 的时区表已经加载。用+08:00这种偏移量写法最不容易出问题,不依赖时区表。

3.3 先把 binlog 和 server-id 开对,后面复制才不用返工

主从复制的核心就是 binlog,所以从一开始就要把它配置好。log-bin=mysql-bin开启 binlog 后,主库每次数据变更都会写一份二进制日志,从库就是靠拉取这份日志来同步的。

server-id用于标识每台 MySQL 实例的全局唯一 ID。一个复制环里每个实例的 server-id 必须不同,否则从库会分不清日志从哪来。我见过有人图省事,主库从库全用默认的server-id=1,结果 IO 线程一直报错,还以为是网络问题。所以从库的 server-id 一定改成别的数字,比如 2。

binlog-format=ROW是复制时的日志格式。ROW 格式记录的是“哪张表的哪一行的字段从什么值变成了什么值”,比 STATEMENT 格式只记录 SQL 语句要更精确。缺点是 binlog 体积变大、占用磁盘,不过对于现在的机器来说都可以接受。混合模式MIXED是折中,但既然 8.0 已经对 ROW 格式做了很多优化,我倾向于直接用 ROW,省得后面遇到触发器、存储过程复制不一致的诡异问题。

binlog 清理策略我习惯用binlog-expire-log-seconds=604800,代表 7 天。这个值不要太短,尤其主从场景,如果从库因为网络故障断了一两天再恢复,binlog 已经过期被清了,那从库就只能重新做全量备份恢复,非常麻烦。

3.4 连接权限、防火墙和 DNS 解析的关系

建业务账号时,我强烈建议按最小权限来。比如业务需要读写某个库,就只授权那个库:

CREATE USER 'app_user'@'192.168.1.%' IDENTIFIED BY 'App@2024'; GRANT SELECT, INSERT, UPDATE, DELETE ON mydb.* TO 'app_user'@'192.168.1.%';

这里把host字段限制到内网网段192.168.1.%,比%安全得多。%是所有主机都可以连接,生产环境慎用。

skip-name-resolve我默认打开。它让 MySQL 不再对客户端 IP 做反向 DNS 解析,能明显减少连接耗时。但副作用是,MySQL 里的账号 host 字段只能写 IP 或%,不能写主机名。很多人打开了这个参数后,发现原来用'user'@'localhost'本地登录没问题,但用'user'@'myhostname'连不上,就是这个原因。我的建议是:统一用 IP 规划账号,别混用主机名。

防火墙是主从复制最容易忽略的一环。麒麟桌面版可能没开防火墙,但如果你之前手动开过 firewalld 或者 iptables,得先把 3306 放行。firewalld 下:

firewall-cmd --zone=public --add-port=3306/tcp --permanent firewall-cmd --reload

如果用的是 ufw:

ufw allow 3306/tcp

检查防火墙规则的命令是:

firewall-cmd --list-all

排查的时候最直接的办法是,从库上执行telnet 主库IP 3306,如果能通,说明网络和防火墙没问题;如果超时,问题基本就在防火墙或者云平台安全组上。

4. 主从复制的完整配置流程

4.1 复制链路怎么跑起来的

先花一分钟把复制原理讲清楚,后面排错会顺很多。主库上所有数据变更会按顺序写入 binlog,从库上有两个线程在后台工作:IO 线程负责连接主库,把主库 binlog 里的内容拉到从库,写到从本地的中继日志 relay log;SQL 线程负责读取 relay log,并重放这些日志操作到从库的数据文件里。

打个比方:主库每天写工作日报(binlog),从库雇了一个信使(IO 线程)去拿日报复印件,放到自己桌面上(relay log),再雇一个抄写员(SQL 线程)照着日报内容把数据抄进自己的记录里。只要日报不停、信使和抄写员不请假,两边数据就是一致的。

所以从库的状态看两个线程:Slave_IO_Running: YesSlave_SQL_Running: Yes,两个都是 Yes 才表示复制链路健康。

4.2 主库配置与复制账号

主库的/etc/my.cnf中,以下配置必须存在并正确:

server-id=1 log-bin=mysql-bin binlog-format=ROW binlog-expire-log-seconds=604800

修改配置后重启:

systemctl restart mysqld

然后登录主库,创建专门用于复制的账号。千万别用 root 来复制,权限太大,一旦账号泄露整个库都完蛋。复制账号只需要两个权限:REPLICATION SLAVEREPLICATION CLIENT。“REPLICATION CLIENT” 是给监控工具用的,如果你不需要监控,只保留 REPLICATION SLAVE 也够。

CREATE USER 'repl'@'%' IDENTIFIED WITH mysql_native_password BY 'Repl@2024'; GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'repl'@'%'; FLUSH PRIVILEGES;

关于认证插件多说一句。MySQL 8.0 默认认证插件是caching_sha2_password,如果你的从库也是 8.0,直接用默认插件没问题。但如果从库是 5.7,或者你后面用某些旧版客户端工具连接,就得创建用户时显式指定mysql_native_password,否则会报Authentication plugin 'caching_sha2_password' cannot be loaded。我上面命令里已经加上了,图个省事。

接着查看主库当前的 binlog 位置:

SHOW MASTER STATUS;

输出类似:

+------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+-------------------+ | mysql-bin.000001 | 154 | | | | +------------------+----------+--------------+------------------+-------------------+

记下FilePosition这两个值,后面从库执行 CHANGE MASTER TO 时要用。

4.3 从库配置与初始数据同步

从库的/etc/my.cnf中,server-id 必须和主库不同,其他复制参数保持相似:

server-id=2 log-bin=mysql-bin binlog-format=ROW relay-log=mysql-relay-bin read_only=1

relay-log=mysql-relay-bin是设置中继日志前缀,默认叫hostname-relay-bin,显式指定可以避免主机名变化导致日志文件混乱。read_only=1能防止普通应用账号在从库写入数据,避免主从数据不一致。注意它不影响 root 和复制线程,所以 DBA 自己还是可以执行写操作。

修改后重启:

systemctl restart mysqld

接下来是主从配置里最容易出问题的一步:初始数据同步。如果主库是全新的空库,可以直接跳到下一节执行 CHANGE MASTER TO。但如果主库已经有业务数据,必须先做一次全量备份,恢复到从库,然后再启动复制。顺序错了,从库会从空状态开始追 binlog,结果就是大量 1062 主键冲突,直接中断。

全量备份用 mysqldump,建议加上--single-transaction,这样可以在 InnoDB 引擎下不锁表完成备份:

/usr/local/mysql/bin/mysqldump -uroot -p \ --single-transaction --routines --triggers --events \ --all-databases --master-data=2 > /tmp/master_backup.sql

--master-data=2会把 CHANGE MASTER TO 位置信息作为注释写进备份文件头部,方便你恢复后确认 binlog 位置。也可以不依赖它,直接用上面 SHOW MASTER STATUS 得到的值。

把备份文件传给从库:

scp /tmp/master_backup.sql 192.168.1.20:/tmp/

在从库上执行恢复:

/usr/local/mysql/bin/mysql -uroot -p < /tmp/master_backup.sql

恢复完成后,如果从库的 read_only 已经生效,你只能以 root 身份导入,但这里实际是在恢复期间直接用 root 执行的,没问题。

4.4 建立复制通道:binlog 位置法

登录从库,执行 CHANGE MASTER TO 指定主库信息:

CHANGE MASTER TO MASTER_HOST='192.168.1.10', MASTER_PORT=3306, MASTER_USER='repl', MASTER_PASSWORD='Repl@2024', MASTER_LOG_FILE='mysql-bin.000001', MASTER_LOG_POS=154;

这里的 IP、账号、文件名、位置号全部要和主库实际情况一致。MASTER_LOG_FILEMASTER_LOG_POS必须对应SHOW MASTER STATUS里的值,位置号写错或者文件写错,IO 线程会直接报错。

然后启动复制:

START SLAVE;

查看状态:

SHOW SLAVE STATUS\G

重点关注这几行:

Slave_IO_Running: Yes Slave_SQL_Running: Yes Seconds_Behind_Master: 0 Last_IO_Error: Last_SQL_Error:

两个Yes+ 延迟为 0,基本就算成功了。验证方法也很简单:在主库建一张测试表插入一条数据,到从库 SELECT 出来,能看到就说明链路正常。

4.5 更省心的方案:GTID 自动定位复制

binlog 位置法比较传统,但有个明显的痛点:如果从库宕机或者网络中断时间长了,需要找到准确的 binlog 和 position 才能重新对齐。GTID(全局事务标识符)方式可以解决这个麻烦。

GTID 会给每个事务分配一个全局唯一的 ID,主从复制不再依靠“文件 + 位置”对齐,而是靠事务 ID 自动对接。配置方法很简单,主从两台机器的/etc/my.cnf都加上:

gtid_mode=ON enforce_gtid_consistency=ON

重启后,主从都启用了 GTID。这时从库的 CHANGE MASTER TO 就不需要指定 binlog 文件和位置了,改成:

CHANGE MASTER TO MASTER_HOST='192.168.1.10', MASTER_PORT=3306, MASTER_USER='repl', MASTER_PASSWORD='Repl@2024', MASTER_AUTO_POSITION=1; START SLAVE;

MASTER_AUTO_POSITION=1的意思是从库会自动请求主库从自己缺失的 GTID 事务开始同步,不用人工找位置。虽然 binlog 位置法仍然完全可用,但新搭建的环境我强烈建议直接用 GTID。后期如果要主从切换、故障恢复,GTID 能省掉一大半心思。

需要注意一个问题:如果你的主库从还没开 GTID 的状态想改成 GTID,官方要求所有 MySQL 版本都推荐用在线方式平滑开启,但实验环境简单粗暴一点就是主从都停掉、清掉旧的复制关系、改配置重启。第一次搭环境直接在配置阶段就把 GTID 打开,是最省事的。

5. 配置主从复制最容易翻车的几个点

5.1 IO线程一直Connecting:从网络到UUID的排查链路

搭建完成后最让人焦虑的就是执行SHOW SLAVE STATUS\G看到Slave_IO_Running: Connecting,这表示 IO 线程根本连不上主库或者连上但握手失败了。排查顺序我建议从简到繁:

第一步,确认网络通不通。在从库上执行:

telnet 192.168.1.10 3306

如果 telnet 不存在,用:

nc -vz 192.168.1.10 3306

这一步能过滤掉绝大多数防火墙、网络不通的问题。如果连不通,回到第 3 章检查防火墙和 bind-address。

第二步,确认账号权限。用复制账号手动连接主库:

mysql -urepl -p'Repl@2024' -h192.168.1.10 -P3306

能连上但执行SHOW DATABASES;什么都看不到很正常,因为 repl 账号没有普通查询权限。只要能登录,说明账号和密码没问题。

第三步,看详细错误。SHOW SLAVE STATUS\GLast_IO_Error会给出具体原因。常见报错有:

  • Master and slave have equal MySQL server UUIDs:这是虚拟机克隆最常见的问题——从库是主库克隆来的,/data/mysql/auto.cnf里保存的 server-uuid 一模一样。这时在从库删除这个文件,重启 mysqld,让它重新生成 UUID:
systemctl stop mysqld rm -f /data/mysql/auto.cnf systemctl start mysqld
  • Authentication plugin 'caching_sha2_password' reported error:前面说过,创建复制账号时指定mysql_native_password,或者升级客户端驱动。

  • Access denied for user 'repl'@'...':复制账号的 host 范围没覆盖从库 IP。CREATE USER 'repl'@'%'%覆盖所有 host,如果你把它写成了具体 IP,就检查从库实际出口 IP 是否匹配。

5.2 SQL线程报错:1062主键冲突、中继日志损坏

如果Slave_IO_Running: YesSlave_SQL_Running: No,说明日志拉回来了但重放失败。最常见的错误码是 1062,主键冲突:

Last_SQL_Error: Could not execute Write_rows event on table mydb.t_user; Duplicate entry '1001' for key 't_user.PRIMARY'

出现 1062 的根本原因是从库上已经有一条相同主键的数据,但主库又插入了一次,复制线程没法重复插入。这通常是因为:从库在复制启动之前被手动写过数据,或者初始数据备份时没有锁住主库导致数据不一致。

如果确认只是少数几条错误并且业务可以容忍跳过,可以执行:

STOP SLAVE; SET GLOBAL sql_slave_skip_counter = 1; START SLAVE;

sql_slave_skip_counter = 1会让 SQL 线程跳过当前一条事务。注意是一次跳一个事务,不是跳过一行记录。如果错误很多,一条条跳不现实,还是老老实实重建从库更干净。

有时候 SQL 线程报的是中继日志损坏,比如relay log read failure。这种情况下不要硬修,直接清理从库复制状态重建:

STOP SLAVE; RESET SLAVE ALL;

然后回到第 4 章,重新做 CHANGE MASTER TO 和 START SLAVE。如果是从库数据已经彻底乱了,就得重新导一次全量备份,回头重新走初始化流程。这确实是笨办法,但在实验环境里往往比重试更快。

5.3 从库被误写入导致复制中断的恢复

我印象最深的一次事故是,开发同学在从库上手动执行了一条 UPDATE,把某张表的状态字段改了。结果主库对应记录也更新了,复制线程重放时发现从库的值已经变掉了,不管怎么重放都对不上。

这种“人为写入从库”造成的数据冲突,没有完美的自动修复方案。最稳妥的办法是重建从库:在主库重新做一次一致性备份,传到从库恢复,从库清空复制关系再重新指向主库。整个过程在业务低峰期做,几分钟就能完成。

如果你确认冲突可以忽略,或者只是测试环境想快速让复制跑起来,再考虑用sql_slave_skip_counter跳过。但生产环境我一定不建议这么干,因为跳过之后从库数据和主库会存在隐藏的不一致,后面排查问题会更痛苦。

预防远比修复重要。read_only=1必须开在从库上,同时从库的业务账号绝对不能授予 SUPER 权限。普通账号只有 SELECT 权限更好,虽然业务需要读,但从库完全不需要写入口。

5.4 一键巡检主从状态的核心命令

我自己不管搭哪套主从,都会写一个简单的巡检脚本,核心就是这两条命令的检查:

mysql -uroot -pXXX -e "SHOW SLAVE STATUS\G" | grep -E 'Slave_IO_Running|Slave_SQL_Running|Seconds_Behind_Master|Last_IO_Error|Last_SQL_Error'

输出里两个 Running 是 Yes、延迟值不高,就说明复制在正常跑。如果拦截到 Last_IO_Error 或 Last_SQL_Error 非空,再用脚本自动发告警。

更进阶的巡检可以对比主从两边的事务位置:

SHOW MASTER STATUS;
SHOW SLAVE STATUS;

观察Master_Log_FileRead_Master_Log_Pos是否持续增长。如果Read_Master_Log_Pos长时间不增长,说明 IO 线程可能已经断了。

6. 主从复制跑起来之后的日常维护

6.1 从库的read_only、备份与延迟监控

从库不只是个冷备机,正确用法是承担备份和只读查询。read_only=1已经限制了普通账号写入,所以可以放心把报表查询、数据导出这些只读业务切到从库,减轻主库压力。

备份优先在从库上做,这样不会影响主库的读写性能。mysqldump 命令和前面主库备份基本一样,只是不加--master-data=2也行。如果是每天全量备份,用 cron 定时执行:

0 2 * * * /usr/local/mysql/bin/mysqldump -uroot -pXXX --single-transaction --routines --triggers --all-databases | gzip > /data/backup/mysql_$(date +\%F).sql.gz

延迟监控主要看Seconds_Behind_Master。注意这个字段是 SQL 线程执行的时间差估算值,不能完全代表数据一致性,但作为日常告警足够。如果这个值持续上涨,常见原因有:从库机器性能比主库差、主库有大事务(一次 UPDATE 几十万行)、从库磁盘 IO 慢。

还有一种隐藏情况:主库有大量并行事务,从库默认是单线程重放,速度跟不上。MySQL 8.0 默认开启了多线程复制,replica_parallel_workers默认值是 4,一般不用动。如果延迟严重,可以调大一点,但要结合从库 CPU 核数谨慎调整。

6.2 binlog清理策略与磁盘空间

binlog 占的磁盘空间比想象中大,尤其 ROW 格式下一条 UPDATE 可能产生几 MB 日志。不清理的话/data分区早晚被填满,MySQL 会因为无法写 binlog 直接挂掉。

自动清理靠配置:

binlog-expire-log-seconds=604800

7 天是合理值。如果你的从库经常连续宕机好几天,这个值可以再调大,比如 14 天,代价是磁盘占用翻倍。

手动清理可以用:

PURGE BINARY LOGS TO 'mysql-bin.000010';

意思是清理到这个文件之前的日志。注意不要用RESET MASTER,那个会把所有 binlog 清光并重置,从库会彻底断掉复制。

清理 binlog 的同时要盯着主从延迟。理想情况是从库已经追平所有日志,再清理才安全。如果从库延迟还有几个 G 的日志没追完,主库这边 binlog 已经被清掉,从库就会报错The slave I/O thread stops because master and slave have equal MySQL server UUIDs或者 1236Could not find first log file name in binary log index,这时候只能重新全量恢复从库。

6.3 故障切换的基本思路

主库宕机后,把从库提升为主库是标准操作,但不要慌着手动点。基本步骤是这样的:

  1. 确认从库复制已经追平,Seconds_Behind_Master为 0。如果没追平,数据会有丢失。
  2. 在从库执行STOP SLAVE; RESET SLAVE ALL;,断开从库的复制关系。
  3. 如果从库配置了read_only=1,改为读写:
    SET GLOBAL read_only=OFF;
  4. 确认从库自身开了 binlog 且 server-id 全局唯一,这样它才能继续给新的从库提供日志。
  5. 修改应用连接串,把数据库 IP 切到原从库。

跑过一次切换之后你会体会到 GTID 的好处。如果最初用的 binlog 位置法,新主库提升后,原来的主库如果修复回来了,重新接入复制时还要再找一次 position;而 GTID 模式下,只要两边都开了 GTID,直接用MASTER_AUTO_POSITION=1就能重新对齐,基本不用人工干预。

关于故障切换,我的建议是实验环境必须演练一到两次,别等到真出故障了再查资料。重点演练两个环节:一是从库追平判定,二是应用连接切换。很多团队栽就栽在从库延迟没追平就把流量切过去了,数据丢了几千条,后面恢复起来非常麻烦。

这些步骤我在麒麟桌面V10上完整走过一遍,期间踩得最深的就是克隆虚拟机的 server-uuid 重复和防火墙没放行 3306。你如果按这篇的顺序操作,基本能绕开我踩过的坑。最后再提醒一句:生产环境做主从,务必先备份、再变更;测试环境出了问题,直接把从库重建一次往往比重试和修数据快得多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/24 19:38:07

JSP+MySQL供热计量后台毕设实战:从建库到答辩避坑指南

简介&#xff1a;这份资源是面向高校计算机相关专业毕业设计场景的Java JSP供热计量后台数据管理系统源码工具包&#xff0c;适合正在准备毕设、需要一套可运行Web项目作为参考或二次开发基础的学生与初级开发者。系统基于JSP页面与MySQL数据库构建&#xff0c;兼容JDK1.8&…

作者头像 李华
网站建设 2026/9/24 19:36:30

Python CNN图像分类系统:98分课设源码与实战解析

简介&#xff1a;这是一套面向计算机相关专业学生与项目实战学习者的图像分类系统源码包&#xff0c;基于Python卷积神经网络CNN实现&#xff0c;适合用作期末大作业、毕业设计或入门深度学习练手。资源包含完整可运行源码、训练好的模型与说明文档&#xff0c;覆盖LeNet-5、Al…

作者头像 李华
网站建设 2026/9/24 19:35:46

Word打开显示只读的6大原因与精准修复方案

1. 为什么Word一打开就“锁住”了&#xff1f;这不是Bug&#xff0c;是系统在悄悄告诉你某些事 你双击一个Word文档&#xff0c;界面右上角赫然写着“只读”&#xff0c;编辑光标变成灰色&#xff0c;CtrlS毫无反应——这种瞬间被剥夺编辑权的体验&#xff0c;几乎每个办公族都…

作者头像 李华
网站建设 2026/9/24 19:34:30

AI原生零代码平台:从意图理解到决策闭环的评估体系

1. 零代码平台不是“拖拽完事”&#xff0c;而是AI原生工作流的起点我去年接手过一个内部运营工具重构项目&#xff1a;市场部需要一个能实时聚合各渠道销售线索、自动打标签、按规则分发给销售团队&#xff0c;并生成周报的系统。传统方式是找外包开发&#xff0c;周期预估6周…

作者头像 李华