
在互联网公司做DBA这些年MySQL高可用方案我踩过的坑可以写一本书。最早用的主从复制VIP漂移主库一宕机就得手动或者半自动切换赶上从库binlog追不上业务损失以分钟计。后来上了MHA架构复杂度上去了脑裂问题照样让你凌晨爬起来。再后来我接触了Percona XtraDB ClusterPXC一个基于Galera协议的同步多主集群部署一次之后我对高可用这三个字的理解彻底变了。这篇文章把我生产环境落地PXC的全过程整理出来包括为什么选它、环境怎么准备、配置文件里每个wsrep参数到底是什么意思、集群怎么从零拉起、日常该关注哪些指标最后是我真实踩过的几个坑。适合正在评估MySQL高可用方案的同学也适合已经决定用PXC但怕踩坑的运维和DBA参考。1. 为什么是PXC从主从到多主同步的选择逻辑我记得第一次听说PXC是在一个数据库技术分享会上当时心里第一反应是多主那数据冲突怎么解决后来系统了解Galera协议才明白PXC并不是让多个节点随意竞争写入而是通过一套严格的同步复制机制让每个节点上的事务保持一致。传统主从复制的核心链路是主库写binlog从库拉取binlog然后自己重放。这带来两个绕不开的问题。一个是延迟主库提交之后从库什么时候追上完全看网络和从库自身压力赶上大事务或者从库磁盘慢几分钟甚至几十分钟的延迟都可能出现。另一个是切换风险主库突然宕机从库可能还缺最后那部分事务强制切换的结果就是丢数据。半同步复制解决了日志已经收到的问题但也只是保证 relay log 写到了从库至于relay log有没有被真正应用主库是不关心的。MHA加VIP的方案更成熟但整体链路长需要额外维护监控和切换脚本而且切换时依然有一段不可写的时间窗口。PXC走的是另一条路。它底层用了Galera协议节点之间通过gcomm基于TCP/UDP的组通信交换写入集write set。一个事务在任何节点上提交时需要先在集群内做certification认证让所有节点都确认这个事务不会和别的节点产生冲突然后要么全集群都提交要么全集群都回滚。这就是同步复制和多主一致的真正含义。这样说可能有点抽象我用一个生活化的类比。传统主从像公司只有一个经理做决策记录完把会议纪要发给副手们副手们什么时候看完看心情。PXC像所有部门负责人坐在一起开会任何一个提案必须在场所有人当场点头才算通过任何一个人否决整场决策就推翻重来。既然数据一致性这么强是不是所有场景都该上PXC不是。它有个必须接受的代价因为每个事务都要经过集群认证节点之间的网络延迟会直接叠加到事务响应时间上。跨机房几百毫秒的延迟在PXC里就是不可接受的。另外如果一个节点突然失联集群为了保证一致性会把正在提交的事务阻塞或者中止这种推进不了的状态对可用性是有影响的。所以我的建议是核心交易类、要求数据强一致、并发写入可控的业务适合PXC跨地域部署、单点写入巨大、对极端可用性要求极高的场景还是要谨慎评估。选型时还要注意一点PXC前身是Codership的Galera ClusterPercona把它和Percona Server for MySQL封装成了开箱即用的版本SST同步工具默认用的就是Percona XtraBackup。所以生产环境我更推荐直接用Percona官方源安装而不是自己拼Galera和MySQL版本兼容性省心很多。2. 部署前的环境盘点节点规划、系统参数与依赖安装PXC的部署不复杂但前期的环境准备如果做草率了后面排错会非常痛苦。我先说节点规划再说系统参数最后说软件安装。2.1 三节点规划主机名、IP与存储我这次用的是三台物理机配置见下面这张表。数据库集群节点不建议少于三个因为其中一个节点专门用于处理SST传输时另外两个节点还能继续保持可用。节点主机名IP地址角色node1pxc-node1.example.local192.168.10.11初始引导节点node2pxc-node2.example.local192.168.10.12普通集群节点node3pxc-node3.example.local192.168.10.13普通集群节点硬件方面每个节点配置了8核CPU、32GB内存、两块SSD做RAID1。在PXC里所有节点数据完全一致所以每个节点的性能配置最好一致不要出现一个节点是高端服务器其余是低配的情况写入时慢节点会拖累整个集群。存储这块我特意强调一下Galera的认证过程依赖快速IOSSD是基本要求。机械盘在传统主从上可能只是延迟高一点PXC里可能直接表现为集群整体变慢甚至超时。另外数据目录独立分区不要把日志和数据放在同一个逻辑卷。2.2 系统级准备hosts、SELinux与防火墙第一步先做主机名映射三台机器都要在/etc/hosts里写上三个节点的对应关系192.168.10.11 pxc-node1 pxc-node1.example.local 192.168.10.12 pxc-node2 pxc-node2.example.local 192.168.10.13 pxc-node3 pxc-node3.example.local这样配置的好处是集群地址可以写主机名而不是IP后续如果换IP不需要改动所有节点的配置。我在生产环境见过有人直接写IP结果机房调整一次就要全部改一遍非常被动。SELinux我直接选择关闭。技术上可以放行相关端口和域但PXC涉及的进程、端口、SST脚本太多放行规则写起来繁琐出问题也不容易排查。测试环境或者对安全要求极高的环境可以单独写SELinux模块但我大多数生产环境采用的都是关闭策略。防火墙需要放行以下几个端口端口用途3306MySQL客户端连接4444SST全量同步传输xtrabackup等4567Galera集群节点间通信含组播与单播4568IST增量状态传输命令大概是firewall-cmd --permanent --add-port3306/tcp firewall-cmd --permanent --add-port4444/tcp firewall-cmd --permanent --add-port4567/tcp firewall-cmd --permanent --add-port4567/udp firewall-cmd --permanent --add-port4568/tcp firewall-cmd --reload这里有个容易忽略的点4567不只要放TCPUDP如果用了组播也要放行否则节点会发现不了彼此。云主机的话对应的安全组规则要同步放行。2.3 安装Percona软件源和PXC软件包我用的是CentOS 7.9安装Percona的官方源yum install -y https://repo.percona.com/yum/percona-release-latest.noarch.rpm percona-release enable pxc-80 release yum install -y percona-xtradb-cluster这里建议指定小版本避免三个节点在滚动更新时出现版本不一致。软件包安装完之后可以用rpm -ql确认一下libgalera_smm.so的位置后面配置wsrep_provider要用到rpm -ql percona-xtradb-cluster | grep galera我装的时候这个库默认在/usr/lib64/libgalera_smm.so。不同版本、不同架构路径可能有差异配置之前先确认一遍避免启动时报找不到模块。2.4 系统调优文件句柄与THP数据库对系统资源的敏感性远超普通应用。打开文件句柄我先放到65535以上具体在/etc/security/limits.conf里加上mysql soft nofile 65535 mysql hard nofile 65535然后关闭透明大页THP。MySQL和XtraDB对THP一直不太友好内存页在数据库场景里抖动会导致性能忽高忽低。关闭方式echo never /sys/kernel/mm/transparent_hugepage/enabled echo never /sys/kernel/mm/transparent_hugepage/defrag写进rc.local或者systemd临时脚本里保证重启后依然生效。这一步不做好PXC跑起来之后在压测阶段性能曲线会很难看。3. 配置文件逐项拆解那些必须懂的wsrep参数PXC安装完系统里会带一份/etc/percona-xtradb-cluster.conf.d/目录里面分成mysqld.cnf、mysqld_safe.cnf老版本等文件。我习惯把所有关键配置放在一个地方统一管理避免改参数时漏掉某个文件。三个节点的配置文件大体相同区别只有节点名和地址。下面是核心配置我加上了注释关于每个参数为什么这么设下面逐一展开。[mysqld] server_id11 binlog_formatROW default_storage_engineInnoDB innodb_autoinc_lock_mode2 wsrep_provider/usr/lib64/libgalera_smm.so wsrep_cluster_namepxc-production-cluster wsrep_cluster_addressgcomm://pxc-node1,pxc-node2,pxc-node3 wsrep_node_namepxc-node1 wsrep_node_addresspxc-node1 wsrep_sst_methodxtrabackup-v2 wsrep_sst_authsstuser:sstpasswd wsrep_slave_threads83.1 三个必须ROW格式、InnoDB与autoinc锁模式第一个必须binlog_format必须是ROW。Galera的写集是基于行的如果binlog格式是STATEMENT或者MIXED部分基于语句的复制在并发冲突检测时会产生不一致的判定结果。这个参数直接写死没有商量余地。第二个必须default_storage_engine是InnoDB。PXC只支持InnoDB以及XtraDBMyISAM表在PXC里创建出来也是不可复制的。如果你把历史遗留的MyISAM表迁移到PXC记得先用ALTER TABLE改成InnoDB。第三个必须innodb_autoinc_lock_mode2。这是Galera的硬性要求改回1会导致自增主键在并发写入时产生冲突。原因在于PXC多个节点都可能分配自增值传统主从模式下主库串行分配自增值没问题而多主场景必须放弃表级锁式的连续分配改用interleaved交错式分配。对应用来说唯一的区别是自增ID不再严格连续如果业务层依赖这个需要提前评估。3.2 集群通信四个参数provider、cluster_name、cluster_address、node_namewsrep_provider指向Galera库文件。它决定了mysqld启动时加载哪个同步引擎路径不对会直接启动失败。wsrep_cluster_name是集群的逻辑名称三个节点必须完全一致。这个名字同时用于区分多个PXC集群它不参与网络路由只是校验节点是否属于同一个集群。命名规范建议带上环境后缀比如pxc-prod-cluster-01方便区分。wsrep_cluster_address是集群成员列表推荐写法是gcomm://节点1,节点2,节点3。这里可以写主机名也可以写IP配合hosts文件用主机名最省心。注意这个列表不是本机连哪几个而是整个集群的成员有哪些每个节点都要写全。wsrep_node_name和wsrep_node_address是本节点的身份标识。node_name建议唯一方便在监控里区分节点。3.3 SST方式与认证为什么我选xtrabackup-v2SSTState Snapshot Transfer状态快照传输是新节点加入集群时获取全量数据的方式。PXC支持mysqldump、xtrabackup等。我在生产环境只推荐xtrabackup-v2。理由很直接mysqldump在几GB的数据上还能忍到了几百GB以上几乎不可用而且逻辑备份在恢复大表时会产生大量随机IO。xtrabackup是物理备份基于InnoDB的redo/undo机制做热备份速度快得多适合大数据量。wsrep_sst_auth是SST同步时使用的数据库账号和密码。这个账号要预先在引导节点上创建好不然第二个节点加入时SST认证会失败。后面启动部分我会给出具体的创建命令。3.4 复制线程数与常规性能参数补全wsrep_slave_threads是节点上用于并行应用复制写集的线程数。我一般设置为CPU核数也可以按核数的1-2倍配实测8核机器设8个线程比较稳妥。这里不要拍脑袋设一个很大的数线程过多反而增加上下文切换开销。常规的MySQL性能参数比如innodb_buffer_pool_size、max_connections、innodb_log_file_size依然按单实例的标准做配置。PXC只是复制层不同存储引擎层还是InnoDB那一套。我这次32GB内存buffer pool分配到20GB具体的值需要结合你机器的实际负载调整。另外别忘了在mysqld_safe或者systemd环境里加一条limit设置文件句柄和进程数都放开配合前面limits.conf里的ulimit配置双保险。4. 集群拉起全过程从零节点引导到三节点全部加入配置准备好之后进入最关键的启动环节。这里有一个必须记住的原则三节点集群第一次启动只能有一个节点使用引导模式bootstrap其他节点用普通模式启动。如果多个节点同时用引导模式等于同时产生两个主分区后果就是脑裂。4.1 引导第一个节点bootstrap只在本次有效第一个节点执行systemctl start mysqlbootstrap这条命令在CentOS 7/8的systemd环境下等价于mysqld_safe --wsrep-new-cluster。它告诉Galera我是第一个节点我拉起一个新的集群分区。启动完成后登录MySQL查看状态SHOW STATUS LIKE wsrep_cluster_size; SHOW STATUS LIKE wsrep_local_state_comment;正常情况下wsrep_cluster_size1wsrep_local_state_commentSynced。这个节点现在是一个只有自己的单节点集群但是数据写入已经进入Galera模式了。4.2 创建SST同步账号在引导节点上执行CREATE USER sstuserlocalhost IDENTIFIED BY sstpasswd; GRANT RELOAD, LOCK TABLES, PROCESS, REPLICATION CLIENT ON *.* TO sstuserlocalhost; FLUSH PRIVILEGES;如果安装的是PXC 8.0还需要加上BACKUP_ADMIN权限8.0的xtrabackup需要这个权限才能做备份和恢复GRANT BACKUP_ADMIN ON *.* TO sstuserlocalhost;这个账号为什么用localhost因为SST传输时xtrabackup是在本机通过socket连到本机的mysqld来备份的从SST发起方视角看就是本机连接不需要远程访问。这里踩坑的人很多我见过有人把host设成%反而增加了暴露面。4.3 启动第二、第三个节点正常systemctl start即可第二、第三个节点执行systemctl start mysql对就是普通的启动。节点启动后会发现wsrep_cluster_address里有成员列表于是通过gcomm协议与引导节点同步元数据然后触发SST流程从已有节点拉取一次全量数据应用完成之后进入Synced状态。这里有个很容易误操作的点如果集群已经存在某节点重启一定不要用mysqlbootstrap。我见过新人运维在节点故障后手动启动了bootstrap直接把集群从Primary分区里分离出去造成全集群不可写。正确操作是普通启动即可节点会自动找现有集群并同步数据。4.4 验证集群状态三个节点都启动后在任意节点执行SHOW STATUS LIKE wsrep_%;重点看几个值状态项期望值含义wsrep_cluster_size3集群成员数wsrep_local_state_commentSynced本节点已同步wsrep_cluster_statusPrimary集群处于主分区wsrep_connectedON本节点已连接集群再做一个写测试在node1上建一张测试表并插入数据回到node2和node3上查数据应该立即可见。这一步验证的是同步复制是否真的生效也可以顺手验证应用连接串随便指向哪个节点都能读到最新数据。4.5 重置引导标记与后续启动顺序集群正常运行后每次重启集群不一定要用node1引导。选择哪个节点做bootstrap关键是确认它拥有最新的完整数据。更稳妥的做法是把集群停掉后检查每个节点数据目录下的grastate.dat找到safe_to_bootstrap1的节点用它执行bootstrap再让其他节点普通启动。这个文件的路径在数据目录下比如/var/lib/mysql/grastate.dat。文件内容包含seqno和safe_to_bootstrap字段。每次干净关闭节点后seqno会递增safe_to_bootstrap标记只有最后一个正常关闭且数据完整的节点才会置1。如果所有节点非正常宕机safe_to_bootstrap可能都是0这时候就要靠人工判断数据完整性来选引导节点了。5. 日常运维的几个关键动作备份、参数调整与状态监控PXC上线的第一周我几乎每天都要盯着状态指标。很多问题在指标上是先有预兆的等真正报错已经晚了。这一节我分享三个日常动作怎么备份、怎么调整参数、怎么看指标。5.1 备份策略物理备份优先注意单节点IO因为PXC所有节点数据一致理论上备份任何一个节点都能拿到完整数据。我建议用Percona XtraBackupPXB对其中一个节点做物理备份xtrabackup --backup --target-dir/backup/pxc-full-$(date %F) \ --userbackup_user --passwordxxx --host127.0.0.1备份时再加上binlog的增量备份形成全量增量的组合恢复时先还原全量再应用增量binlog。这里有个PXC特有的注意点备份节点本身也是承担流量的PXB全量备份期间会读大量数据对其他节点的写入会造成流控flow control。所以大库备份一定安排在业务低峰或者轮换着从不同节点备份避免某节点长期高IO。另外PXC 8.0的PXB工具要选择与实例大版本匹配的版本比如8.0.30的PXC要用8.0.34版本的PXB来备份恢复版本错位会导致无法识别数据文件。5.2 参数调整静态参数与动态参数分开对待PXC大部分wsrep参数是静态的修改后必须重启节点。重启单个节点不影响集群可用性但需要注意滚动顺序逐个重启确保每次集群中至少有N-1个节点存活。因为PXC需要多数派节点才能正常提交事务三节点集群如果有两个节点同时不可用剩下的那一个节点会进入non-Primary状态整个集群不可写。动态参数可以用SET GLOBAL的方式修改但要注意动态修改只对当前节点生效。想把配置固化的话记得把参数同步写进配置文件否则下次重启就还原了。有一个参数我特别提一下wsrep_max_ws_size和wsrep_max_ws_rows。这两个限制了单个事务的写集大小。默认配置对绝大多数业务够用但如果在PXC里执行超大事务比如批量更新几百万行可能直接报transaction too large的错误。遇到这种场景可以适度调大限制但根本上还是要从应用侧拆分大事务。5.3 状态指标我看哪几个值判断集群健康日常巡检我用一条SQL就够了SHOW GLOBAL STATUS LIKE wsrep_%;重点关注wsrep_cluster_status必须是Primary一旦显示non-Primary意味着节点失去了多数派集群进入保护状态。wsrep_flow_control_paused反映节点被流控阻塞的时间比例。持续大于0.5说明集群某个节点写入慢拖慢了整体。wsrep_last_committed三个节点这个值应当基本接近差距过大说明某个节点同步滞后。wsrep_local_state_commentSynced是正常Joining/Donor出现时说明正在做SST或IST。这三个节点之间的延迟监控我直接写了一个简单的shell脚本每30秒轮询一次把wsrep_last_committed的差值打印出来超过阈值就告警。比看负载和CPU更能直接反映Galera层的健康状况。6. 我踩过的坑启动顺序、磁盘空间、网络超时与慢速SST这一节是全文最贵的部分。以下问题我在测试环境和生产环境都真实遇到过有些坑在官方文档里写得不够直白我在这里完整还原排查链路。6.1 第二节点加入时SST一直失败的排查现象node2执行systemctl start mysql后日志里反复出现State transfer failed或者WSREP: Failed to prepare for state transfer。排查思路先看错误日志。PXC的错误日志路径在/var/log/mysql/error.log搜索WSREP相关条目。通常能看到两种原因一种是SST认证失败提示access denied另一种是SST传输过程中断。如果是认证失败检查wsrep_sst_auth里写的账号密码是否和4.2节创建的一致注意别把创建时用的host写错。如果是传输中断十有八九是磁盘空间。xtrabackup做SST时在Donor节点提供数据的节点和Joiner节点新加入节点两端都需要临时存储空间。Joiner节点数据目录所在分区的可用空间小于数据总量时xtrabackup stream到一半就会报错。我当时遇到的坑就是node2的数据盘只给了50GB而主节点数据已经有80GBSST跑一会就把磁盘写满了。解决方式数据盘扩容到数据的1.5倍以上或者临时往另一个磁盘写SST再调整xtrabackup相关临时目录配置。这里给一个明确判断命令df -h /var/lib/mysql如果使用率超过90%先解决空间问题再谈SST。6.2 节点重启后反复走慢速SST现象node3只是宕机了10分钟启动后不是走IST增量同步而是又做了一次全量SST几小时才恢复。原因分析SST和IST的选择逻辑取决于Joiner在加入时集群里是否还保留着它缺失的那部分事务。如果Joiner的grastate.dat里seqno比Donor落后太多超出了Donor的保留窗口就必须走全量SST。另外如果Joiner数据的safe_to_bootstrap被标记为0且无法验证数据完整性也会退回到全量SST。这里我先解释一下IST和SST的区别。SST是把整份数据打包给你对应的是全量快照传输速度慢且消耗大量网络和磁盘。IST是你缺多少我给你补多少基于Donor的gcache缓冲做增量传输快得多。日常节点短时间重启都应该走IST如果每次都全量SST多半是配置或者数据清理策略有问题。我当时排查发现是我在配置文件里把wsrep_sst_method改成了mysqldump为了测试对比mysqldump无法做增量SST于是一律全量。换回xtrabackup-v2并确保gcache够大之后节点重启基本都走IST。这里补充一个重要的运维习惯如果节点只是进程崩溃而数据文件完整启动前可以先检查grastate.dat里的seqno比Donor落后多少如果差距很小直接普通启动多数会走IST。不要贸然删除grastate.dat删除后节点必然全量SST。6.3 两个节点同时失联剩下的节点变non-Primary现象机房网络抖动node2和node3同时断连node1日志里出现WSREP: failed to reach primary view并且数据库只读不可写。原因PXC是多数派原则。三节点集群只有node1一个存活存活节点数不满足多数派为了防脑裂集群主动进入non-Primary状态拒绝写入。这是设计行为不是故障。此时如果node2、node3恢复网络三个节点重新握手后会恢复Primary。我在这里吃过一个亏当时误以为node1坏了手动在node1上执行了bootstrap试图拉起新集群结果node2、node3恢复之后发现已经分离成两个分区数据出现分裂。正确的做法是等待失联节点网络恢复让集群自己恢复多数派视图。如果失联节点确实无法恢复比如物理宕机需要人工介入保留数据完整的节点作为新引导节点其他节点重新加入。这种场景下操作顺序和之前章节说的引导逻辑一致关键是要确认哪个节点的seqno最新、数据最完整。6.4 慢速SST和网络带宽的纠缠SST同步本质上是一次全量数据拷贝几百GB数据在千兆网卡上跑传输阶段就要几十分钟加上xtrabackup的备份和恢复整体可能数小时。我遇到过因为SST占用带宽导致业务查询变慢的情况。解决思路有三个层面一是业务低峰期进行节点扩容二是专门配一条内网高速链路用于节点间数据传输比如万兆网卡三是给SST配置限速通过wsrep_sst_xtrabackup相关的参数控制备份速率避免拖垮业务流量。另外一个容易被忽视的细节云主机如果用了公网IP互连做集群SST流量会走公网不仅慢还可能有额外费用。生产环境一定要用内网互通地址配置wsrep_cluster_address。最后说一句个人体会。PXC让DBA在数据一致性这件事上省了很多心但对运维的基本功要求反而更高了——你得清楚理解每个节点启动时到底在做什么得习惯在出问题的时候先看grastate.dat和error log而不是凭感觉重启。把部署和启动逻辑吃透了PXC是一个相当省心的集群反之任何一个细节的疏忽都会在后续某次故障里加倍还回来。