首页 / 资讯中心 / 文章详情

MySQL MGR选主机制解密:权重、事务序号与高可用切换实战

MySQL MGR选主机制解密:权重、事务序号与高可用切换实战 ★ FEATURED ARTICLE
我干了这么多年数据库运维最不愿意碰的就是深夜主节点悄无声息地挂掉然后一堆业务告警把手机刷成震动模式。你就守在屏幕前盯着MGR的视图看它到底要把“主”的位置交给谁——这个等结果的过程有时候比故障本身还折磨人。MySQL Group Replication (MGR)的选主策略就是你在这个场景下最该摸透的底牌。这篇文章不会讲太多Paxos协议的学术概念我就按我实操中的理解把MGR选主这件事拆开揉碎。你会搞清楚为什么某些节点会上位、某些节点永远没机会那个叫group_replication_member_weight的参数到底怎么玩以及当网络抖动、节点被驱逐、事务积压这些破事发生时MGR到底是怎么从一堆候选者里挑出一个新主的。这个东西适合正在搞高可用架构、给系统做故障切换预案、或者单纯被MGR“自动选出一个你不想要的主”坑过的同学。看完你至少能做到一点以后MGR再选主你能提前猜中它选谁甚至让它乖乖选你要的那台机器。1. MGR选主机制全景这玩意儿到底是怎么“选”出主的1.1 不是投票选劳模而是一条“共识链”上的必然结果很多人第一次接触MGR脑子里会自动套用传统主从切换的逻辑——以为有个什么中心节点统计票数然后宣布谁当主。实际情况完全不是这样。MGR的选主不是独立于复制之外的“额外流程”它就藏在组复制的共识协议和数据同步逻辑里。我换个说法解释一个MGR集群里的每个成员都在通过组通信系统不停交换事务信息。每个成员手里其实都维护了一套关于“组里现在有哪些人、每个人数据到了哪个位置”的状态。当某个成员发现当前主节点失联了或者组内视图发生变化时它会基于本地已经同步到的信息自己独立去算“如果现在选主我该推谁”。算完大家再通过共识机制把结果“敲定”下来。这个过程里最关键的一点是候选者凭借的不是“我被谁推举了”而是“我手上数据够不够新、我的配置优先级够不够高”。一个数据落后十条街的节点就算业务上你特别想让它当主它在选举里也排不上号。这就是MGR与传统主从最大的分野——你没法靠“人为指定”硬推一个数据不完整的节点上位它自己也心虚因为它的事务序号不够大。1.2 单主模式才有“选主”这回事多主模式不选这里必须先掰扯清楚一个概念MGR分single-primary单主和multi-primary多主两种模式。家常生产环境里用的绝大多数是单主模式因为多主模式下冲突检测和事务回滚会让你在业务层有很多“惊喜”。单主模式下组里只有一台机器能对外提供写服务这一台就是“主”primary。所以“选主策略”严格来说指的是单主模式下如何确定那台写入服务由谁承担。多主模式下不存在“谁是主”这个概念所有成员都能写自然也没有选举流程。你要是运营着多主模式还纠结选主策略那属于方向跑偏了。在单主模式下触发选主常见的就三种场景集群首次启动组建从零开始搭组没有一个现成的主得从第一批成员里选一个当主。当前主节点故障退出主宕机、被驱逐、网络隔离组里感知不到它了剩余成员得重新定一个主。人为切换迁移主角色你主动把某台实例从主降级或隔离触发组内重新收敛选主。三种场景底层走的选主逻辑是一样的区别只在于候选者的范围和数据状态可能不太一样。首次启动时大家都是空库事务序号一样选主往往看权重和内部排序主故障时活着的成员里谁的事务最全谁就占绝对优势。2. 选主的胜负手member_weight权重与事务序号到底谁说了算2.1 选主算分规则其实就两层MGR选主的判定规则拆到最底层就两个维度在起作用。第一维度成员权重group_replication_member_weight这个参数就是让你人为干预选举结果的入口。取值范围是0到100的整数默认值是50。数值越大代表这个成员在选举中被“优先考虑”的程度越高。注意这里的表述是优先考虑不是“一票定生死”——它只是在member_weight上比别人高。第二维度事务执行程度gtid_executed的事务序如果候选的成员member_weight完全一样那 MGR 就会去比较他们的gtid_executed集合。执行过的事务越多、事务序号越靠后、日志越全的节点优先级越高。说的直白点谁的数据停留在更靠前的“历史时刻”谁就当备选垫底谁掌握了最新的写入记录谁就是天选之人。这两层比较结束后理论上就能选出唯一的新主了。如果比到这儿还没分出胜负呢MGR内部会有一个确定性的规则兜底——对成员自身的某种标识比如成员ID或内部排序做一次数值比较保证总会有一个人被选中。也就是说除非整个组都不可用否则一定会有选主结果。2.2 这个参数怎么设置才靠谱能否动态调整group_replication_member_weight是个动态变量你可以用SET GLOBAL在线修改不需要重启实例也不需要重搭复制。这点在实际运维里太重要了——我见过很多同学在配置文件里写死权重结果想调优先级就得晚上停机窗口。其实完全没必要。它的生效范围是每个成员各自独立设置。也就是说你在某台机器上只给自己设了权重90其他机器默认50这两台机器都会带着各自的权重参与比较。我复制一份参考配置给你看-- 在指定成员上执行调整本机权重 SET GLOBAL group_replication_member_weight 80; -- 查看每个成员的权重 SELECT * FROM performance_schema.replication_group_members;performance_schema.replication_group_members这张表里就有一列MEMBER_ROLE和MEMBER_STATE你可以顺带查一下当前成员的角色。不过要注意这张表里看不到权重值。想看组内所有成员的权重配置你得去每个实例上分别SHOW VARIABLES LIKE group_replication_member_weight;。这里补一个坑如果你用的是 MySQL 5.7 早期版本可能压根没有这个变量。它是后面版本才引入的更早版本只能靠server_uuid的字母顺序作默认仲裁依据属于纯不可控的排序。所以你要是还在跑老版本然后发现选主结果不可控换个新版本可能是最优雅的方案。2.3 手动模拟选主逻辑这波谁会被选中一目了然你可以自己用一张表来推演选主结果。假设组内有四台机器A、B、C、D。成员配置权重事务状态推演结果A100事务序号 100最优先如果活着基本就是它B80事务序号 200权重高但A的权重更高A上位C80事务序号 300权重与B一样但C事务新C胜出D80事务序号 300权重、事务一样D靠兜底规则还是可能输这个案例里你会看得特别清楚权重领先的人未必稳赢只有权重和事务进度都在线的节点才是被全组认可的新主。所以你的运维策略不能只调权重还得保证候选节点跟得上主库的同步节奏。一个天天中继日志积压严重的“备胎节点”在选举里会被事务进度一票否决。3. 实操干预选举怎么让MGR稳稳选出你想要的那台主3.1 给某个节点“加血”的正确时间和姿势选主的理想情况是你想让哪台机器当主就给它设最高的权重。但盲目的做法往往是——权重调好了主还是选了别人。为什么因为权重只在新一次选举时生效它没法逼迫当前主节点“退位”。想要主动把主切到目标节点就得先有“触发选主”的动作。实操上我一般这么干第一步检查当前组状态。SELECT member_id, member_host, member_port, member_role, member_state FROM performance_schema.replication_group_members;确认所有成员都是ONLINE如果有节点处于RECOVERING或者OFFLINE先排除干扰项。第二步给目标节点设置高权重。-- 登录目标主节点的机器执行 SET GLOBAL group_replication_member_weight 100;同时把其他候选节点的权重调低比如统一调到0或1确保万一选主时不会跑到别人身上去。第三步有计划地“撵走”当前主。这里有两类操作方式效果不同。温和方式把当前主的权重临时调成最低0然后关掉它的写权限或者直接让它STOP GROUP_REPLICATION退出组触发自动选主。别的节点一看到主没了就会按权重收敛选出你的目标节点。强制方式在别的节点上执行group_replication_force_members把你想要的节点设置为组成员。这个操作我一般极度谨慎它是一个强制组视图重置稍有不慎会导致脑裂风险新手绝对不建议碰。3.2 权重如何做到“平滑调整”避免影响在途业务我遇到的很多同学在调整权重时直接一把梭SET GLOBAL group_replication_member_weight 100完全不考虑当前主节点是其他机器。这个操作本身不影响在途事务但因为它是动态变量所有成员的“下一次选举”都会立即拿它做参考。问题在于你提前把权重改了如果此刻主节点临时发生一次瞬间闪断哪怕最后它又恢复回来也可能因为这个“改过的权重”导致主角色发生非预期漂移。主节点漂移对连接层和缓存来说都是一段不可忽略的抖动。所以规范的操作应该是选主动作发生前的窗口内再改权重而不是提前很久全局渲染。如果你是在日常巡检里发现某台机器负载低、性能强、做备胎浪费了想为未来的故障切换抢先布局那你需要做的不是调权重而是调plugin_secondary_engine_cost_threshold不说笑了你该做的是把它的事务同步调正常、把延迟压下去让权重能够决定一切。权重是意志事务进度是资格两者都齐备它才真正具备“接班条件”。3.3 新成员加入的时候是不是“一次清零重新投”经常有同学问我新加一台从库数据追平了它有没有可能在下一次选主时突然选中它我的回答是敬请放心它一辈子都很难选上。原因是新节点加入组后它的gtid_executed虽然通过状态重建被追平了但在MGR内部的一致性视角里它的事务上下文仍然是“从某个位点之后才开始连续”的。即便我们手动把所有成员的权重都设为一样的新节点由于事务执行的“连续性”和内部序号对比记录上不占优势基本都会在选举排序里垫后。这其实是个好消息——它防止了一个新节点刚上线还没扛过完整流量就因为权重最高而莫名其妙变成主节点。我见过有人为了测试故意给新节点设权重100结果主节点故障时它真的上位了然后业务开始疯狂报错因为它的数据库连接数、buffer pool预热、应用账号权限都还没按主节点标准准备好。所以默认情况下新节点就该是“万年备胎”等它真正确认稳定再给它权重这个逻辑是科学的。4. 故障场景选主实录网络分区、节点驱逐、复制积压下的表现4.1 网络分区时为什么偶尔会看到“没有主”的状态MGR选主有个大前提新主的选定必须得到多数派成员同意。这个多数派不是简单数人头而是基于组通信视图的“法定人数”。假设一个组有五台成员其中两台因为网络抖动导致它们自己聚在一起另外三台连在一起。MGR内部的处理方式是少数派这边只有两台无法形成法定人数所以它们会把自己标记为不可用保证整个系统不至于两边同时选主形成“双脑”。这个时候你会观察到少数派里的两台机器MEMBER_STATE会从ONLINE变成ERROR日志里会有类似 “has no quorum” 或者 “Member was expelled from the group due to network failures” 的提示。整个组在短时间内可能看不到可用的主节点MEMBER_ROLE没有PRIMARY业务写直接断掉。多数派那边重新收敛后会从自己这边挑一个新主。这个过程看着吓人但其实是大规模集群里必须付出的安全代价。宁可暂时没有主也不能同时出现两个主。那种既要高可用又要零脑裂的诉求在分布式系统里就是鱼与熊掌。对付网络分区你唯一能做的就是保证组通信超时参数配置合理、机房网络真正稳定。4.2 主节点“假死”触发驱逐选主结果会偏向谁有一种高频事故是主节点的业务线程被某个大事务或者长查询卡住心跳还能发组通信没断但主节点实际上已经没有能力处理写入。这种状态很阴间——MGR不会立刻炒掉当前主组里也不会触发选主因为共识协议认为它还好端端活着。你会看到从节点复制照常但写入已经全部卡死。只有当它真正确认失联超过阈值默认由group_replication_communication_stack和心跳超时共同决定组里才会把它踢出去然后按老规矩重新选。这个场景里事务序号最大的节点会天然占据明显优势因为主节点最后几笔事务只存在于它身上。如果其他从节点还没拉到那几笔日志选它当主就是唯一安全选项。所以我在故障演练的时候经常故意在主节点上跑大事务拖慢中继日志然后把主 kill 掉看选主结果。你会发现那个最努力拉取日志、延迟最低的从节点基本都会成为新主。反向说明一个问题平时你给从节点加再高的权重都没用它同步延迟拉胯关键时候顶不上去就是顶不上去。4.3 选主完成后的“连接层”隐痛选主本身通常也就一两秒就出结果了但业务恢复往往比这个时间长得多的多。为什么呢因为应用连接池里的写连接还指向旧主节点的IP和端口。MGR选主完成后不会自动通知你“快去改JDBC URL”它只能通过group_replication的元数据视图展示新的主是谁。靠谱的生产架构里前端都会挂一层代理或者中间件查询replication_group_members的动态变化然后自动把写流量切换到新主。没有这层机制的话哪怕MGR选主策略完美得如同教科书你的业务一样会在每次切换时中断好几分钟。这是很多同学在做MGR时只盯着选主逻辑、却忽略了上层感知链路这个大坑的地方。5. 选主参数的进阶调优与日常运维心得5.1 除了权重哪些参数会影响选举与切换体验group_replication_member_weight是唯一直接参与选主“偏好”的参数但有几个间接参数非常影响选主结果。group_replication_autorejoin启用后被驱逐的集群成员会自动尝试重新加入组。重新加入后它会重新参与下一次选举。如果你不想让它刚回组就被选为主它的延伸影响就是——权重依旧默认50但它的事务状态非常新极有可能在下次选举中直接上位。group_replication_communication_stack底层通信栈类型目前推荐默认值。它决定了组通信的心跳间隔和超时判定从而影响故障发现速度。loose-group_replication_start_on_boot实例启动时是否自动启动组复制影响一个节点误重启后回组的时机。我见过最无语的一次事故某台从库权重忘记调主库故障后它成为新主但它的max_connections设置比老主低了整整一半。切换后业务新连接大量被拒告警声比故障切换时还密集。这就是典型的“只顾选主逻辑没顾候选节点的富余容量”。调优的时候候选主节点的连接数、内存参数、innodb缓冲池这些硬指标必须和权重放在一起评估。5.2 多机房架构下选主策略要有“地域倾向”如果你在跨机房部署MGR三地五副本是常见拓扑。跨机房延迟天然无法消除这时候的选主策略要特别考虑“谁会选上新主、数据延迟多严重”。靠默认权重50很可能选出一个与你核心业务读写不在同一机房的节点。应用访问新主要跨专线写入延迟瞬间飙升一个量级。常规做法给业务主所在机房的成员权重调高到100或者90。给其他机房的灾难恢复节点权重调到0或者20。定期演练“如果主机房整体断网剩下两个机房是否还有法定人数能够选出新主”。如果两个剩余机房的成员数加起来都不足多数派那任凭你权重怎么配MGR也一样会进入只读模式整个集群不可写。所以说节点数奇偶性的设计比调参更优先搞成偶数组是最常见的低端失误。5.3 每次选的“主”不是越新越好要评估数据“新鲜vs稳定”这个观点可能跟很多人的直觉相悖。我见过很多同行看到某从库同步延迟最低就手动把权重调最高巴不得下次故障它做新主。但真正等它上了位才发现这个节点运行的版本是集群里最特殊的一个它上面跑着全量归档任务、备份任务、甚至数据抽取任务环境变量和主节点的安全配置完全不一致。业务一接入就是各种奇怪的权限问题、临时表空间问题。我自己的习惯是每个候选主都得按主节点的全套标准来做安全基线配置不然它就不该进候选名单。如果一个节点连read_only都还没设置成OFF的权限哪怕事务再新也不值得托付。MGR给你提供了权重的杠杆是让你在“同水平备胎”之间做择优的时候用的不是让你拿一个见都没见过生产写流量的节点硬顶上去的。6. 经验总结MGR选主别再对着文档死背把它当作运维闭环的一部分来看MySQL Group Replication的选主机制本质上是一套融合了数据安全性与人工干预入口的共识逻辑。你不需要去死记“谁权重高谁上位”或者“谁事务多谁当选”你需要做的是理解这背后对数据一致性的坚持——宁可没有主绝不选错主。我自己的一个小习惯是每次搭完MGR或者做完主备切换演练都会把performance_schema.replication_group_members的结果截个图存档顺手记录一下当时各节点的权重配置和事务序号。下一次故障发生时只要翻一翻上次的记录基本就能掏出“这个节点会不会成为新主”的预测结论。这个习惯帮你避开很多排查弯路。最后分享一个更细节的技巧如果你想刻意避免某台节点被选为新主不一定要把权重调成0直接把它的group_replication_member_weight调成负数——不行这个参数不接受负数0就是最低。把候选者的权重统一调低把目标节点单独调到峰值是控制MGR选主方向最干净、最安全的手段。但请记住无论你如何设计权重最终能让MGR心服口服的一定是那个事务完整、状态在线、容量充裕的节点。调参数能帮你做倾向真正的底气得靠平时把复制健康度和容量冗余做扎实。
阅读完成 · 觉得有帮助?
咨询建站