ARTICLE DETAIL

资讯详情

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

MySQL 8.4 全局只读模式 read_only 行为细节与备库复制异常排查

MySQL 8.4 全局只读模式 read_only 行为细节与备库复制异常排查 MySQL 8.4 全局只读模式 read_only 行为细节与备库复制异常排查在构建金融级 MySQL 主从复制与高可用集群架构中备库Replica必须处于绝对可控的只读状态。若只读屏障被意外击穿业务写入流量误入备库将瞬间造成数据多点更新、双写分叉与主从复制位点冲突GTID 裂化。在最新的 MySQL 8.4 LTS长期支持版本中权限系统经历了彻底的细粒度重构Dynamic Privileges 替代传统粗暴的SUPER这使得read_only与super_read_only的底层行为与拦截边界变得更为严苛且隐蔽。工程团队若沿用 5.7 时代的运维认知极易在主从平滑切换或容灾演练中触发复制中断。本文深入剖析 MySQL 8.4 中只读参数的底层运作机制、联动逻辑以及典型复制报错的根因。只读控制矩阵read_only 与 super_read_onlyMySQL 提供了两级全局只读状态控制其控制边界存在显著差异模式普通用户拥有 SUPER 权限用户拥有 CONNECTION_ADMIN / SYSTEM_VARIABLES_ADMIN 用户复制回放线程Replication Applier会话临时表操作read_only OFF允许读写允许读写允许读写允许读写允许读写read_only ON硬性拦截 (报错 1290)允许读写允许读写允许读写允许读写super_read_only ON硬性拦截 (报错 1290)硬性拦截 (报错 1290)硬性拦截 (报错 1290)特殊通道允许允许读写核心联动逻辑陷阱在开发自动化运维控制台或容灾脚本时必须谨防参数设置的隐式级联行为单向级联激活当执行SET GLOBAL super_read_only ON;时MySQL 内核会自动将read_only隐式同步置为ON。反向联动失效风险当执行SET GLOBAL read_only OFF;时MySQL 内核会自动将super_read_only同步降级为OFF若脚本编写者误以为两个参数相互独立在做配置下发时如果先下发super_read_onlyON后下发read_onlyOFF会导致整个实例的只读防护彻底瓦解出现安全真空期。典型生产异常复制回放线程遭遇 1290 报错在正常情况下从库回放 Relay Log 的 SQL/Coordinator 线程拥有内核级的豁免标记不受super_read_only约束。然而在生产环境中从库经常出现以下致命报警Last_SQL_Errno: 1290 Last_SQL_Error: The MySQL server is running with the --super-read-only option so it cannot execute this statement异常场景 APRIVILEGE_CHECKS_USER 权限配置缺陷在 MySQL 8.4 中官方强推并默认支持复制通道的安全审计机制即通过CHANGE REPLICATION SOURCE TO ... PRIVILEGE_CHECKS_USER applier_userlocalhost为复制通道绑定特定系统账号。根因复盘若绑定的applier_user仅被赋予了业务表的 DML 权限而缺少系统动态权限当主库产生涉及系统表如权限变更、密码轮转、存储过程编译的 DDL/DML 时Applier 线程会在super_read_onlyON的备库上直接被安全检查拦截抛出 1290 错误并导致复制线程挂起。标准授权修复方案-- 必须为复制 Applier 账号补充细粒度系统权限 GRANT REPLICATION_APPLIER, SYSTEM_USER, BACKUP_ADMIN ON *.* TO applier_userlocalhost; -- 重新激活复制通道 STOP REPLICA; START REPLICA;异常场景 B触发器Trigger内跨库写操作引发的安全上下文脱节主库某张表挂载了AFTER INSERT触发器该触发器定义中声明的DEFINER账号在备库不存在或属于被限制的受限账号。在复制回放时触发器试图写入另一张日志表由于切换到了非特权的 DEFINER 安全上下文super_read_only的豁免穿透机制失效瞬间触发 1290 中断。生产环境安全切换与只读巡检实战为了防止因主从切换过程中的微秒级空隙导致数据双写我们设计了以下工业级切换保障脚本确保新旧主库切换满足强一致性边界。#!/usr/bin/env bash # MySQL 8.4 生产级高可用只读提权/降级脚本 set -euo pipefail MYSQL_CMDmysql --defaults-file/etc/mysql/admin.cnf -NB action${1:-status} case ${action} in lock_readonly) echo [INFO] 正在将当前实例置为绝对只读模式 (super_read_only)... ${MYSQL_CMD} -e SET GLOBAL super_read_only ON; -- 校验级联状态是否完全生效 SELECT global.read_only, global.super_read_only; # 强制终止当前存在的业务前台长事务连接避免残留事务继续写 echo [INFO] 杀除非复制、非系统后台的普通写连接... ${MYSQL_CMD} -e SELECT CONCAT(KILL , id, ;) FROM information_schema.processlist WHERE user NOT IN (system user, event_scheduler, dba_admin) AND command ! Sleep AND command ! Binlog Dump; | while read -r kill_sql; do if [ -n ${kill_sql} ]; then ${MYSQL_CMD} -e ${kill_sql} || true fi done echo [SUCCESS] 实例已进入强只读锁定状态。 ;; unlock_readwrite) echo [WARN] 正在将实例解除只读升级为主库写入节点... ${MYSQL_CMD} -e SET GLOBAL read_only OFF; -- 验证双参数均已平稳关闭 SELECT global.read_only, global.super_read_only; echo [SUCCESS] 实例已开启全局读写。 ;; check_leak) echo [INFO] 扫描当前实例是否存在绕过 read_only 的高风险普通用户... ${MYSQL_CMD} -e SELECT user, host FROM mysql.user WHERE Super_priv Y OR user IN ( SELECT user FROM mysql.global_grants WHERE priv IN (SYSTEM_VARIABLES_ADMIN, SYSTEM_USER) ); ;; *) echo 使用方式: $0 {lock_readonly|unlock_readwrite|check_leak} exit 1 ;; esac存储架构师的避坑底线1. 严禁使用物理级的innodb_read_only做在线主从切换MySQL 参数中存在一个极易混淆的参数innodb_read_only。该参数是针对 InnoDB 存储引擎内核的启动级只读参数一旦在配置文件中指定必须重启生效。在它开启的状态下连 Redo Log 刷盘和 Undo 空间清理都会被彻底封死甚至会导致复制线程的临时文件创建失败。铁律在线主从切换、读写分离中间件调度仅允许且必须使用全局动态参数super_read_only。2. 警惕临时表Temporary Tables对磁盘与复制的潜在消耗在super_read_only ON状态下应用程序依然可以执行CREATE TEMPORARY TABLE以及对该临时表进行高频的写操作。很多报表类批处理在只读从库上疯狂创建千万级行的大型临时表导致从库磁盘空间被撑爆、tmpdir挂载点写死。防御措施是在从库的配置中严格限制会话级内存临时表上限tmp_table_size与max_heap_table_size并将落盘引擎参数temptable_max_ram约束在安全水位杜绝只读从库被临时表拖垮的隐患。只有透彻理解内核只读控制与权限体系的映射关系才能在高并发与故障转移的极限博弈中构筑坚不可摧的底层数据一致性防线。
返回列表