ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

从零搭建MySQL 8.0高可用环境:主从复制与自动备份实战

从零搭建MySQL 8.0高可用环境:主从复制与自动备份实战 1. 为什么从零搭 MySQL 8.0先拆“高性能、高可用、自动备份”这三个要求一说到从零搭建 MySQL 8.0 环境很多人的第一反应就是yum install mysql-server或者干脆用面板工具一键安装。但真等上了生产环境慢查询一堆、主从延迟拉满、备份文件恢复不了才开始后悔当初没花那半小时把底子打牢。我自己的习惯是宁可前期多花点时间做二进制部署和参数调优也不愿在生产上出一次事故再来救火。这篇文章就是把一套完整的 MySQL 8.0 高可用环境从零到一拆开讲清楚覆盖部署安装、性能参数、GTID 主从复制、故障切换以及用 XtraBackup 做无人值守的全量加增量自动备份。这套方案解决什么问题简单说三件事让 MySQL 跑得更快、让数据库挂了之后业务不中断、让备份和恢复不再依赖人工手工操作。适合谁看主要面向刚接手数据库的小团队运维、正在从单机 MySQL 转向主从架构的开发者以及那些想给自己项目搭一套规范数据库环境但又不想踩坑的朋友。有 Linux 基础就能跟着操作我会把每一步命令和配置背后的原因也讲清楚。1.1 我为什么坚持用二进制包而不是包管理器安装如果你在公司生产环境里跑过yum install mysql-server大概率会遇到这么几个问题系统仓库里的 MySQL 版本普遍偏旧比如 CentOS 自带的 mysql 还是 5.7 甚至更老安装完之后数据目录、日志目录、socket 文件的路径非常不可控想改成独立数据盘要动一堆配置还有最关键的一点不同机器上用不同方式装的 MySQL环境差异会让后续的备份脚本和切换脚本很难统一。MySQL 官方提供的 Linux Generic 二进制包就不存在这个问题。它不依赖发行版的包管理机制下载解压后就是一个完整的 MySQL 目录你可以自由决定数据目录放在哪块盘上、二进制文件放在哪个路径、用什么用户来跑。同一套安装方式在所有机器上保持一致后续写自动化脚本时就不用分别适配。而且二进制包自带的安装方式是官方长期支持的升级时也只需要替换目录里的文件再重启服务。当然二进制部署不是没有代价。它不会自动帮你处理系统依赖比如libaio库必须手动装好也默认不生成 systemd 服务需要自己写 unit 文件。这些工作量就是一个 systemd 服务文件的事相比 yum 安装后期带来的不可控性这点付出非常值得。1.2 “高性能”和“高可用”落地的具体目标很多人对高性能的理解就是堆硬件给数据库配上几十核 CPU、几百 GB 内存。但实际生产里更常见的瓶颈往往是配置不合理缓冲池太小导致频繁磁盘 IO、redo log 太小导致刷脏频繁、连接数设置过高导致内存耗尽、binlog 格式不当导致主从数据不一致。所以本文提到的高性能不是指某个虚拟化的性能测试分数而是让 MySQL 在真实业务负载下保持低延迟、高吞吐、不因为配置问题成为整个系统的瓶颈。高可用也不是说必须上三节点强一致方案。对大多数中小团队来说一主一从加一个自动故障切换配合可靠的备份和恢复演练已经能满足 99% 的场景。真正的高可用是“坏一台机器之后业务能在很短时间内恢复”而不是保证单机永不故障。因此在后面的方案里我会采用主从复制配合 VIP 漂移的方式来做故障切换同时保证每天有全量备份、每天有增量备份备份文件定期清理并异地同步这样即使主从全挂了也能在半小时内把数据恢复到最近状态。2. 环境规划与部署从下载安装到 systemd 服务拉起2.1 目录规划与系统准备生产环境的 MySQL 最忌讳把所有东西塞到系统盘/底下。系统盘一旦满了不仅数据库会异常整台机器都可能卡死。我一般建议把数据目录单独放到数据盘上日志和备份目录也分开规划既能避免互相挤占空间也更方便后续的扩容和备份清理。我习惯的目录规划如下软件目录/usr/local/mysql存放 MySQL 二进制文件数据目录/data/mysql/data存放 InnoDB 数据文件、redo log 等日志目录/data/mysql/log存放慢查询日志、错误日志binlog 目录/data/mysql/binlog存放 binlog和数据文件分开能降低单块磁盘的 IO 压力备份目录/data/mysql/backup存放 XtraBackup 备份文件系统准备方面先确保装了libaio依赖CentOS 上执行yum install -y libaioDebian/Ubuntu 则是apt install -y libaio1。然后创建专用的mysql用户注意不要为了省事直接用 root 跑数据库MySQL 的初始化脚本会明确提示不能用 root 执行而且用专用用户也有利于权限隔离。创建命令很简单useradd -r -s /bin/false mysql mkdir -p /data/mysql/data /data/mysql/log /data/mysql/binlog /data/mysql/backup chown -R mysql:mysql /data/mysql很多人在这步会忽略目录权限问题导致后面mysqld --initialize报Permission denied其实不一定是权限真的有问题而是没有把目录的属主改成 mysql 用户。养成好习惯目录创建完先chown再往下走。2.2 下载、解压与初始化实例到 MySQL 官网下载 Linux Generic 版本的二进制包注意选择当前较新的 8.0 版本比如 8.0.35 或 8.0.36我建议挑一个发布至少两三个月的版本社区反馈充分、已知问题比较少。下载完成后解压到/usr/local下tar -xvf mysql-8.0.36-linux-glibc2.17-x86_64.tar.xz mv mysql-8.0.36-linux-glibc2.17-x86_64 /usr/local/mysql chown -R mysql:mysql /usr/local/mysql然后准备一份基础配置文件/etc/my.cnf。这份配置在初始化之前就要放好因为初始化实例时会读取配置文件中的参数。下面是一个我比较常用的基础模板重点关注数据目录、socket、pid、日志和 binlog 的相关配置[mysqld] user mysql basedir /usr/local/mysql datadir /data/mysql/data socket /data/mysql/data/mysql.sock pid-file /data/mysql/data/mysqld.pid log-error /data/mysql/log/mysql_error.log # binlog 配置 server-id 1 log-bin /data/mysql/binlog/mysql-bin binlog_format ROW gtid_mode ON enforce_gtid_consistency ON # 连接与字符集 port 3306 character-set-server utf8mb4 collation-server utf8mb4_0900_ai_ci default-time-zone 08:00这里提前把gtid_mode ON和binlog_format ROW打开了方便后面直接配置主从复制。配置文件准备好后执行初始化命令/usr/local/mysql/bin/mysqld --defaults-file/etc/my.cnf --initialize --usermysql初始化过程会生成一个临时 root 密码记录在错误日志/data/mysql/log/mysql_error.log里。初始化完成后不要急着直接启动先确认一下日志里有没有 ERROR 级别的报错最常见的就是libaio.so.1加载失败这时候回头装依赖即可。2.3 通过 systemd 管理 MySQL 服务二进制包解压出来的目录里不带 systemd 服务文件需要自己写一个。这一步很有必要因为只有纳入 systemd 管理才能实现开机自启、异常自动拉起、日志统一管理。在/etc/systemd/system/mysqld.service里写入以下内容[Unit] DescriptionMySQL 8.0 Server Afternetwork.target [Service] Typeforking Usermysql Groupmysql PIDFile/data/mysql/data/mysqld.pid ExecStart/usr/local/mysql/bin/mysqld --defaults-file/etc/my.cnf ExecReload/bin/kill -HUP $MAINPID TimeoutSec300 LimitNOFILE65535 [Install] WantedBymulti-user.target保存后执行systemctl daemon-reload然后先启动服务。启动成功后先用初始化日志里的临时密码登录强制修改 root 密码systemctl start mysqld mysql -uroot -p ALTER USER rootlocalhost IDENTIFIED BY 你的强密码;这里有个坑要提醒一下初次登录后如果不修改 root 密码MySQL 8.0 会在后续操作时报权限相关错误有些操作还会因为密码策略太弱被拒绝。所以建议在配置里默认安装validate_password组件或者至少遵循密码长度不低于 8 位的原则。3. MySQL 8.0 参数调优让硬件资源真正为数据库服务3.1 InnoDB 缓冲池、redo log 与刷盘策略InnoDB 缓冲池buffer pool是 MySQL 内存管理中最关键的一块它决定了多少数据和索引可以被缓存在内存里避免每次查询都走磁盘。一般建议设置为物理内存的 60% 到 75%前提是机器主要跑 MySQL没有其他重量级应用抢内存。比如一台 64GB 内存、专门跑数据库的服务器innodb_buffer_pool_size可以设成 40GB 到 48GB。单纯设置大小还不够还有两个参数要一起调整。一个是innodb_buffer_pool_instances默认是 8当缓冲池超过 16GB 时用多个实例可以减少并发访问时的锁竞争。另一个是innodb_flush_method在 Linux 环境下建议设置成O_DIRECT。这个参数的作用是让 InnoDB 绕过操作系统页缓存直接读写磁盘避免双重缓存导致的内存浪费。你可以把操作系统页缓存想象成一层中转站MySQL 自己已经有缓冲池了再让系统缓存一遍就纯属浪费。redo log 的配置在 MySQL 8.0.30 之后发生了变化不再使用innodb_log_file_size来直接指定单个文件大小而是由innodb_redo_log_capacity统一管理。默认值是 100MB对大多数业务来说实在太小频繁触发刷盘会让性能大幅下降。我建议根据缓冲池大小来设缓冲池在 16GB 以下可以给 2GB32GB 到 64GB 缓冲池给 8GB 到 16GB。设置后可以把未来一段时间内写入产生的 redo 日志都圈定在内存和固定文件里而不是频繁做 checkpoint。还有一个直接影响性能和安全的参数组合innodb_flush_log_at_trx_commit和sync_binlog。前者设为 1 时每次事务提交都会把日志刷到磁盘最安全但相对最慢设为 2 时每次提交只写到操作系统缓存每秒再刷一次盘性能更好但掉电可能丢失最多一秒的事务。后者设为 1 时每次事务提交都同步 binlog 到磁盘。对需要高可用的场景我建议保守一点两个都设成 1。如果你业务写并发极高又对丢失一秒钟数据不敏感可以折中把innodb_flush_log_at_trx_commit设成 2但sync_binlog我强烈建议保持 1因为 binlog 丢了会影响主从复制和恢复能力。3.2 连接层、并发与临时表参数连接参数的设置有个常见误区max_connections设置得越高越好。实际上每个连接都会占用线程栈内存和缓存设置过高会导致内存耗尽设置过低又会频繁报Too many connections。我的经验做法是先给一个合理基线比如 300 到 500再结合监控逐步调整。同时要把thread_cache_size设成 64 到 128这样新连接可以复用缓存的线程减少创建线程的开销。MySQL 8.0 的默认连接线程模型是 one-thread-per-connection也就是一个连接一个线程。如果业务是短连接请求频繁起伏可以考虑开启线程池插件但线程池对长连接型业务收益不明显。中小业务建议先不开线程池把max_connections、thread_cache_size调好就够了。临时表参数也是调优里容易被忽略的环节。连接执行的ORDER BY、GROUP BY、子查询都会生成临时表如果临时表大小超过阈值MySQL 会把它落盘到磁盘速度会骤降。tmp_table_size和max_heap_table_size建议一起设成 64MB 或 128MB保持一致才有效。还有sort_buffer_size和join_buffer_size这两个是会话级参数每个连接都会按设置值分配内存所以不能设得过大一般 2MB 到 4MB 起步遇到复杂排序再针对性调大。3.3 慢查询、performance_schema 与安全基线配置性能调优不光是改参数还得能发现慢 SQL。把慢查询日志打开设定合理阈值为 1 秒或 2 秒slow_query_log ON slow_query_log_file /data/mysql/log/mysql_slow_query.log long_query_time 1 log_queries_not_using_indexes ONlog_queries_not_using_indexes很有用它可以记录那些跑了全表扫描但速度还不太慢的查询这类查询往往是业务上线后的隐性炸弹。performance_schema默认是开启的用于采集性能指标但它本身也会消耗 10% 到 15% 的 CPU 资源。如果你的机器性能比较紧张又没在使用需要performance_schema的监控工具可以在配置里加上performance_schema OFF来省下这部分开销。安全基线配置方面记得关闭skip_name_resolve之外的风险选项。生产环境建议加上skip_name_resolve ON避免每次客户端连接都做反向 DNS 解析减少连接耗时。还要设置bind-address 0.0.0.0让主从服务器可以互相访问。文件权限方面/etc/my.cnf里如果写了密码相关的配置项要把文件权限设成 600防止普通用户读到明文账密。4. 高可用架构设计与主从复制搭建4.1 为什么选 GTID 半同步复制而不是传统位点复制传统的主从复制是基于 binlog 文件和位置点来同步的主库记录当前写到哪个 binlog 文件的哪个 offset从库通过CHANGE MASTER TO master_log_filemysql-bin.000001, master_log_pos123来定位。这种方式有个明显缺点一旦主从记录的位点出现偏差比如从库重连时需要人工找到正确的位点非常容易出错。GTIDGlobal Transaction Identifier则是给每个事务分配一个全局唯一 ID从库自动跟踪执行过的 GTID天然不存在位点偏移问题也支持自动跳过已执行事务。半同步复制则是介于异步复制和全同步复制之间的一种模式。异步复制下主库提交事务后不等待从库确认从库的延迟可能随时发生半同步复制要求主库至少收到一个从库的 ACK 确认后事务才算提交成功。这样可以在不牺牲太多性能的情况下极大降低主从切换时丢事务的风险。把 GTID 和半同步复制搭配使用是高可用环境最稳妥的起步组合。需要说明的是尽管半同步复制能减少丢失风险它并不是“零丢失”。如果主库在等待从库 ACK 时挂了已经执行但未确认的事务仍然可能丢失。所以容灾的最后一道防线还是可靠的备份。本文的自动备份方案能在意外发生时把损失控制在很小的范围内。4.2 主从复制完整配置过程在配置主从复制之前需要保证主从两边的 MySQL 都用 GTID 模式且 server-id 不能相同。假设主库 server-id 为 1从库 server-id 为 2两边都开启 GTID。然后主库上创建一个复制专用账号CREATE USER repl10.0.0.% IDENTIFIED BY 你的复制密码; GRANT REPLICATION SLAVE ON *.* TO repl10.0.0.%;由于我们已经开启了 GTID从库不需要手动记录主库 binlog 位置只需要告诉它主库的地址和复制账号。在从库上执行CHANGE MASTER TO MASTER_HOST主库IP, MASTER_PORT3306, MASTER_USERrepl, MASTER_PASSWORD你的复制密码, MASTER_AUTO_POSITION1; START SLAVE;执行后查看从库状态重点看Replica_IO_Running和Replica_SQL_Running是否为Yes以及Seconds_Behind_Source是否为 0。如果 IO 线程不是 Yes大概率是网络或账号问题如果 SQL 线程不是 Yes看Last_SQL_Error信息通常是主从数据不一致导致的。开启半同步复制还需要在两台机器上安装插件并启用对应的系统变量。主库执行INSTALL PLUGIN rpl_semi_sync_source SONAME semisync_source.so; SET GLOBAL rpl_semi_sync_source_enabled ON; SET GLOBAL rpl_semi_sync_source_timeout 1000;从库执行INSTALL PLUGIN rpl_semi_sync_replica SONAME semisync_replica.so; SET GLOBAL rpl_semi_sync_replica_enabled ON;把两个变量写进配置文件以便重启后仍然生效。这里的rpl_semi_sync_source_timeout 1000意思是主库等待从库 ACK 的毫秒数超时则退化为异步复制防止主库因为从库故障而被拖死。这个参数很关键我见过有人把它设成 5000结果从库停机维护时主库也被卡得读写超时。4.3 故障切换、VIP 漂移中小团队最落地的高可用方案主从搭建完成之后需要一套自动故障切换机制。大型团队可能用 Orchestrator 或者 MHA 这种专业组件但中小团队我比较推荐 Keepalived 配合 VIP 的方案。Keepalived 在主从两台机器上各部署一个实例主库上持有 VIP从库上作为备用节点。一旦主库进程本身或所在机器出现故障Keepalived 的 VRRP 协议会使 VIP 自动漂移到从库。应用连接数据库时只需要连接 VIP不感知底层机器的变化。实现流程是主库和从库各装一个 Keepalived配置文件里设置virtual_ipaddress优先级主库设为 100从库设为 90。同时写一个健康检查脚本不仅检查 VIP 所在机器的 mysqld 进程是否存活还要通过 MySQL 账号执行SELECT 1来验证数据库确实可用。当健康检查连续失败几次后Keepalived 角色切换从库升为新的 VIP 持有者。但这里我需要强调一个很多人忽略的细节Keepalived 只管 VIP 漂移它不管从库是否已经追上主库的数据。如果主库突发宕机时从库还有大量事务没同步完成应用切换到从库后就会看到数据缺失。所以故障切换前最好人工确认或者用脚本判断Seconds_Behind_Source和Retrieved_Gtid_Set。我的建议是半同步复制 实时监控延迟告警 定期备份三管齐下。半同步保证最常规情况下不丢数据监控保证我们能及时发现延迟备份兜底应对最坏场景。5. XtraBackup 自动备份全量加增量无人值守5.1 为什么选 XtraBackup 而不是 mysqldumpmysqldump是 MySQL 自带的逻辑备份工具导出的是 SQL 语句恢复时逐条执行。它的问题很明显大数据量下导出速度慢、恢复速度更慢而且 InnoDB 表在导出过程中要保持数据一致性如果业务持续写入必须使用--single-transaction参数但即便如此也只能保证导出的那一刻一致无法做增量备份。对于动辄几百 GB、还在持续写入的生产库mysqldump 基本不适合做日常备份方案。XtraBackup 是 Percona 推出的物理备份工具它的原理是直接复制 InnoDB 的数据文件、redo log 等底层文件备份时不需要锁表也不会阻塞业务写入。恢复时只需要把文件放回数据目录可以做到秒级停机窗口。更关键的是XtraBackup 支持增量备份每次只备份自上次备份以来发生变化的数据页让日常备份的磁盘开销和耗时都大幅下降。要注意版本匹配问题。MySQL 8.0 必须使用 Percona XtraBackup 8.0 版本不能拿 5.7 时代的 XtraBackup 2.4 去备份 8.0否则会在 prepare 阶段报错。同时XtraBackup 版本号和 MySQL 小版本越接近越稳妥最优做法是让两者保持一致比如都用 8.0.35。5.2 安装 XtraBackup 与备份账号准备XtraBackup 8.0 可以通过 Percona 的官方软件源安装CentOS 上直接添加 repo 后yum install percona-xtrabackup-80。安装完成后在 MySQL 里创建专用备份账号。备份账号需要的最小权限如下CREATE USER backuplocalhost IDENTIFIED BY 备份密码; GRANT BACKUP_ADMIN, PROCESS, RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO backuplocalhost; GRANT SELECT ON performance_schema.* TO backuplocalhost;BACKUP_ADMIN权限让 XtraBackup 可以使用BACKUP LOCK和FLUSH TABLES WITH READ LOCK相关能力REPLICATION CLIENT权限则用于读取 binlog 位点或 GTID 信息这些信息在恢复后配置从库时会用到。不要图省事直接用 root 跑备份把备份账号最小化授权可以避免备份脚本一旦被攻击导致数据库控制权旁落。我建议用localhost而不是%因为备份通常就在本机执行不需要远程连数据库备份。如果有多台服务器每台各自建本地备份账号脚本里也就不用把密码放到公网传输。5.3 全量备份、增量备份与恢复流程实战全量备份执行命令xtrabackup --backup \ --target-dir/data/mysql/backup/full_$(date %F) \ --userbackup \ --password备份密码 \ --parallel4 \ --compress--parallel4表示用 4 个线程并行备份能显著缩短备份时间IO 允许的情况下可以设得更高。--compress开启压缩备份体积一般能减少 50% 左右但恢复时需要先解压。如果磁盘空间宽裕也可以不压缩恢复速度更快。备份完成后这个 target-dir 里的文件还不能直接用于恢复必须先执行 prepare 将 redo log 应用到数据文件上让备份数据达到一致状态xtrabackup --prepare --target-dir/data/mysql/backup/full_$(date %F)注意prepare 阶段不要在原始备份目录上反复执行--prepare如果中间出错最好重新拷贝一份再处理否则备份文件会被破坏。增量备份是在全量基础上备份变化的数据页。假设全量备份目录是/data/mysql/backup/full_20250601现在做今天的增量备份xtrabackup --backup \ --target-dir/data/mysql/backup/inc_20250602 \ --incremental-basedir/data/mysql/backup/full_20250601 \ --userbackup \ --password备份密码 \ --parallel4增量备份的恢复流程要比全量复杂。首先需要按顺序 prepare 全量备份在第一次 prepare 时加上--apply-log-only这样只应用 redo log 而不进入回滚阶段目的是保留增量备份的叠加空间xtrabackup --prepare --apply-log-only --target-dir/data/mysql/backup/full_20250601然后把每个增量备份依次合并到全量目录中同样带--apply-log-only中间所有增量都叠加完成后再执行一次不带该参数的 prepare最后就会得到一个完整一致的数据集。恢复时使用xtrabackup --copy-back把数据文件拷回数据目录或者直接rsync同步到目标机器然后启动 MySQL 验证数据完整性。5.4 自动备份脚本与清理策略有了上面的基础接下来就是写自动备份脚本。我的备份策略设计是每周日做一次全量备份周一到周六每天做增量备份全量备份保留最近两次增量备份保留最近七天超出时自动删除老文件。同时每天备份完成后把当天的备份文件同步到另一台机器或者对象存储防止本机磁盘损坏导致备份和源数据一起丢失。一份可以直接使用的脚本框架如下#!/bin/bash BACKUP_BASE/data/mysql/backup DATE$(date %F) WEEKDAY$(date %u) BACKUP_USERbackup BACKUP_PASS备份密码 if [ $WEEKDAY 7 ]; then xtrabackup --backup --target-dir$BACKUP_BASE/full_$DATE --user$BACKUP_USER --password$BACKUP_PASS --parallel4 --compress xtrabackup --prepare --target-dir$BACKUP_BASE/full_$DATE else LAST_FULL$(ls -d $BACKUP_BASE/full_* | tail -1) xtrabackup --backup --target-dir$BACKUP_BASE/inc_$DATE --incremental-basedir$LAST_FULL --user$BACKUP_USER --password$BACKUP_PASS --parallel4 --compress fi # 清理超过 7 天的增量备份和超过 2 份的全量备份 find $BACKUP_BASE -name inc_* -mtime 7 -exec rm -rf {} \; find $BACKUP_BASE -name full_* -mtime 14 -exec rm -rf {} \; # 同步到远程备份机 rsync -av $BACKUP_BASE/ 备份机IP:/data/mysql/backup/然后把脚本写到 crontab 里每天凌晨低峰期执行。我习惯把备份时间安排在凌晨 2 点到 4 点之间并且要确认这个时间段业务写入量确实比较低否则备份会拉长。脚本执行后一定要检查退出状态码和日志文件如果xtrabackup任一阶段失败应该触发告警而不是静默退出。6. 备份失败、复制延迟等常见问题排查实录6.1 XtraBackup 备份失败的典型原因第一个高频问题就是版本不匹配。XtraBackup 8.0 只能备份 MySQL 8.0但 XtraBackup 8.0.x 和不同的 MySQL 8.0.y 小版本之间也可能存在兼容问题比如提示This version of XtraBackup doesnt support MySQL version 8.0.3x。解决办法是让 XtraBackup 和 MySQL 的小版本保持一致差距尽量不要超过一个版本。第二个高频问题是备份期间磁盘空间不足。XtraBackup 备份时会在 target-dir 里生成临时文件备份文件本身通常和数据文件差不多大如果开启了压缩会小一些。所以在备份前必须检查磁盘可用空间至少要保证当前数据量的 1.5 倍空间否则备份执行到一半就会失败遗留的半成品目录还会占用大量磁盘。建议备份目录单独规划在数据盘之外日常用df -h监控空间使用率。第三个问题是备份账号权限不足报错通常是Access denied或者The user could not be authenticated。回看上面 5.2 节的授权语句把BACKUP_ADMIN、RELOAD、LOCK TABLES、PROCESS、REPLICATION CLIENT权限逐一比对。6.2 主从复制延迟的排查思路主从延迟是生产环境最让人头疼的问题之一。首先要确认延迟是不是真实存在的SHOW REPLICA STATUS里的Seconds_Behind_Source为 0 不代表没有延迟因为如果从库 SQL 线程已经追上主库的 binlog 但主库 binlog 还没刷新下来这个字段可能出现短暂为 0。更可靠的方式是比较主库的gtid_executed和从库的gtid_executed。延迟的常见原因有几种从库硬件性能比主库差从库执行大事务的 SQL 语句花费时间太长网络带宽不足导致 binlog 拉取慢还有最容易被忽略的问题——从库上跑着大量报表或分析查询抢占了 CPU 和 IO 资源。针对大事务导致的延迟可以考虑调整从库并行复制参数SET GLOBAL replica_parallel_workers 8; SET GLOBAL replica_parallel_type LOGICAL_CLOCK;这个参数可以让从库并行执行不同事务的 binlog而不是顺序执行。注意要重启或者动态调整后观察如果是因为单条超大事务导致的延迟并行复制也解决不了只能优化业务 SQL 本身。如果延迟长期存在且主从数据差距越来越大最稳妥的办法是重建从库。在业务低峰期用 XtraBackup 全量备份主库恢复到从库后重新CHANGE MASTER TO MASTER_AUTO_POSITION1并START SLAVE几分钟就能追平。6.3 参数调整不生效排查配置加载顺序我调整了my.cnf里的max_connections重启后SHOW VARIABLES还是旧值这类问题十有八九是配置文件加载顺序的坑。MySQL 启动时读取配置文件的顺序不是固定的它会依次查找/etc/my.cnf、/etc/mysql/my.cnf、/usr/local/mysql/etc/my.cnf、~/.my.cnf等多个位置而且后面的读取值会覆盖前面位置的值。所以排查思路是先确定当前实例实际读取了哪些配置文件。执行mysqld --verbose --help | grep Default options查看加载顺序再通过SHOW VARIABLES LIKE max_connections确认当前生效值如果确认配置没错却不生效很可能是还有其他配置文件覆盖了你的设置。我在生产环境上见过好几次开发同事在用户 home 目录的.my.cnf里设置了连接参数导致全局配置被覆盖查了整整半天才定位到。还有一个隐含坑是修改配置后忘记重启。MySQL 里很多参数是动态的可以通过SET GLOBAL在线修改但像innodb_buffer_pool_size这种参数虽然也可以动态修改修改后的值和配置文件里的值可能不一致一旦重启配置文件的旧值又会生效。所以参数调优完成后最好同步把配置文件改掉再动态设置一次最后在低峰期重启验证两边都一样。我在实际部署过程中踩过最深的坑就是每次只关注单个参数有没有设置正确而忽略了参数之间的组合关系。比如缓冲池调大了但innodb_flush_method没改或者tmp_table_size调大了但max_heap_table_size还是默认值最终结果就是配置了等于白配。建议大家在改完所有参数后花十分钟把SHOW VARIABLES的输出导出来对照这份方案里的关键参数逐项检查一遍。另外再分享一个小技巧每次做完备份恢复演练不要只在测试机上跑一遍就算完最好把恢复出来的实例接上几分钟真实流量测试才发现很多问题是演练过程中根本不会暴露的。数据库环境没有所谓的一劳永逸定期检查备份有效性、持续观察监控指标才是高可用真正能落地的关键。
返回列表