十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

MySQL 8.0.45 MGR单主模式高可用集群搭建与故障切换实战

MySQL 8.0.45 MGR单主模式高可用集群搭建与故障切换实战 干这一行久了就明白MySQL高可用方案选来选去最后还是会绕回官方那套东西。MGRMySQL Group Replication从5.7时代推到现在8.0里已经非常稳定很多生产环境都在用。今天就把我在Ubuntu 22.04上搭建MySQL 8.0.45 MGR单主模式的完整过程写下来从环境准备、配置文件逐行拆解到节点引导、故障切换实测一步都没落下。如果你正要搭一套组复制这篇文章可以直接照着抄。1. 动手之前先搞明白MGR在解决什么问题我见过不少朋友MySQL主从复制跑得好好的觉得高可用不过如此一台Master一台Slave坏了手动切换就是了。但真正等到凌晨两点接到报警电话登录上去发现从库延迟几万秒主库磁盘写满那一刻才知道这套方案有多脆弱。MGR不一样它的核心是组内节点用Paxos协议保持数据共识所有节点的数据通过binlog应用保持一致组成员之间互相监控状态。单主模式下组内只有一个PRIMARY节点负责写入其他SECONDARY节点保留完整数据副本当PRIMARY宕机或者网络隔离时集群会自动从剩下的SECONDARY里选举出新的PRIMARY整个过程不需要人工介入。解决主从复制手动切换、容易丢数据、从库延迟不可控的问题自动故障检测与选举RPO趋近于零组内成员状态对应用透明配合MySQL Router或负载均衡可以做读写分离适用场景对一致性要求较高、希望减少人工运维干预的中小型业务这里必须提醒一句MGR不是银弹它要求至少三个节点才有意义因为Paxos需要多数派才能选出主。两个节点挂了任何一个都无法继续服务所以生产环境请老老实实起三台或者更多。本文用的就是三台Ubuntu 22.04虚拟机跑的都是MySQL 8.0.45。2. 三台Ubuntu 22.04的环境准备与安装细节先把三台机器规划好后面所有配置都以这里的IP和主机名为准。节点主机名IP地址角色server_idnode1mgr-node1192.168.56.101初始PRIMARY1node2mgr-node2192.168.56.102SECONDARY2node3mgr-node3192.168.56.103SECONDARY3MGR内部通信默认走33061端口客户端和复制连接走3306端口。两个端口都要保证能互相访问这里建议先在每台机器上把/etc/hosts配好避免主机名解析出问题sudo tee -a /etc/hosts EOF 192.168.56.101 mgr-node1 192.168.56.102 mgr-node2 192.168.56.103 mgr-node3 EOF然后配置防火墙。如果测试环境图省事直接关防火墙生产环境务必按最小化原则放行sudo ufw allow 3306/tcp sudo ufw allow 33061/tcp sudo ufw status时间同步也不要忽略组复制对时钟漂移敏感。Ubuntu 22.04默认有systemd-timesyncd确认它在跑就行如果用的是NTP或者Chrony保证每一台节点的时间偏差在几百毫秒以内。2.1 MySQL 8.0.45的安装方式Ubuntu自带源里的MySQL版本通常不够新我们要用官方提供的APT仓库这样才能装到8.0.45。先在MySQL官网下载对应发行版的deb包wget https://dev.mysql.com/get/mysql-apt-config_0.8.33-1_all.deb sudo dpkg -i mysql-apt-config_0.8.33-1_all.deb安装过程中会弹出一个蓝色配置界面让你选择要使用的MySQL版本这里选MySQL 8.0 LTS系列然后OK保存。接着刷新源并安装sudo apt update sudo apt install -y mysql-server安装过程会要求设置root密码也可以选择跳过用auth_socket插件后期再改。装完验证一下版本mysql --version如果显示mysql Ver 8.0.45 for Linux on x86_64那就对了。2.2 克隆虚拟机后的隐藏雷区server-uuid冲突如果你和我一样是克隆了三台虚拟机来搭这套环境那有一个坑十有八九会遇到每台MySQL的数据目录里都有一个auto.cnf文件里面保存着本机唯一的server_uuid。克隆出来的机器auto.cnf是完全一样的而MGR要求每个节点的server_uuid必须唯一否则节点加入组时会直接报错。解决办法很简单在node2和node3上先停掉MySQL删除或改掉auto.cnfsudo systemctl stop mysql sudo rm -f /var/lib/mysql/auto.cnf sudo systemctl start mysql重启后MySQL会生成一个新的uuid。这个操作每台克隆出来的机器都要做包括后面要加入组的任意节点别偷懒。3. 核心配置逐条拆解每个参数为什么这么写MGR的配置集中在/etc/mysql/mysql.conf.d/mysqld.cnf我习惯在文件末尾追加一个独立段落方便管理。下面是node1的完整配置[mysqld] server_id 1 gtid_mode ON enforce_gtid_consistency ON binlog_checksum NONE log_bin mysql-bin log_slave_updates ON binlog_format ROW master_info_repository TABLE relay_log_info_repository TABLE transaction_write_set_extraction XXHASH64 # group replication loose_group_replication_group_name a6cf14d8-2e0a-4b85-8cb6-e1748c315f84 loose_group_replication_start_on_boot OFF loose_group_replication_local_address 192.168.56.101:33061 loose_group_replication_group_seeds 192.168.56.101:33061,192.168.56.102:33061,192.168.56.103:33061 loose_group_replication_single_primary_mode ON loose_group_replication_enforce_update_everywhere_checks OFFnode2和node3只有三处不同server_id、loose_group_replication_local_address前者按2和3配置后者换成各自的IP。group_seeds保持不变因为所有节点都要暴露给组内其他成员。3.1 基础参数背后的逻辑gtid_mode ON和enforce_gtid_consistency ON是硬性要求MGR底层用的是GTID和binlog没有GTID组复制根本跑不起来。binlog_format ROW也是必须的组复制要求基于行的复制才能在冲突检测时通过write set提取事务特征。log_slave_updates ON这个参数容易被忽略很多人以为从库自己写binlog没什么用。但在MGR里每个节点既是通过复制通道应用的“从库”同时也是给其他节点提供binlog的“主库”这个参数不打开副本节点连上来的数据流转就断了。binlog_checksum NONE是MGR早期版本的要求8.0.45其实已经兼容CRC32校验但为了减少各种莫名其妙的问题建议还是按NONE配。3.2 group_replication参数逐个解读loose_前缀的意思是如果MySQL实例上还没有加载group replication插件遇到这些参数也不会报错只是忽略掉。这样即使插件编译版本不匹配MySQL至少还能正常启动。loose_group_replication_group_name组的唯一标识必须是一个合法的UUID。可以用SELECT UUID();生成一个三台机器必须一致loose_group_replication_start_on_boot这里先设OFF防止MySQL一启动就自动尝试加入组等手动确认无误后再决定是否打开loose_group_replication_local_address本机用于组内通信的地址和端口注意不是客户端连接端口loose_group_replication_group_seeds组内所有节点的local_address列表逗号分隔。新节点加入时会先连接这些种子节点中的任意一个loose_group_replication_single_primary_mode设为ON即单主模式组内只有一个Primaryloose_group_replication_enforce_update_everywhere_checks单主模式下必须设为OFF这里有个容易踩的坑group_replication_group_name如果直接复制别人的UUID是小事最怕的是三台机器配置不一致那就永远凑不到一个组里。我在三个配置文件里都是手动粘贴同一个UUID还是建议配置完成后用grep检查一遍sudo grep -r group_replication_group_name /etc/mysql/mysql.conf.d/确认三台输出一致再继续。4. 第一个节点引导顺序错一步全盘推倒重来配置改完先重启MySQLsudo systemctl restart mysql然后用root登录确认扩展插件路径正常。Ubuntu上MySQL插件一般装在/usr/lib/mysql/plugin/下group_replication.so就在那里INSTALL PLUGIN group_replication SONAME group_replication.so;如果已经安装过会提示插件已存在不影响。接着校验一下核心参数是否全部生效SHOW VARIABLES LIKE group_replication%; SHOW VARIABLES LIKE gtid_mode; SHOW VARIABLES LIKE binlog_checksum;确认没有哪项是空值或者异常再创建专门的复制账号。MGR的recovery通道要用这个账号从其他节点拉取binlogCREATE USER repl% IDENTIFIED WITH mysql_native_password BY Rpl123456; GRANT BACKUP_ADMIN, REPLICATION SLAVE ON *.* TO repl%; FLUSH PRIVILEGES;为什么这里用mysql_native_password这是很多教程不会告诉你的一个坑MGR的recovery channel在建立SSL或者公钥交换之前如果复制账号用的还是默认的caching_sha2_password非常容易出现认证失败节点一直卡在RECOVERING状态。直接指定native_password能省掉一堆公钥交换的麻烦。生产环境如果安全要求高可以用caching_sha2_password并配置好SSL但测试环境建议先这么跑通。4.1 引导节点bootstrap_group的开关时机第一个节点引导前需要先让它认为自己是组的起点SET GLOBAL group_replication_bootstrap_group ON; START GROUP_REPLICATION; SET GLOBAL group_replication_bootstrap_group OFF;bootstrap_group这个开关只能在这一步临时设置为ON成功启动组后必须立刻关掉。如果一直让它开着下一次这个节点重启后再次START GROUP_REPLICATION时它会新建一个不同视图的组其他节点就永远加不进来。我见过有人反复引导多次最后整个组逻辑全乱只能清空数据重来。启动后立刻检查成员状态SELECT * FROM performance_schema.replication_group_members\G看到当前节点状态为ONLINEMEMBER_ROLE为PRIMARY说明引导成功。可以顺手建个测试库表往里面写点数据CREATE DATABASE testdb; USE testdb; CREATE TABLE t_demo (id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50)); INSERT INTO t_demo(name) VALUES (node1-init);这一步不是多余的。后面节点加入后它们会同步到这张表验证复制是否真正生效。5. 从节点加入组recovery channel细节与状态验证node2和node3的操作基本一致这里以node2为例。先确认MySQL已启动、插件已安装、复制账号已创建。然后指定recovery channel的认证信息。MySQL 8.0.23之后官方推荐用CHANGE REPLICATION SOURCE TO但旧版CHANGE MASTER TO依然可用考虑到很多脚本和习惯下面两种写法都放出来STOP GROUP_REPLICATION; CHANGE MASTER TO MASTER_USERrepl, MASTER_PASSWORDRpl123456 FOR CHANNEL group_replication_recovery; START GROUP_REPLICATION;或者CHANGE REPLICATION SOURCE TO SOURCE_USERrepl, SOURCE_PASSWORDRpl123456 FOR CHANNEL group_replication_recovery;这一步的本质是从节点通过这个专用channel从种子节点拉取binlog追赶数据。很多新手误以为MGR加入节点只需要启动插件不需要配置任何复制信息实际上没有这个recovery channel节点是无法自动补齐数据的。5.1 节点状态正常与异常的判断标准启动后立刻看成员状态SELECT * FROM performance_schema.replication_group_members\G正常情况应该看到node1、node2都是ONLINEnode2的MEMBER_ROLE是SECONDARY。如果node2状态一直停在RECOVERING说明recovery channel没跑通。此时要先查看复制线程状态SELECT * FROM performance_schema.replication_connection_status\G SHOW REPLICA STATUS FOR CHANNEL group_replication_recovery\G最常见的异常是Last_IO_Errno为2061或者Authentication plugin错误这个基本就是复制账号认证方式不对重新按mysql_native_password创建账号再执行STOP GROUP_REPLICATION和START GROUP_REPLICATION即可。node3同样操作全部加入后再次查询SELECT * FROM performance_schema.replication_group_members;三条成员全部ONLINE角色一个PRIMARY、两个SECONDARY组就算建成了。然后在node2上登录MySQL查一下之前建的testdb和t_demo数据应该已经同步过来。USE testdb; SELECT * FROM t_demo;能查到node1-init那行数据说明复制链路完全正常。这时你大概率会松一口气但先别高兴太早高可用那部分还没验证。6. 高可用实测故障切换和恢复到底靠不靠谱搭建完不是终点真正验证MGR能不能用要模拟一次主节点宕机。我习惯先把应用连接和测试负载准备好然后直接停掉PRIMARY节点的MySQL服务。先确认当前主节点是谁SELECT MEMBER_HOST, MEMBER_ROLE, MEMBER_STATE FROM performance_schema.replication_group_members;假设node1是PRIMARY那么直接sudo systemctl stop mysql等大约10到60秒取决于故障检测的阈值和网络状态再在node2或node3上执行SELECT MEMBER_HOST, MEMBER_ROLE, MEMBER_STATE FROM performance_schema.replication_group_members;你会看到node2或node3中有一个角色变成了PRIMARY另一个仍然是SECONDARY。MGR通过组内心跳和多数派协议自动选出了新主整个过程不需要人工切VIP也不需要执行任何change master。接着测试一下新主是否真的可写USE testdb; INSERT INTO t_demo(name) VALUES (after-failover);能正常写入说明新主已经进入读写状态。而老主node1恢复服务后它会自动检测到原组还在自己重新作为SECONDARY加入不需要手动引导。你可以在node1重启后观察成员状态看到它重新变成ONLINE两个PRIMARY同时存在的情况不会发生。6.1 单主模式下的读写分离边界这里要明确一点MGR本身不提供VIP也不提供负载均衡。单主模式下应用必须知道当前PRIMARY是谁否则写入请求打到SECONDARY上会被拒绝报错信息类似ERROR 1290 (HY000): The MySQL server is running with the --super-read-only option。生产环境通常会在前面加MySQL Router或者ProxySQL把读写请求按角色分流。本文搭建的是MGR核心集群这部分不在本次范围内。测试的时候可以写个简单脚本循环INSERT配合systemctl stop mysql观察写入中断时间你会看到故障切换导致的写入抖动通常在秒级相比人工切换快了不止一个量级。7. 排错手册搭建过程里最容易踩的坑清单我把这次搭建前后遇到的各种报错整理成了一张表每一条都是实际踩过的不是网上复制粘贴的。你在搭建时如果也遇到类似现象直接对着排查就行。现象根因解决办法START GROUP_REPLICATION后一直RECOVERING网络33061端口不通或recovery channel账号密码不对检查防火墙确认CHANGE MASTER配置确认复制账号使用native_password从节点报ERROR 3092/3096插件未安装或group_replication相关参数未生效执行INSTALL PLUGIN重启MySQL后检查SHOW VARIABLES报错Contains no magic table or system table组名不是合法UUID用SELECT UUID();生成新UUID确保三台一致节点状态报ERROR并退出组binlog_checksum不等于NONE或部分参数不满足MGR要求配置文件统一加binlog_checksumNONE重启所有节点克隆虚拟机后节点无法加入auto.cnf中的server_uuid重复删除/var/lib/mysql/auto.cnf后重启MySQL客户端连接正常但写入失败应用把请求发到了SECONDARY节点通过MySQL Router或应用层识别PRIMARYSECONDARY本身禁止写入bootstrap_group没有及时关闭多次引导导致组视图混乱所有节点STOP GROUP_REPLICATION重新从第一个节点引导排错时有个通用思路优先看错误日志Ubuntu上MySQL日志在/var/log/mysql/error.log里面会明确写出是网络、认证还是插件问题。其次看performance_schema里的视图和复制通道状态这两处信息基本能定位90%的故障。另外提醒一下如果你在配置里开了loose_group_replication_start_on_boot ON节点重启后会自动尝试加入组这本来是省事的设计但如果组本身已经挂了或者网络抖动启动阶段就可能报错。测试环境我建议还是保持OFF等每次都手动START GROUP_REPLICATION确认无误后再在真正需要自动拉起的环境里打开。最后再分享一个经验别在节点数据不一致的情况下强行做组复制。三个节点最好都是全新初始化的实例避免历史binlog和GTID残留导致加入后数据校验不过。如果非要导入旧数据也请保证三边基准一致否则MGR的冲突检测机制会让你在恢复阶段吃尽苦头。这套环境我前后重建了三次才把各种细枝末节理顺按这篇文章一步步来应该能一次跑通。
返回列表