Galera Cluster mariadb 生产环境常见问题排查与运维指南

一、节点掉队与无法加入集群

1.现象

节点启动后一直卡在 JoiningDonor/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 端口在节点间互通

    bash 复制代码
    1# 从 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';

    配置文件中添加:

    bash 复制代码
    wsrep_sst_auth = "sst_user:sst_password"
  • grastate.dat 损坏 :节点异常宕机后,/var/lib/mysql/grastate.dat 中的 safe_to_bootstrap 可能为 0,导致无法启动

    bash 复制代码
    cat /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.datseqno 可能为 -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
相关推荐
雨辰AI1 小时前
K8s 国产数据库慢 SQL 自动监控|Prometheus+Grafana 可视化全落地
数据库·sql·安全·容器·kubernetes·grafana·prometheus
70asunflower1 小时前
Linux 性能排查分析完全教程
linux·运维
房开民1 小时前
PyQt5 常用模块(对应Qt五大模块)
数据库·pyqt
QYRdata1 小时前
Oracle云应用咨询服务驶入增长快车道:2026-2032年复合增长率达8.5%
数据库·oracle
AI办公探索者2 小时前
多租户架构下数据隔离的三种实现方案对比
数据库·ai·oracle·架构
2601_963282772 小时前
寒地专网通信实战:对讲机技术选型、组网优化与东北多行业落地全指南
大数据·数据库·人工智能
霖霖总总2 小时前
[MongoDB小技巧29]MongoDB PITR 深度工程化:从全量备份到“任意时间点”精准回滚
数据库·mongodb
JckOLF04Z2 小时前
自动开机调用迅雷下载数据库备份,完成后自动关机
数据库·单片机·嵌入式硬件
霖霖总总2 小时前
[MongoDB小技巧30]MongoDB 数据生命周期管理完全指南:从 TTL 索引到冷热分离归档
数据库·mongodb