MySQL 主从复制的痛点,用过的人都懂:从库是异步的,主库写入了、从库还没收到就宕机,这部分数据就丢了;主库挂了要手动切换,切的过程中应用报错;读写在应用层散落一地,改一次架构要动一堆代码。传统主从能解决"读扩展"和"备份",但解决不了"高可用"——真正的故障自动转移,需要别的方案。
MariaDB Galera Cluster 就是冲着这个问题来的。它提供多主同步复制:任意一个节点都能读写,写入时通过认证协议同步到所有节点,所有节点数据强一致,任意节点宕机集群继续服务,不用改一行应用代码(前提是表用 InnoDB)。这篇文章讲清楚 Galera 的原理、三节点集群的搭建、跨机房部署的坑,以及它到底适合什么样的个人站场景。
一、Galera 的核心:同步复制与认证协议
先建立一个最重要的认知:Galera 是"写集"(write set)级别的同步复制,不是语句级、也不是行级。它的工作流程是这样的:
- 客户端连到某个节点,执行事务提交。
- 该节点把这次事务的所有改动打包成一个 write set。
- write set 通过 galera 组通信广播给集群里所有其他节点。
- 其他节点做认证(certification)——检查这个 write set 和自己本地是否有冲突(比如是否同时改了同一行)。
- 认证通过后,所有节点(包括发起节点)才真正 apply 到本地存储引擎,然后返回提交成功。
这里有两个关键点。第一,提交必须等到所有节点确认才返回,所以它是同步的——一致性级别最高,但写延迟取决于最慢的那个节点。第二,认证阶段是冲突检测的核心:如果两个节点同时改了同一行,其中一个会在认证阶段被拒绝,返回死锁错误(ER_LOCK_DEADLOCK),应用需要重试。
这带来一个必须理解的行为:Galera 集群下,和主从不同,"读"也不一定能读到最新的数据?不,恰恰相反——因为提交是同步的,任何节点提交成功后,其他所有节点都已经有这份数据了。所以从任意节点读取都能读到最新值,这是 Galera 相对异步主从最大的优势(代价是写放大、延迟高)。
二、多主 vs 主从:什么时候选 Galera
Galera 的卖点是"任意节点可读写",但现实中往往不应该真的让所有节点都写。原因很简单:多主意味着并发写冲突的概率大增,认证失败(死锁)会更频繁,尤其是那些"读-改-写"逻辑(先 SELECT 再 UPDATE)在多个节点同时进行时几乎必然冲突。
所以业界的实际做法是:用 Galera 搭集群,但写入只走一个节点(单主模式),其他节点做只读和故障转移。这样既拿到了"节点挂了自动切换"的高可用,又避免了多主冲突。多主的价值在于——当主节点挂掉时,另一个节点立刻可以接手,不需要传统主从那样提升从库、改 VIP、改配置的一堆操作。
选型建议:
- 需要高可用、不能容忍切换期间业务中断 → Galera。
- 只需要读扩展、能容忍短暂停机 → 传统主从更简单、性价比更高。
- 多机房分布式 → Galera 支持跨机房,但对网络延迟极度敏感,见后文。
- 写入量极大、单表高并发 → 慎用 Galera,同步复制会成为写性能瓶颈。
三、前置条件:节点数、InnoDB、主机名
搭 Galera 有几个硬性要求,踩了这几个点基本搭不起来:
1. 至少三个节点。 Galera 用类 Paxos 的多数派机制仲裁。三节点能容忍一个节点故障(存活 2 个仍过半数);两节点是最糟糕的配置——任一个挂了剩下的都无法形成多数派。所以集群规模应该是 3、5、7 这样的奇数。
2. 所有表必须用 InnoDB 引擎。 MyISAM 等非事务引擎不支持 Galera 的复制,遇到 MyISAM 表会直接报错。建库前检查一遍:SELECT table_schema, table_name, engine FROM information_schema.tables WHERE engine != 'InnoDB';
3. 每张表必须有主键。 没有主键的表,认证阶段无法做行级冲突检测,会大幅降低性能。这是 Galera 的一条硬规则。
4. 主机名必须唯一且能互相解析。 Galera 节点间靠主机名通信。三台机器都要在 /etc/hosts 里配好彼此的 hostname → IP 映射,且 hostname 要和机器实际 hostname 一致。
四、三节点集群搭建(逐台操作)
假设三台机器:db1=10.0.0.11、db2=10.0.0.12、db3=10.0.0.13。
第一步:主机名与 hosts。每台机器执行(以 db1 为例):
hostnamectl set-hostname db1
echo "10.0.0.11 db1" >> /etc/hosts
echo "10.0.0.12 db2" >> /etc/hosts
echo "10.0.0.13 db3" >> /etc/hosts第二步:安装 MariaDB 与 Galera。
apt update
apt install -y mariadb-server galera-4 rsync
systemctl stop mariadb这里同时装了 rsync,因为新节点加入集群时默认用 rsync 做 SST(State Snapshot Transfer,全量数据同步)。
第三步:Galera 配置。在 /etc/mysql/mariadb.conf.d/60-galera.cnf 里写:
[mysqld]
binlog_format = ROW
default_storage_engine = InnoDB
innodb_autoinc_lock_mode = 2
innodb_flush_log_at_trx_commit = 0
query_cache_size = 0
query_cache_type = 0
bind-address = 0.0.0.0
wsrep_on = ON
wsrep_provider = /usr/lib/galera/libgalera_smm.so
wsrep_cluster_name = "my_personal_cluster"
wsrep_cluster_address = "gcomm://10.0.0.11,10.0.0.12,10.0.0.13"
wsrep_node_name = "db1"
wsrep_node_address = "10.0.0.11"
wsrep_sst_method = rsync逐条解释关键项:
- innodb_autoinc_lock_mode = 2:Galera 强制要求,因为多主场景下自增 ID 不能依赖表级锁。
- innodb_flush_log_at_trx_commit = 0:官方推荐值,配合 Galera 的同步机制使用,能显著降低写延迟。
- query_cache 关闭:Galera 下查询缓存会导致各节点数据不一致,必须关。
- wsrep_cluster_address:列出所有节点地址。注意这是"首节点引导"用的列表——正常节点启动时它会去连这些地址,找到集群后加入。
- wsrep_sst_method = rsync:全量同步方式。
rsync会锁表(阻塞写),xtrabackup-v2不锁表(推荐生产用,但要装 percona-xtrabackup)。
注意:每台机器只有 wsrep_node_name 和 wsrep_node_address 不同,其余配置一致。
五、引导第一个节点(关键步骤,最容易出错)
集群的第一个节点必须用"引导"方式启动,否则它会尝试去连接一个还不存在的集群,一直失败重试:
# 只在 db1 上执行
galera_new_cluster这个命令做的事,本质是把 wsrep_cluster_address 临时设成 gcomm://(空地址)启动,表示"我是新集群的起点"。启动后验证:
mysql -e "SHOW STATUS LIKE 'wsrep_cluster_size';"应该看到 wsrep_cluster_size 1——集群里目前就它一个。
然后正常启动 db2 和 db3:
# db2 和 db3 上执行
systemctl start mariadb它们会用配置里的 wsrep_cluster_address 找到 db1、加入集群,并触发 SST 把 db1 上的全量数据同步过来。稍等片刻,在任意节点查:
mysql -e "SHOW STATUS LIKE 'wsrep_cluster_size';"
mysql -e "SHOW STATUS LIKE 'wsrep_cluster_status';"
mysql -e "SHOW STATUS LIKE 'wsrep_ready';"期望结果:cluster_size = 3、cluster_status = Primary、wsrep_ready = ON。三项都对了,集群才算真正健康。
六、验证同步复制:写一个节点,读其他节点
在 db1 上建库建表并插入:
mysql -e "CREATE DATABASE IF NOT EXISTS testdb;"
mysql -e "CREATE TABLE testdb.t (id INT PRIMARY KEY, v VARCHAR(50)) ENGINE=InnoDB;"
mysql -e "INSERT INTO testdb.t VALUES (1,'hello galera');"立刻在 db2 和 db3 上查:
mysql -e "SELECT * FROM testdb.t;"数据已经在了——注意是"立刻",没有主从那种延迟。这直观地展示了同步复制的意义。
七、故障演练:干掉一个节点
在 db3 上直接停库模拟宕机:
# db3 上
systemctl stop mariadb然后回到 db1 观察集群状态:
mysql -e "SHOW STATUS LIKE 'wsrep_cluster_size';" # 变成 2
mysql -e "SHOW STATUS LIKE 'wsrep_cluster_status';" # 仍是 Primary
mysql -e "SHOW STATUS LIKE 'wsrep_cluster_members';"集群规模从 3 变 2,但状态依然是 Primary——业务继续可用,写读都不受影响。这就是 Galera 高可用的体现:三节点集群中挂一台,剩下的两台仍能形成多数派(2 > 3/2),照常服务。
再把 db3 启动回来:
# db3 上
systemctl start mariadb它会自动重新加入集群,把宕机期间遗漏的数据同步(IST 增量同步或 SST 全量,取决于差异量),几分钟后 wsrep_cluster_size 回到 3。全程零人工干预——对比传统主从的故障转移流程,这是巨大的运维优势。
但要注意:如果你把 db2 和 db3 同时干掉,只剩 db1 一个节点,它会失去多数派,进入 Non-Primary 状态、拒绝写入。这是 Galera 的保护机制,不是 bug——防止脑裂时两边各自写导致数据分叉。恢复时必须手动引导其中一个节点(galera_new_cluster),这一点官方文档有专节讲,务必读懂再操作。
八、跨机房部署:能,但很痛
站长常常幻想"两个机房各放一台,机房全挂也不怕"。Galera 确实支持跨机房,但它的同步复制对网络延迟极度敏感——提交延迟 = 最慢节点的一次网络往返。同机房内网延迟通常 0.1~0.5ms,跨机房可能 10~50ms,写入吞吐会被直接砍到几分之一。
如果一定要跨机房,两个原则:
- 多数派放在主机房。 例如主机房三节点 + 备机房一节点(甚至备机房只放一个仲裁节点 arbiter),保证主机房独立时仍能形成多数派。绝不要把节点平均分到两个机房(2+2),那样任何一边断了都无法形成多数派。
- 用 gmcast.segment 划分网段。 Galera 支持把节点标记成不同 segment,让复制流量优先在 segment 内传播,减少跨机房往返。
但说实话,对于个人站点的数据量,与其折腾跨机房 Galera,不如老老实实"单机房三节点 Galera + 异地异步备份"。高可用(Galera)解决的是"机器坏了服务不断",异地备份解决的是"机房没了数据还在"——两者是不同层次的需求,不要用 Galera 去替代备份。
九、五个必踩的坑
坑一:用两节点搭集群。两节点没有多数派意义,一台挂了集群就不可用,等于白搭。最小规模是三节点,节点数要奇数。
坑二:忘了 galera_new_cluster,一直用 systemctl start。首次启动集群时必须用 galera_new_cluster 引导,否则节点反复尝试连接一个不存在的集群,wsrep_ready 永远是 OFF。已引导过之后,后续启动一律用 systemctl start,不能再用 galera_new_cluster(会尝试另起一个新集群)。
坑三:表没有主键,或者混入 MyISAM。无主键表导致认证阶段全表扫描、性能暴跌;MyISAM 表直接无法复制。上 Galera 前必须审计表结构。
坑四:SST 用 rsync 又赶上大库。rsync 做 SST 会锁住 donor 节点的表(FLUSH TABLES WITH READ LOCK),大库同步期间业务写入全被阻塞。生产环境应换成 xtrabackup-v2,或者给集群单开一个"donor"节点专门做 SST 数据源,不影响业务节点。
坑五:应用层不处理认证死锁。多主模式下,冲突的写入会在认证阶段被拒,应用收到 ER_LOCK_DEADLOCK。这是 Galera 的正常行为,应用必须有重试逻辑(捕获该错误码、退回事务、重试 2~3 次)。如果直接从主从切过来而不改代码,会看到大量莫名其妙的死锁报错。
十、个人站长该不该上 Galera
诚实地讲:Galera 不是所有个人站的答案。它的复杂度、资源消耗(三台机器)、以及对网络和维护能力的要求都不低。给一个决策参考:
- 单机跑站点、数据量不大、能接受几小时停机恢复:不需要 Galera。一份自动化备份 + 快速恢复脚本性价比高得多。
- 站点有付费用户、对停机敏感、已有两台以上服务器:值得上。三节点里一台做只读从库其实也常见。
- 单纯想扩读、可以接受切换期短暂中断:传统一主多从 + 中间件(ProxySQL)更简单。
Galera 的真正价值不是"多主并发写",而是"故障自动转移、无需人工干预"。想清楚你要的是高可用,而不是把三台机器都用满写能力,选型就不会跑偏。对于把网站当正经事业在做的站长,花几天时间把 Galera 搭起来、把故障演练跑一遍,是值得的投资——因为它换来的,是半夜服务器宕机时你能安心睡觉的底气。