ARTICLE DETAIL

资讯详情

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

MySQL MGR单主集群部署指南:从参数配置到踩坑实战

MySQL MGR单主集群部署指南:从参数配置到踩坑实战 最近一个月我在干一件事把一个跑了好几年的单主从MySQL迁移到三节点的MGR单主集群上。MGRMySQL Group Replication是MySQL官方的组复制方案而单主集群是其中最常见的一种部署形态同一时刻只有一个节点可写其余节点只读。这篇就把Linux环境下完整的部署流程、参数含义和踩坑记录一次性写清楚。如果你正在考虑给业务加上高可用又不想引入中间件那一大套东西那MGR单主几乎是最省心的选择。它不依赖第三方工具MySQL自己就把故障检测、成员管理、数据复制全包了。适合有一定MySQL基础、想快速搭建一套可靠高可用环境的DBA或运维同学参考。1. 为什么是MGR为什么偏偏要单主1.1 传统主从复制差在哪之前那套主从方案其实也能用但问题在于它没有真正的自动决策能力。主库挂了从库不会自己转正得靠脚本检测、VIP漂移、HA软件配合才能完成切换。整个过程里只要有一环没跟上业务就断得比预期久。更麻烦的是主从延迟没法根治半同步方案虽然缓解了一部分但毕竟还是一主一备的逻辑脑裂风险始终在。MGR的底层是Paxos协议所有节点互相通信、互相投票成员状态是组内共享的。一个节点出问题其他节点会在几秒内感知到然后自动推举新的主节点。这个机制从根上解决了靠外部脚本才知道主库挂了的尴尬局面。1.2 单主与多主到底怎么选MGR有两种模式单主single-primary和多主multi-primary。单主就是同一时间只有一个节点可写其他节点全部只读写入压力完全集中在一台机器上。多主则是每个节点都能写数据会通过组复制互相同步。听起来多主更灵活但实际上在跨机房、跨地域的场景里多主很容易因为网络延迟产生认证冲突两个节点同时对同一行数据做了修改就会有一个事务被回滚。应用层要想办法处理这种冲突非常麻烦。单主模式下不存在这个问题写入只有一个入口其他节点只负责读和备份逻辑简单得多。1.3 什么样的情况适合单主MGR单主MGR适合绝大多数常规业务读多写少单节点写入完全够用需要高可用但不想折腾复杂架构。三到五个节点在一个机房或同城机房网络稳定、延迟低组复制才能跑得顺畅。如果你的业务是写密集型的单节点写入成了瓶颈那单主MGR确实不适合反而应该考虑分库分表或者直接上分布式数据库。还有一点MGR对事务大小很敏感单个大事务会把整组拖慢后面我会专门说这个问题。所以部署前先想清楚你的业务是不是真的适合这套方案不是所有高可用需求都该用MGR。2. 环境规划与前置准备没想清楚别动手2.1 三节点拓扑怎么分MGR最少三台节点因为组复制需要多数派投票才能决策。三台里面挂掉一台剩下两台还能继续跑挂掉两台就只剩一台不满足多数派整个组会进入只读保护状态。五台节点理论上能容忍两台故障但成本高了一些常规业务三台足够了。我这边用的拓扑是这样节点别名IPMySQL端口MGR内部通信端口用途mgr-node1192.168.1.11330633061初始主节点mgr-node2192.168.1.12330633061从节点mgr-node3192.168.1.13330633061从节点33061这个端口是组复制的内部通信端口节点间通过它互相传输事务和选举信息跟3306业务端口完全是两回事。配置的时候千万别漏了我就是在这个端口上栽过跟头后面详细说。2.2 系统初始化与软件安装操作系统我用的是Rocky Linux 8.x如果你们用的是openEuler、Anolis这类国产Linux发行版命令基本上是通用的底层都是RHEL系的systemd和firewalld。MySQL版本选了8.0.32用了MySQL官方的二进制包解压就能跑不依赖yum源的版本方便统一。安装路径规划也很重要别一股脑都放在默认目录软件目录/usr/local/mysql数据目录/data/mysql/data日志目录/data/mysql/log运行目录/data/mysql/run初始化之前先建好mysql系统用户和这些目录然后把属主改成mysql。数据目录单独挂一块磁盘会更稳至少确保磁盘空间足够组复制会把所有节点的binlog都同步一遍日志量比单机大不少。2.3 时间同步、SELinux和防火墙MGR对时间同步有要求节点间时钟偏移太大会导致事务时间戳错乱建议所有节点都跑NTP或chrony跟同一个时间源同步。很多部署教程把这一步忽略了等到排查问题的时候才发现日志时间对不上很难受。SELinux建议直接设成disabled或者至少让mysqld的端口和相关目录在SELinux策略里放行。我图省事直接setenforce 0再把/etc/selinux/config改成了disabled省得后面冒出各种权限问题。防火墙方面190行规则基本就够了firewall-cmd --permanent --add-port3306/tcp firewall-cmd --permanent --add-port33061/tcp firewall-cmd --reload3306要放行因为应用要连33061要放行因为组内节点要通信。如果三台机器在同一个安全组里还要注意云平台的安全组规则是不是也放了这两个端口。3. my.cnf核心参数逐项拆解3.1 数据库初始化与基础配置二进制包解压到/usr/local/mysql后先初始化数据目录/usr/local/mysql/bin/mysqld --initialize-insecure --usermysql --basedir/usr/local/mysql --datadir/data/mysql/data--initialize-insecure会让root初始密码为空方便第一次登录登录后再设置强密码。生产环境第一步就把root密码改了不要拖。初始化完成后用mysqld_safe或systemd启动MySQL。我习惯用systemd管理写一个mysqld.service指向前面的目录这样开机自启、异常重启都由systemd负责比裸跑mysqld_safe省心得多。3.2 组复制相关的核心参数下面是节点1的完整my.cnf节点2和节点3只改server_id和local_address两处其他完全一样[mysqld] # 基础配置 server_id 11 port 3306 bind_address 0.0.0.0 datadir /data/mysql/data socket /data/mysql/run/mysql.sock pid_file /data/mysql/run/mysqld.pid log_error /data/mysql/log/error.log # 二进制日志与GTID binlog_format ROW log_bin mysql-bin binlog_rows_query_log_events ON log_slave_updates ON gtid_mode ON enforce_gtid_consistency ON binlog_checksum NONE master_info_repository TABLE relay_log_info_repository TABLE relay_log_recovery ON # InnoDB调优 innodb_buffer_pool_size 4G innodb_flush_log_at_trx_commit 1 sync_binlog 1 transaction_isolation READ-COMMITTED # 字符集 character_set_server utf8mb4 collation_server utf8mb4_0900_ai_ci # 组复制专属参数 transaction_write_set_extraction XXHASH64 loose-group_replication_group_name 3fcc0f1c-2d54-11ee-9b6a-0c9a2f1c1234 loose-group_replication_start_on_boot OFF loose-group_replication_local_address 192.168.1.11:33061 loose-group_replication_group_seeds 192.168.1.11:33061,192.168.1.12:33061,192.168.1.13:33061 loose-group_replication_bootstrap_group OFF loose-group_replication_single_primary_mode ON loose-group_replication_enforce_update_everywhere_checks OFF loose-group_replication_exit_state_action READ_ONLY每个参数都值得说清楚server_id三台必须各不相同这是MySQL区分实例的依据重复会导致节点无法加入组。gtid_mode ON和enforce_gtid_consistency ONMGR强制要求开启GTID只有基于全局事务标识符组内才能准确判断每个节点执行到哪个位置。enforce_gtid_consistency是为了禁止那些GTID下不允许的操作比如非事务引擎的DDL。binlog_checksum NONE这是个经典坑。MySQL默认的binlog校验和会让MGR在应用日志对不上号官方要求必须关掉。master_info_repository TABLE和relay_log_info_repository TABLE把复制元数据存到InnoDB表里而不是文件里这样配合GTID才能正确记录复制进度。log_slave_updates ON从节点上接收到的变更也要写进自己的binlog否则其他节点没法通过它继续同步。transaction_write_set_extraction XXHASH64MGR事务冲突检测依赖write setXXHASH64是8.0推荐算法5.7上很多用MURMUR32咱们用8.0就直接XXHASH64。loose-前缀意思是如果这个参数对应的插件还没加载MySQL不要报错直接把未知参数忽略掉而是正常启动。这样即使my.cnf里写了组复制参数、插件还没INSTALL服务也能正常起来。group_replication_group_name这个必须是一个合法的UUID代表整个组的身份。所有节点的这个值必须完全一致用SELECT UUID()生成一个就行。我上面这个是我测试环境实际用的你部署时换成新生成的。group_replication_local_address当前节点用于组内通信的地址和端口每个节点配自己的。group_replication_group_seeds组内所有节点的内部通信地址列表所有节点都配相同的这份列表类似注册名单。group_replication_start_on_boot OFF我建议第一次部署时手动启动组复制不要开机自动加入。等集群稳定了再考虑改成ON。group_replication_single_primary_mode ON开启单主模式这是整个部署形态的核心开关。group_replication_enforce_update_everywhere_checks OFF配合单主模式必须设为OFF如果设成ON反而是在为多主模式做检查。group_replication_exit_state_action READ_ONLY节点被组除名后做什么我设成只读而不是直接关闭数据库这样即使节点被隔离数据还在人还能登上去查问题。3.3 组复制账号与恢复通道MGR在节点加入集群时需要一个账号来拉取增量数据这个过程叫recovery。这里要单独创建一个专用账号不要用root去跑复制CREATE USER repl% IDENTIFIED WITH mysql_native_password BY Repl2023; GRANT REPLICATION SLAVE, REPLICATION CLIENT, GROUP_REPLICATION_ADMIN, BACKUP_ADMIN ON *.* TO repl%; FLUSH PRIVILEGES;MySQL 8.0默认的认证插件是caching_sha2_password但在recovery通道里会有兼容性问题经常出现认证失败或者必须启用group_replication_recovery_get_public_key ON才能连上。为了避免这个麻烦我直接给repl账号指定了mysql_native_password认证插件简单直接。账号建好后要告诉MGR用哪个账号去拉数据每个节点都执行CHANGE MASTER TO MASTER_USERrepl, MASTER_PASSWORDRepl2023 FOR CHANNEL group_replication_recovery;如果是MySQL 8.0.23及以上版本也可以用新语法CHANGE REPLICATION SOURCE TO SOURCE_USERrepl, SOURCE_PASSWORDRepl2023 FOR CHANNEL group_replication_recovery老语法依然兼容不用纠结。4. 单主集群启动全流程实录4.1 引导第一个节点组复制的启动有讲究第一个节点跟后面加入的节点操作不一样因为组还不存在需要引导来创建。先在三个节点上都加载插件INSTALL PLUGIN group_replication SONAME group_replication.so;然后在node1上执行引导三连SET GLOBAL group_replication_bootstrap_group ON; START GROUP_REPLICATION; SET GLOBAL group_replication_bootstrap_group OFF;bootstrap_group这个变量只允许第一个节点打开它告诉MGR我是老大我要创建这个组。启动完成后立刻把它关掉防止后续误操作又创建出一个新组那就分裂了。第一次执行后错误日志里能看到类似这样的记录[Note] Plugin group_replication reported: Group replication started with the following configuration: single primary mode看到这一行基本就说明单主模式生效了。4.2 第二、第三节点如何加入node2和node3的加入就简单得多不需要bootstrap直接STARTSTART GROUP_REPLICATION;如果配置没问题几秒后再查询performance_schema里的成员表SELECT member_id, member_host, member_port, member_state, member_role FROM performance_schema.replication_group_members;node1刚引导完时它的member_state应该是ONLINEmember_role是PRIMARY。等node2、node3加入后它们的member_role应该都是SECONDARYmember_state是ONLINE。如果某个节点一直是RECOVERING状态说明recovery过程没走完大概率是账号权限、防火墙、数据不一致这三类问题。别急先把错误日志打开tail -f /data/mysql/log/error.log里面会明确告诉你卡在哪一步。4.3 状态验证与读写测试集群状态正常后还要做一次读写验证毕竟配置看起来对和实际跑起来对有差别。查看当前主节点的正规方式SHOW STATUS LIKE group_replication_primary_member;在主节点node1上建库建表并写入CREATE DATABASE testdb DEFAULT CHARACTER SET utf8mb4; CREATE TABLE testdb.repl_test (id INT PRIMARY KEY AUTO_INCREMENT, val VARCHAR(50)); INSERT INTO testdb.repl_test(val) VALUES (hello), (mgr);然后登录node2或node3查询这张表SELECT * FROM testdb.repl_test;如果能看到刚才插入的两条数据说明组复制同步链路是通的。再顺手在node2上试试写入INSERT INTO testdb.repl_test(val) VALUES (should_fail);应该会直接报错提示The MySQL server is running with the --super-read-only option这正是单主模式该有的行为说明只有主节点能写。5. 日常运维与故障排查真实踩坑笔记5.1 高频问题速查表MGR启动和运行期的报错其实高度集中我把几个最常见的情况整理成了一张表现象可能原因解决办法START GROUP_REPLICATION报错日志里是连接对端33061失败防火墙没放行33061端口三台节点都放行33061检查云安全组节点加了半天还是RECOVERINGrecovery账号密码不对或节点数据不一致检查错误日志重新初始化数据或用mysqldump导入报错提示group_replication plugin未安装没执行INSTALL PLUGIN先装插件再启动提示group_name不匹配成员元数据group_replication_group_name配置不一致三台改成同一个UUID执行事务时提示没有主键或非InnoDBMGR要求所有表必须有主键引擎必须InnoDB把表结构规范好再迁入节点被自动驱逐状态变成ERROR网络抖动或者节点响应超时调大group_replication_member_expel_timeout5.2 三次真实故障复盘第一个坑是33061端口。当时node1引导成功但node2一直报连接失败错误日志反复出现无法建立TCP连接到192.168.1.12:33061。检查了半天IP和端口最后发现是node2这台机器的防火墙没有放行330613306放行了但组复制端口漏了。MGR对防火墙的敏感度比想象中高因为组复制要求节点之间频繁通信任何丢包或超时都会影响成员状态。第二个坑是GTID不干净。有一台节点之前跑过普通主从GTID集合跟新组的对不上启动组复制时报错说无法加入因为本地GTID与组里不一致。处理办法是确认这台机器不需要保留旧数据后执行RESET MASTER清空GTID再从主节点重新初始化数据然后再START GROUP_REPLICATION。千万记住别在有业务数据的机器上贸然RESET。第三个坑是大事务。上线后某天突然发现整个集群的查询全变慢写入也几乎卡住。排查后定位到是某个批量操作一个事务更新了几百万行MGR要把这个事务广播给所有节点还要做冲突检测整个组的吞吐被这个笨重事务拖死。从那以后我把应用里的大批量更新全部拆成小批量每个事务控制在几千行以内再没出现过类似情况。5.3 主节点切换手动与自动各有讲究自动切换场景如果主节点宕机或网络断开组内剩下的节点会进行primary election自动推举一个新主。这时候应用的写入连接要能自动找到新主通常靠VIP漂移或者应用层做节点感知。MGR本身不做VIP这一点要自己解决。手动切换的场景一般是计划内维护比如要给旧主升级硬件。我推荐的做法是先在想让它成为新主的节点上调高权重SET GLOBAL group_replication_member_weight 100;然后停掉旧主节点的组复制STOP GROUP_REPLICATION;组内节点会根据权重重新选举权重最高的node2大概率会成为新主。等旧主维护完重新START GROUP_REPLICATION加回来它会自动作为从节点追平数据非常顺畅。需要注意一点单主MGR的failover不是0秒切换从节点感知到主节点故障到发起选举通常需要几秒钟。应用层如果连得上VIP这块时间就是停机窗口的最小值。对日志要求毫秒级的支付类业务还得在MGR之上再做一层数据保护不能裸奔。另外每次版本升级前先把exit_state_actionREAD_ONLY确认好再逐节点滚动升级一个节点一个节点来别同时停两台否则多数派挂掉整个组就进保护了。这套MGR单主集群我这边已经稳定跑了一年多最直观的感受是自动故障转移终于不用再靠外部脚本提心吊胆了节点的加入和退出都变得很干净数据一致性也有Paxos在兜底。但本质上它解决的是高可用问题解决不了高并发写入扩容问题单主的写入上限还是单机上限。另外所有表一定要有主键事务一定要控制大小这两条是MGR用得长久的基本前提。如果你们也在评估高可用方案不妨先把这套单主集群在测试环境原样跑一遍体会一下它跟传统主从的差别再决定要不要上生产。
返回列表