MySQL InnoDB Cluster 部署完整文档 MySQL InnoDB Cluster Router Keepalived 高可用部署完整文档环境Rocky Linux 9.8 × 3 台节点192.168.10.11mysql-node1、192.168.10.12mysql-node2、192.168.10.13mysql-node3网卡ens33VIP192.168.10.10目标三节点 InnoDB Cluster 双 Router Keepalived VIP实现数据库层与接入层双重高可用应用无感知 本文中所有 IP 地址、密码、认证口令均为示例值请按实际生产环境替换后再执行。目录一、架构总览二、环境准备三台分别执行三、统一 root 密码与远程授权三台分别执行四、配置 MySQL 实例仅在 141 执行五、创建集群仅在 141 执行六、添加其余节点仅在 141 执行七、部署 MySQL Router141 与 142 分别执行八、部署 Keepalived VIP141 与 142 分别执行九、验证高可用十、原主节点恢复与 rejoin十一、应用连接地址十二、变量对照表十三、常见问题排查一、架构总览角色主机IP说明MySQL 节点 Router KeepalivedMASTERmysql-node1192.168.10.11主库首选VIP 首选持有者priority 100MySQL 节点 Router KeepalivedBACKUPmysql-node2192.168.10.12备库VIP 备选priority 90MySQL 节点仅数据节点mysql-node3192.168.10.13第三个数据节点保证多数派浮动 VIP—192.168.10.10应用唯一接入地址流量路径应用 → VIP 192.168.10.10:6446 │ ┌──────┴──────┐ Router141 Router142 (Keepalived VRRP 主备) │ │ └──────┬───────┘ 当前主库 3306141/142/143 中任一 │ InnoDB Cluster (MGR)高可用两层数据层MGR 三节点主库宕机自动选主容忍一台故障。接入层双 Router Keepalived VIPRouter 所在机器宕机 VIP 自动漂移。二、环境准备三台分别执行在 141、142、143 上各自完成 2.12.8。2.1 配置主机名与 hosts 解析141 上hostnamectl set-hostname mysql-node1142 上hostnamectl set-hostname mysql-node2143 上hostnamectl set-hostname mysql-node3三台都执行cat/etc/hostsEOF 192.168.10.11 mysql-node1 192.168.10.12 mysql-node2 192.168.10.13 mysql-node3 EOF验证ping-c1mysql-node1ping-c1mysql-node2ping-c1mysql-node3关键Shell 会以mysql-nodeX:3306作为集群成员通信地址解析不通会导致addInstance失败。2.2 关闭防火墙与 SELinux简化部署sudosystemctl stop firewalldsudosystemctl disable firewalldsudosetenforce0sudosed-is/SELINUXenforcing/SELINUXdisabled/g/etc/selinux/config生产环境应改为放行 3306、33060、33061、6446、6447、112VRRP端口并保留 SELinux。2.3 修复 locale 警告sudodnfinstall-yglibc-langpack-en2.4 安装 MySQL 官方 yum 仓库sudodnfinstall-yhttps://dev.mysql.com/get/mysql80-community-release-el9-1.noarch.rpm说明el9对应 Rocky / AlmaLinux 9其他系统版本换成对应包如 el8安装后生成/etc/yum.repos.d/mysql-community.repo等仓库文件后续dnf install才有包可装验证ls /etc/yum.repos.d/mysql*.repo。若此步安装 repo rpm 本身提示Public key for mysql80-community-release...rpm is not installed说明新机器缺少 MySQL 官方公钥先执行sudo rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2023再重试。2.5 安装 MySQL 软件包首次安装可能触发 GPG 密钥报错sudodnf clean allsudodnf makecachesudodnfinstall-ymysql-community-server mysql-shell mysqlrouter keepalived可能遇到的报错常见Public key for mysql-community-server-8.0.46-1.el9.x86_64.rpm is not installed. Failing package is: mysql-community-server-8.0.46-1.el9.x86_64.rpm ... The GPG keys listed for the MySQL 8.0 Community Server repository are already installed but they are not correct for this package.原因MySQL 8.0.46 起软件包改用2023 版公钥RPM-GPG-KEY-mysql-2023签名而仓库文件中的gpgkey仍指向旧密钥校验失败。遇到此报错请执行 2.6 修复后重新执行本条安装命令。2.6 修复 MySQL GPG 密钥问题遇报错时执行清理旧密钥rpm-qagpg-pubkey*|grep-imysql若有输出如gpg-pubkey-3a79bd29-xxxx逐个删除sudorpm-e实际包名导入 2023 版密钥sudorpm--importhttps://repo.mysql.com/RPM-GPG-KEY-mysql-2023替换仓库 gpgkey 与 gpgchecksudosed-is|^gpgkey.*|gpgkeyhttps://repo.mysql.com/RPM-GPG-KEY-mysql-2023|g/etc/yum.repos.d/mysql*.reposudosed-is|^gpgcheck.*|gpgcheck1|g/etc/yum.repos.d/mysql*.repo确认grep-E^\[|^gpgkey|^gpgcheck/etc/yum.repos.d/mysql*.repo修复完成后重新执行 2.5 的安装命令即可。2.7 验证安装mysqld--versionmysqlsh--versionmysqlrouter--versionkeepalived--version三台都装mysqlrouter和keepalived便于后续灵活调整实际只在 141/142 启用。2.8 启动 MySQL 并设置开机自启sudosystemctlenable--nowmysqldsudosystemctl status mysqld --no-pager确认active (running)。三、统一 root 密码与远程授权三台分别执行三台都要完成 3.13.3。3.1 获取临时 root 密码sudogreptemporary password/var/log/mysqld.log输出中rootlocalhost:后面的字符串即临时密码。3.2 修改 root 密码mysql-uroot-p在 MySQL 提示符下执行三台统一同一密码示例YourRootPass_2026ALTERUSERrootlocalhostIDENTIFIEDBYYourRootPass_2026;FLUSHPRIVILEGES;EXIT;3.3 授权 root 从集群内网远程访问MySQL 8.0 语法变更IDENTIFIED BY不能写在GRANT语句里必须拆分为CREATE USERGRANT。mysql-uroot-p执行CREATEUSERroot192.168.10.%IDENTIFIEDBYYourRootPass_2026;GRANTALLPRIVILEGESON*.*TOroot192.168.10.%WITHGRANTOPTION;FLUSHPRIVILEGES;EXIT;不要使用root%。用192.168.10.%限定内网网段。三台都执行同样的授权否则configureInstance和addInstance会因 Error 1130 失败。四、配置 MySQL 实例仅在 141 执行dba.configureInstance()会检查并修复 MGR 参数gtid_mode、enforce_gtid_consistency、server_id、binlog_transaction_dependency_tracking 等并创建 clusteradmin。⚠️ 不要加interactive: false。该参数会禁用所有交互式提示包括密码输入导致Access denied ... (using password: NO)的 1045 错误。4.1 进入 MySQL Shellmysqlsh4.2 配置 141在MySQL JS 提示符下执行dba.configureInstance(root192.168.10.11:3306,{clusterAdmin:clusteradmin,clusterAdminPassword:YourClusterAdminPass_2026})提示密码时输入 141 的 root 密码。两个交互确认都输入yDo you want to perform the required configuration changes? [y/n]: y Do you want to restart the instance after configuring it? [y/n]: y成功标志The instance mysql-node1:3306 was configured to be used in an InnoDB cluster.4.3 配置 142dba.configureInstance(root192.168.10.12:3306,{clusterAdmin:clusteradmin,clusterAdminPassword:YourClusterAdminPass_2026})4.4 配置 143dba.configureInstance(root192.168.10.13:3306,{clusterAdmin:clusteradmin,clusterAdminPassword:YourClusterAdminPass_2026})4.5 验证配置结果mysql-uroot-p-eSELECT server_id, gtid_mode, enforce_gtid_consistency;期望server_id不为 1gtid_mode与enforce_gtid_consistency均为ON。五、创建集群仅在 141 执行5.1 使用集群管理账户连接 141在 MySQL Shell 中\connect clusteradmin192.168.10.11:3306输入 clusteradmin 密码YourClusterAdminPass_2026。5.2 创建集群varclusterdba.createCluster(myCluster)预期输出含Cluster successfully created.。5.3 查看初始状态cluster.status()单节点状态status 为OK_NO_TOLERANCEprimary 为192.168.10.11:3306。六、添加其余节点仅在 141 执行保持cluster变量可用。6.1 添加 142cluster.addInstance(clusteradmin192.168.10.12:3306)提示数据恢复方式时直接回车接受默认Clone。6.2 添加 143cluster.addInstance(clusteradmin192.168.10.13:3306)同样接受默认Clone。6.3 验证集群健康状态cluster.status()期望status:OKstatusText:Cluster is ONLINE and can tolerate up to ONE failure.一个节点 R/WPRIMARY两个节点 R/OSECONDARY。6.4 设置备库优先权重可选建议执行若希望 MySQL 主库故障时优先由 142 接管cluster.setInstanceOption(clusteradmin192.168.10.12:3306,memberWeight,80)cluster.setInstanceOption(clusteradmin192.168.10.13:3306,memberWeight,20)验证cluster.status({extended:1})在输出中各节点的memberWeight字段可见。七、部署 MySQL Router141 与 142 分别执行Router 部署在两台141 和 142。143 不部署 Router。7.1 在 141 上 Bootstrap Router先退出 MySQL Shell\exit在系统 shell 中执行sudomkdir-p/etc/mysqlroutersudomysqlrouter--bootstrapclusteradmin192.168.10.11:3306--directory/etc/mysqlrouter--usermysqlrouter输入 clusteradmin 密码。7.2 在 141 上启动 Routersudosystemctlenable--nowmysqlroutersudosystemctl status mysqlrouter --no-pager ss-tlnp|grep-E6446|6447应看到 6446读写和 6447只读在LISTEN。7.3 在 142 上 Bootstrap Routersudomkdir-p/etc/mysqlroutersudomysqlrouter--bootstrapclusteradmin192.168.10.11:3306--directory/etc/mysqlrouter--usermysqlrouterbootstrap 连 141当前主库即可。Router 会从元数据拿到完整拓扑。7.4 在 142 上启动 Routersudosystemctlenable--nowmysqlroutersudosystemctl status mysqlrouter --no-pager ss-tlnp|grep-E6446|64477.5 分别验证两台 Router 连通性141 上mysql-h192.168.10.11-P6446-uclusteradmin-p-eSELECT hostname, port;142 上mysql-h192.168.10.12-P6446-uclusteradmin-p-eSELECT hostname, port;两者都应返回当前主节点主机名例如 mysql-node1 和 3306。这证明两台 Router 都能正确路由。八、部署 Keepalived VIP141 与 142 分别执行Keepalived 只部署在 141 和 142。143 不部署。VIP 用 192.168.10.10网卡用 ens33不是 eth0。8.1 141 上配置 Keepalived编辑/etc/keepalived/keepalived.confsudovi/etc/keepalived/keepalived.conf141 配置MASTERpriority 100vrrp_instance VI_ROUTER { state MASTER interface ens33 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass YourVrrpAuthPass } virtual_ipaddress { 192.168.10.10/24 } }⚠️ 不要包含任何virtual_server块。之前 141 启动失败正是因为残留了 LVS/IPVS 相关配置。当前场景只需要 VRRP不需要 LVS。8.2 142 上配置 Keepalived142 配置BACKUPpriority 90vrrp_instance VI_ROUTER { state BACKUP interface ens33 virtual_router_id 51 priority 90 advert_int 1 authentication { auth_type PASS auth_pass YourVrrpAuthPass } virtual_ipaddress { 192.168.10.10/24 } }8.3 两台关键参数必须一致参数141142必须一致interfaceens33ens33✅virtual_router_id5151✅auth_passYourVrrpAuthPassYourVrrpAuthPass✅virtual_ipaddress192.168.10.10/24192.168.10.10/24✅state / priorityMASTER / 100BACKUP / 90141 优先8.4 加载 ip_vs 内核模块保险措施在两台上执行sudomodprobe ip_vssudomodprobe ip_vs_rrechomodprobe ip_vs|sudotee/etc/modules-load.d/ipvs.confechomodprobe ip_vs_rr|sudotee-a/etc/modules-load.d/ipvs.conf8.5 启动两台 Keepalived141 和 142 上分别sudosystemctlenable--nowkeepalivedsudosystemctl status keepalived --no-pager检查两台systemctl is-active keepalived mysqlrouter都应输出两行active。8.6 确认 VIP 归属141 上ipaddr show ens33|grep192.168.10.10应有输出说明 141 作为 MASTER 持有 VIP。142 上ipaddr show ens33|grep192.168.10.10应无输出BACKUP 不持有 VIP正常。8.7 通过 VIP 验证接入层从任意机器执行mysql-h192.168.10.10-P6446-uclusteradmin-p-eSELECT hostname, port;应返回当前 MySQL 主节点主机名证明VIP → 141 Router → 当前主库链路通。九、验证高可用高可用分两层验证接入层 VIP 漂移 和 数据库层主库切换。9.1 验证接入层VIP 漂移第一步在 141 上停掉 Keepalivedsudosystemctl stop keepalived第二步在 142 上确认 VIP 已漂移等待 1~3 秒后ipaddr show ens33|grep192.168.10.10应出现192.168.10.10/24。第三步通过 VIP 再次访问数据库mysql-h192.168.10.10-P6446-uclusteradmin-p-eSELECT hostname, port;仍应成功返回当前主节点主机名。这证明 VIP 漂到了 142142 的 Router 正常接管。第四步恢复 141 的 Keepalivedsudosystemctl start keepalived141 priority 更高会抢回 VIP142 回到 BACKUP。这是正常行为。9.2 验证数据层主库自动切换第一步模拟主库假设当前主库为 141宕机在 141 上执行sudosystemctl stop mysqld第二步在 142 或 143 上查看集群状态mysqlsh--js-eshell.connect(clusteradmin192.168.10.12:3306); var cluster dba.getCluster(myCluster); print(JSON.stringify(cluster.status(), null, 2));输入 clusteradmin 密码。几秒内 primary 变为 142 或 143status 变为OK_NO_TOLERANCE剩两节点仍构成多数派但不能再容忍第二次故障。第三步通过 VIP 验证读写切换mysql-h192.168.10.10-P6446-uclusteradmin-p-eSELECT hostname, port;返回的主机名不再是 mysql-node1而是新选举出的主节点。证明 Router 已自动把写流量切换到新主库。9.3 验证整机宕机综合场景第一步141 整机关机或systemctl isolate emergency慎用等效模拟方式在 141 上同时停掉服务sudosystemctl stop mysqldsudosystemctl stop mysqlroutersudosystemctl stop keepalived第二步在 142 上检查 VIP 与 Routeripaddr show ens33|grep192.168.10.10 ss-tlnp|grep6446systemctl is-active mysqlrouter keepalived期望VIP 已漂到 142、6446 在监听、两服务active。第三步通过 VIP 访问数据库mysql-h192.168.10.10-P6446-uclusteradmin-p-eSELECT hostname, port;应成功返回 142 或 143新主库。至此数据层与接入层的双重高可用完整闭环验证通过。十、原主节点恢复与 rejoin当 141 恢复后重新开机或启动服务10.1 141 上启动 MySQL 与 Routersudosystemctl start mysqldsudosystemctl start mysqlroutersudosystemctl start keepalived10.2 将 141 重新加入集群在任意健康节点如 142上执行mysqlsh--js-eshell.connect(clusteradmin192.168.10.12:3306); var cluster dba.getCluster(myCluster); cluster.rejoinInstance(clusteradmin192.168.10.11:3306);如果 141 未自动 rejoin此命令将其作为 SECONDARY 加回集群。10.3 验证集群恢复健康mysqlsh--js-eshell.connect(clusteradmin192.168.10.12:3306); var cluster dba.getCluster(myCluster); print(JSON.stringify(cluster.status(), null, 2));期望三节点全部 ONLINEstatus 回到OK。注意MGR 不会自动把主库迁回 141。此时 142或 143仍是 PRIMARY141 是 SECONDARY这是正常的。若希望主库回到 141手动执行cluster.setPrimaryInstance(clusteradmin192.168.10.11:3306)10.4 确认 VIP 已回到 141由于 141 priority 更高Keepalived 恢复后会自动抢回 VIP# 141 上ipaddr show ens33|grep192.168.10.10十一、应用连接地址应用的 DBHost 统一写192.168.10.10:6446不再指向任何一台具体物理机。高可用效果故障场景数据层行为接入层行为应用影响MySQL 主库进程崩溃MGR 自动选新主Router 自动跟秒级中断自动恢复141 整机宕机若 141 为主库MGR 选主若 141 为从库无影响VIP 漂到 142接入不中断142 整机宕机若 142 为主库MGR 选主若 142 为从库无影响VIP 漂回 141若在线接入不中断143 宕机集群剩 2 节点仍可用但不再容忍第二次故障无影响无影响十二、变量对照表变量本文值说明MySQL root 密码YourRootPass_2026三台统一集群管理账户clusteradmin由 configureInstance 自动创建集群管理密码YourClusterAdminPass_2026建议替换为强密码集群名称myCluster后续 getCluster 需一致节点 IP192.168.10.11/12/13三台数据节点网卡名ens33Keepalived 配置必须匹配VIP192.168.10.10/24应用唯一接入地址VRRP 组 ID51141/142 必须一致VRRP 认证密码YourVrrpAuthPass141/142 必须一致141 priority100MASTER 优先持有 VIP142 priority90BACKUPRouter 读写端口6446应用连接此端口Router 只读端口6447读请求分发到从节点备库权重可选1428014320主库故障时优先 142 接管十三、常见问题排查13.1 Error 1130 Host ‘xxx’ is not allowed to connect原因目标 MySQL 未授权 root 从集群内网远程访问。解决在目标 MySQL 本地登录执行第三章 3.3 的CREATE USERGRANT。13.2 Error 1045 Access denied … (using password: NO)原因dba.configureInstance命令中带了interactive: false禁用了密码提示。解决去掉interactive: false保持交互模式让 Shell 提示输入密码。13.3 ERROR 1064 … near ‘IDENTIFIED BY … WITH GRANT OPTION’原因MySQL 8.0 语法变更IDENTIFIED BY不能写在GRANT语句里。解决拆分为CREATE USERGRANT两条语句分别执行。13.4 GPG 检查失败公钥没有安装原因MySQL 8.0.46 使用 2023 版密钥签名旧仓库配置仍指向 2022 版密钥首次dnf install报Public key for ... is not installed也是同一原因。解决执行第二章 2.6 的密钥清理、导入、sed 替换再重新执行 2.5 的安装命令。13.5 Cannot set LC_ALL to locale en_US.UTF-8原因系统缺少 en_US.UTF-8 locale。解决sudo dnf install -y glibc-langpack-en。13.6 addInstance 卡住或失败检查三台/etc/hosts是否都能互相解析 mysql-node1/2/3以及防火墙是否放行 3306、33060、33061。13.7 interactive option is deprecated 警告MySQL Shell 8.0 较新版本的前瞻性提醒当前版本仍完全支持可忽略。13.8 Keepalived 启动失败日志有 Initializing ipvs / Gained quorum … VS […]原因配置文件中残留virtual_server块LVS/IPVS 配置当前场景只需要 VRRP。解决# 编辑 /etc/keepalived/keepalived.conf删除所有 virtual_server { ... } 块sudomodprobe ip_vssudomodprobe ip_vs_rrsudosystemctl restart keepalivedgrep-cvirtual_server /etc/keepalived/keepalived.conf# 输出应为 013.9 VIP 不漂移 / 两台各自持有 VIP脑裂原因141 和 142 的virtual_router_id或auth_pass不一致未形成同一 VRRP 组。解决核对两台grep -E virtual_router_id|auth_pass /etc/keepalived/keepalived.conf输出必须完全相同。同时确认interface ens33、virtual_ipaddress 192.168.10.10/24两台一致。13.10 VIP 在 142 上但应用连不上 6446原因142 上 Router 未启动或未 bootstrap6446 未监听。解决ss-tlnp|grep6446systemctl status mysqlrouter --no-pager若 6446 无监听在 142 上重新执行sudomysqlrouter--bootstrapclusteradmin192.168.10.11:3306--directory/etc/mysqlrouter--usermysqlroutersudosystemctl restart mysqlrouter13.11 setPrimaryInstance 报 bash 语法错误原因把 JavaScript 命令敲到了 Linux bash 里提示符是#而不是JS 。解决先mysqlsh进入 Shell连接集群再在JS 提示符下执行cluster.setPrimaryInstance(...)。按上述顺序逐条执行即可完成三节点 InnoDB Cluster 双 Router Keepalived VIP 的完整高可用部署并通过两层故障转移验证。