一、节点掉队与无法加入集群
1.现象
节点启动后一直卡在 Joining 或 Donor/Desynced 状态,无法进入 Synced。
2.排查步骤
1. 检查节点状态
sql
SHOW STATUS LIKE 'wsrep_local_state_comment';
常见状态含义:
| 状态 | 含义 |
|---|---|
| Joining | 正在接收 SST/IST 数据 |
| Donor/Desynced | 正在作为 SST 捐赠节点,暂时不参与集群写入 |
| Synced | 正常同步,可接受读写 |
| Error | 出现严重错误,需查看日志 |
2. 检查错误日志
bash
tail -f /var/log/mariadb/mariadb.log
# 或
journalctl -u mariadb -f
3. 常见原因与解决
-
网络不通或端口未放行:确认 3306、4567、4568、4444 端口在节点间互通
bash1# 从 node2 测试到 node1 的连通性 2nc -zv 192.168.31.185 4567 -
SST 认证失败 :检查
wsrep_sst_auth配置是否正确,SST 用户是否在所有节点上存在且密码一致sql-- 创建 SST 用户(所有节点执行) CREATE USER 'sst_user'@'localhost' IDENTIFIED BY 'sst_password'; GRANT RELOAD, LOCK TABLES, PROCESS, REPLICATION CLIENT ON *.* TO 'sst_user'@'localhost';配置文件中添加:
bashwsrep_sst_auth = "sst_user:sst_password" -
grastate.dat 损坏 :节点异常宕机后,
/var/lib/mysql/grastate.dat中的safe_to_bootstrap可能为 0,导致无法启动bashcat /var/lib/mysql/grastate.dat # 输出示例: # GALERA saved state # version: 2.1 # uuid: a1b2c3d4-xxxx-xxxx-xxxx-xxxxxxxxxxxx # seqno: -1 # safe_to_bootstrap: 0如果确认该节点是最后正常关闭的,可以手动改为
safe_to_bootstrap: 1,然后使用galera_new_cluster启动
二、脑裂(Split-Brain)问题
1.什么是脑裂
当集群因网络分区被拆分为两个或多个无法互相通信的子集时,如果每个子集都认为自己是"主组件"并继续接受写入,就会导致数据不一致------这就是脑裂。
2.Galera 的防护机制
Galera 基于**多数派(Quorum)**原则:只有包含超过半数节点的子集才能成为 Primary Component 并继续接受写入。少数派节点自动进入 Non-Primary 状态,拒绝所有查询。
sql
-- 查看当前节点是否在主组件中
SHOW STATUS LIKE 'wsrep_cluster_status';
-- Primary = 正常,Non-Primary = 脑裂/少数派
3.预防方案
- 始终使用奇数节点(3、5、7),确保总能产生多数派
- 部署 Galera Arbitrator(garbd):在偶数节点集群中,garbd 作为轻量级仲裁者参与投票,但不存储数据
bash
# 在独立机器上启动 garbd
garbd --address='gcomm://192.168.31.185,192.168.31.186' \
--group='mariadb_galera_cluster' \
--daemon
配置文件方式(/etc/sysconfig/garb):
bash
address="gcomm://192.168.31.185,192.168.31.186"
group="mariadb_galera_cluster"
options=""
log="/var/log/garbd.log"
4.脑裂恢复
如果集群确实发生了脑裂(如 2 节点集群一个宕机),幸存节点会进入 Non-Primary 并拒绝服务。恢复方法:
方法一:Bootstrap 幸存节点(推荐)
bash
-- 在幸存节点上执行,强制其成为新的主组件
SET GLOBAL wsrep_provider_options='pc.bootstrap=YES';
当其他节点恢复后,会自动进行 SST 同步并重新加入集群。
方法二:忽略脑裂(危险,仅限特殊场景)
sql
-- 强制允许少数派节点继续写入(可能导致数据不一致!)
SET GLOBAL wsrep_provider_options='pc.ignore_sb=TRUE';
⚠️ 此操作极其危险,仅在你完全理解风险且能手动解决数据冲突时使用。
三、同步延迟与 Flow Control
1.现象
集群写入变慢,日志中出现大量 Flow Control PAUSE/RESUME 信息。
2.监控指标
sql
-- 查看关键性能指标
SHOW STATUS LIKE 'wsrep_flow_control_paused'; -- 被流控暂停的时间比例,>0.2 说明有问题
SHOW STATUS LIKE 'wsrep_local_recv_queue'; -- 当前接收队列长度,应接近 0
SHOW STATUS LIKE 'wsrep_local_recv_queue_avg'; -- 平均接收队列长度
SHOW STATUS LIKE 'wsrep_local_send_queue'; -- 发送队列长度
SHOW STATUS LIKE 'wsrep_flow_control_sent'; -- 发送 PAUSE 消息的次数
wsrep_flow_control_paused 接近 0.0 表示健康;达到 0.2 或更高说明集群存在瓶颈。
3.原因分析与解决
原因一:某节点硬件性能不足
某个节点 CPU/磁盘 I/O 明显弱于其他节点,应用事务速度跟不上接收速度。
→ 解决:升级该节点硬件,或将写负载均匀分配
原因二:应用线程不足
wsrep_slave_threads 设置过低,多核 CPU 未被充分利用。
sql
# 建议设为 CPU 核心数的 1~1.5 倍
wsrep_slave_threads = 8
原因三:大事务阻塞
单次写入大量数据(如百万行 INSERT)会生成巨大的 write-set,阻塞整个集群。
→ 解决:将大事务拆分为小批次
sql
-- 错误做法:一次性插入百万行
INSERT INTO big_table VALUES (...), (...), ... ; -- 百万行
-- 正确做法:分批插入,每批 1000 行
INSERT INTO big_table SELECT * FROM temp_table LIMIT 1000 OFFSET 0;
INSERT INTO big_table SELECT * FROM temp_table LIMIT 1000 OFFSET 1000;
-- ...
原因四:流控参数调优
sql
[galera]
wsrep_provider_options="gcache.size=4G; gcs.fc_limit=256; gcs.fc_factor=0.45"
| 参数 | 默认值 | 调优建议 | 说明 |
|---|---|---|---|
gcs.fc_limit |
100 | 128~512 | 增大可给慢节点更多缓冲,但会增加落后程度 |
gcs.fc_factor |
0.8 | 0.4~0.5 | 降低可让流控更早触发,防止队列溢出 |
gcache.size |
128M | 4G~16G | 增大可提高 IST 成功率,避免昂贵的 SST |
四、SST 失败或耗时过长
1.现象
新节点加入或故障节点恢复时,SST 过程失败或耗时数小时。
2.排查与优化
更换 SST 方法
| 方法 | 特点 | 适用场景 |
|---|---|---|
rsync |
简单快速,但会锁定捐赠节点 | 小数据库(<50GB) |
mariabackup |
非阻塞,捐赠节点可继续服务 | 生产环境推荐 |
mysqldump |
最慢,但最安全 | 跨版本迁移 |
ini
# 推荐使用 mariabackup
wsrep_sst_method = mariabackup
wsrep_sst_auth = "sst_user:sst_password"
增大 GCache 避免 SST
如果节点只是短暂离线(如重启),可以通过 IST(增量传输)快速恢复,而无需全量 SST。前提是 GCache 中保存了离线期间的所有 write-set:
ini
wsrep_provider_options="gcache.size=8G"
五、写冲突(Deadlock)
1.现象
应用报错:ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
2.原因
Galera 使用乐观并发控制(OCC):不同节点同时修改同一行数据时,后提交的节点会检测到冲突并回滚。
3.解决方案
- 应用层重试:捕获 1213 错误并重试事务
- 分散写入:尽量让不同节点处理不同主键范围的数据
- 使用负载均衡:通过 ProxySQL/HAProxy 将同一业务实体的写入路由到同一节点
四、全集群关闭后的重启
这是运维中最容易出错的场景之一。
1.正确步骤
1. 找到最后关闭的节点
检查每个节点 /var/lib/mysql/grastate.dat 中的 seqno 值,seqno 最大的节点是最后正常关闭的:
bash
cat /var/lib/mysql/grastate.dat
2. 在该节点上引导集群
bash
# 确保 grastate.dat 中 safe_to_bootstrap: 1
galera_new_cluster
3. 其他节点正常启动
bash
systemctl start mariadb
2.所有节点异常宕机
如果所有节点都崩溃(如断电),grastate.dat 中 seqno 可能为 -1。此时需要:
bash
# 在每个节点上查找最新的 seqno
mysqld_safe --wsrep-recover
# 查看日志中的恢复序列号
grep "Recovered position" /var/log/mariadb/mariadb.log
# 选择 seqno 最大的节点,修改 grastate.dat
# 将 safe_to_bootstrap 改为 1,填入正确的 seqno
galera_new_cluster
五、生产环境监控建议
1.关键监控指标
bash
-- 一键检查集群健康状态
SELECT
(SELECT VARIABLE_VALUE FROM information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='wsrep_cluster_size') AS cluster_size,
(SELECT VARIABLE_VALUE FROM information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='wsrep_cluster_status') AS cluster_status,
(SELECT VARIABLE_VALUE FROM information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='wsrep_local_state_comment') AS local_state,
(SELECT VARIABLE_VALUE FROM information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='wsrep_ready') AS ready,
(SELECT VARIABLE_VALUE FROM information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='wsrep_flow_control_paused') AS fc_paused,
(SELECT VARIABLE_VALUE FROM information_schema.GLOBAL_STATUS WHERE VARIABLE_NAME='wsrep_local_recv_queue_avg') AS recv_queue_avg;
2.告警规则建议
| 指标 | 告警阈值 | 含义 |
|---|---|---|
wsrep_cluster_size |
< 预期节点数 | 有节点掉线 |
wsrep_cluster_status |
≠ Primary | 脑裂或少数派 |
wsrep_local_state_comment |
≠ Synced | 节点未完全同步 |
wsrep_flow_control_paused |
> 0.2 | 流控频繁,性能下降 |
wsrep_local_recv_queue_avg |
> 100 | 同步延迟严重 |
3.负载均衡配置(HAProxy 示例)
生产环境务必使用负载均衡器,避免应用直连单节点:
bash
listen galera_cluster
bind *:3306
mode tcp
balance roundrobin
option tcp-check
server node1 192.168.31.185:3306 check port 9200 inter 5s
server node2 192.168.31.186:3306 check port 9200 inter 5s
server node3 192.168.31.187:3306 check port 9200 inter 5s
💡
port 9200可配合自定义健康检查脚本,通过查询wsrep_local_state_comment是否等于Synced来判断节点是否健康。
六、总结速查表
| 问题 | 快速排查命令 | 常见解决 |
|---|---|---|
| 节点无法加入 | SHOW STATUS LIKE 'wsrep%'; + 查日志 |
检查网络、SST 用户、防火墙 |
| 脑裂 | SHOW STATUS LIKE 'wsrep_cluster_status'; |
pc.bootstrap=YES 或部署 garbd |
| 同步延迟 | SHOW STATUS LIKE 'wsrep_flow_control%'; |
增加 wsrep_slave_threads、拆分大事务 |
| SST 失败 | 查 /var/log/mariadb/mariadb.log |
换用 mariabackup、检查权限 |
| 写冲突 | 应用报 ERROR 1213 |
应用层重试、分散写入 |
| 全集群重启 | 查 grastate.dat 的 seqno |
在 seqno 最大节点执行 galera_new_cluster |