建立具备高可用(HA)功能的 MariaDB 架构,核心目标是保障数据不丢失(RPO ≈ 0)和服务快速故障转移(RTO 达到秒级/分钟级)。
针对不同的业务规模和场景需求,业界主流的 MariaDB HA 方案分为以下三种,您可以根据实际业务体量选择最适合的部署架构:
一、 主流 HA 方案对比与选型建议
| 方案架构 | 推荐生产场景 | 优点 | 缺点 | 推荐度 | ||||||
|---|---|---|---|---|---|---|---|---|---|---|
| 方案 A:MariaDB Galera Cluster (推荐) | 中大型业务、强一致性读写、OLTP 场景 | • 真正多主架构,全同步复制 | • 无主从延迟(RPO = 0) | • 自动节点加入与自我修复 | • 写入性能受限于网络延迟(建议同机房/低延迟环境) | • 不支持长事务/大事务 | ⭐⭐⭐⭐⭐ | |||
| 方案 B:MHA / Orchestrator + 主从复制 + Keepalived | 读多写少、已有主从架构改造 | • 技术成熟,对现有应用无侵入 | • 性能开销小 | • 主从异步/半同步复制存在微小延迟风险 | • 自动切换逻辑较复杂(防脑裂) | ⭐⭐⭐⭐ | ||||
| 方案 C:MariaDB + Pacemaker/Corosync (共享存储) | 传统企业级应用、严格要求单点写入 | • 数据一致性高 | • 兼容所有复杂 SQL 与事务 | • 属于主备架构(单点瓶颈),无读扩展能力 | • 强依赖 SAN/NAS 共享存储 | ⭐⭐⭐ |
二、 方案 A 详解:MariaDB Galera Cluster + MaxScale(推荐生产架构)
这是目前 MariaDB 官方最推荐且生产环境应用最广的高可用方案。
1. 架构拓扑
- 数据库层:3 个 MariaDB 节点组成 Galera 多主集群(避免偶数节点的脑裂问题)。
- 负载均衡/中间件层:2 个 MariaDB MaxScale 节点,负责读写分离、健康检查与 SQL 路由。
- 高可用入口:Keepalived VIP(虚拟 IP)绑定在 MaxScale 前端。
Plaintext
[ 客户端应用 / Client ]
│
VIP: 192.168.1.100
│
┌───────────┴───────────┐
▼ ▼
[ MaxScale 1 ] (Master) ◄──► [ MaxScale 2 ] (Backup)
( Keepalived ) ( Keepalived )
│ │
────────┼───────────────────────┼────────
│ │
▼ ▼
┌──────────────┬───────────────┬──────────────┐
│ │ │ │
[ MariaDB Node1 ] [ MariaDB Node2 ] [ MariaDB Node3 ]
└─────── Galera Synchronous Replication ───────┘
2. 关键配置与设计要点
- 节点数量:部署节点数必须为奇数(最少 3 节点)。若资源有限仅能部署 2 个节点,需额外部署一个
Garbd(Galera Arbitrator) 仅参与投票,防止脑裂。 - 网络要求:节点间网络延迟建议 $< 5\\text{ms}$,网络带宽充裕(Galera 使用广播/组播机制进行数据同步)。
- 存储引擎:Galera 仅全面支持 InnoDB 引擎,确保所有表均有显式主键。
三、 部署实施步骤(以 3 节点 Galera 集群为例)
1.基础环境准备:三台服务器均需执行.
- 配置三台服务器的主机名映射(
/etc/hosts)及时间同步(NTP/Chrony)。 - 关闭 SELinux 并配置防火墙允许以下端口通信:
3306: MariaDB 客户端连接4567: Galera 集群通信端口(TCP/UDP)4568: IST (Incremental State Transfer) 端口4444: SST (State Snapshot Transfer) 端口
Bash
# 安装 MariaDB Server 及 Galera 插件
sudo apt-get install mariadb-server mariadb-plugin-galera galeraproxy # Debian/Ubuntu
# 或 sudo yum install MariaDB-server MariaDB-Galera-server # RHEL/CentOS
2.配置 Galera 集群节点:在三台 MariaDB 节点上添加 Galera 配置.
在 /etc/mysql/mariadb.conf.d/60-galera.cnf 中添加:
Ini, TOML
[mysqld]
binlog_format=ROW
default_storage_engine=InnoDB
innodb_autoinc_lock_mode=2
# Galera Provider 配置
wsrep_on=ON
wsrep_provider=/usr/lib/galera/libgalera_smm.so
# 集群标识
wsrep_cluster_name="mariadb_ha_cluster"
wsrep_cluster_address="gcomm://192.168.1.10,192.168.1.11,192.168.1.12"
# 本地节点配置 (按节点修改 IP 和名称)
wsrep_node_address="192.168.1.10"
wsrep_node_name="db-node-1"
wsrep_sst_method=mariabackup
3.初始化与启动集群:注意:仅在第一个节点执行引导初始化.
- 在 Node 1 上执行引导命令启动首个节点:
Bash
sudo galera_new_cluster
- 检查首节点状态,确认
wsrep_cluster_size为 1:
SQL
SHOW STATUS LIKE 'wsrep_cluster_size';
- 在 Node 2 和 Node 3 上依次正常启动 MariaDB 服务加入集群:
Bash
sudo systemctl start mariadb
- 再次在任意节点验证,此时
wsrep_cluster_size应当显示为 3。
4.接入层与负载均衡配置:配置 MaxScale 与 Keepalived.
- 在两台代理服务器上安装 MariaDB MaxScale。配置
ReadWriteSplit服务,自动将写请求路由至单台主节点(避免多主同时写入带来的死锁风险),将读请求分发给所有可用节点。 - 配置 Keepalived 绑定虚拟 IP(VIP:
192.168.1.100),监控 MaxScale 进程。当主代理挂掉时,VIP 自动漂移至备用代理服务器。
四、 运维与高可用验证策略
脑裂防护(Split-Brain):
当出现网络分区导致集群分割时,节点较少的子集群会进入
Non-Primary状态并拒绝接受任何 SQL 读写请求,从而保证数据绝对一致。- 故障演练测试:
- 单节点宕机测试:直接拔掉 Node 3 网线或执行
poweroff,检查集群尺寸变更为 2,业务无感知。 - 网线恢复/重启测试:重新启动 Node 3,验证其是否通过 SST/IST 自动补全数据并重新融入集群。
- 代理节点故障测试:Stop 主 MaxScale 上的 Keepalived 服务,验证 VIP 是否在 1\~3 秒内漂移至备用代理节点。
在跨机房(WAN / 广域网)高延迟环境下部署 MariaDB Galera 集群,最大的挑战在于 Galera 的强同步特性:Galera 在事务提交时必须经过 2PC(两阶段提交) 和集群全网节点广播验证(Certify)。
公式化理解瓶颈:
每次写事务提交延迟 ≈ $\\text{单次事务本地执行时间} + 2 \\times \\text{跨机房往返网络延迟 (RTT)}$。
若机房间 RTT 为 $30\\text{ms}$,则单条写事务的额外网络等待就至少需要 $60\\text{ms}$,TPS(每秒事务数)会急剧下降。
为了在保障跨机房数据高可用的同时最大化写入性能,需要从拓扑架构优化、Galera/MySQL 参数调优、应用侧优化三个维度联合实施。
一、 跨机房网络与拓扑架构设计
1. 节点分布与仲裁节点(Garbd)
- 禁止 2 机房各 1 节点(共2节点):机房间链路中断会导致两边都不足 50% 投票权,集群整体挂起。
- 推荐方案 A(3 机房架构 - 最理想): 每一个机房部署 1 个数据库节点(1 + 1 + 1)。
- 推荐方案 B(2 机房架构 - 常见):
- 机房 A(主):2 个 Galera 节点
- 机房 B(备/灾备):1 个 Galera 节点
- 或 机房 A(2 节点) + 机房 B(1 节点) + 机房 C/云厂商(仅部署 1 个低配轻量级的
garbdGalera 仲裁进程,不存数据,只参与投票)。
2. 使用 segment 参数隔离跨机房流量(重中之重)
默认情况下,Galera 节点向集群广播 SST/IST 或复制数据时会发给所有节点,这会导致跨机房链路重复传输流量。
通过设置 gmcast.segment,Galera 会将相同机房的节点划分为同一 Segment。跨机房传输时,数据只由源机房发送一次给目标机房的“代表节点”,再由该代表节点在本地机房组播,大幅节省 WAN 带宽并降低延迟。
Ini, TOML
# 机房 A (DataCenter 1) 的节点配置
wsrep_provider_options="gmcast.segment=1; evs.send_window=512; evs.user_send_window=256"
# 机房 B (DataCenter 2) 的节点配置
wsrep_provider_options="gmcast.segment=2; evs.send_window=512; evs.user_send_window=256"
二、 核心参数调优(Galera & InnoDB)
针对高延迟网络(高 RTT、高丢包风险),需修改以下参数避免集群误判节点宕机或因队列积压引发严重的流量控制(Flow Control)。
1. 调整心跳与超时判定(防止 WAN 波动导致集群踢人)
跨机房网络偶发丢包或抖动容易触发 EVS(Event Service)超时,导致节点被误判离线并频繁重连。
Ini, TOML
[mysqld]
wsrep_provider_options = "
gmcast.segment=1;
evs.keepalive_period=PT3S; # 心跳检测间隔,默认 1 秒,提高到 3 秒
evs.suspect_timeout=PT10S; # 怀疑节点故障的超时时间,默认 5 秒,提高到 10 秒
evs.inactive_timeout=PT30S; # 确认节点死亡的超时时间,默认 15 秒,提高到 30 秒
evs.consensus_timeout=PT30S; # 节点状态达成一致的超时时间
evs.send_window=1024; # 增大发送窗口(适应高延迟/高吞吐)
evs.user_send_window=512;
"
2. 优化复制队列与流量控制(Flow Control)
高延迟环境下,从节点(Replica)应用 Binlog 的速度跟不上主节点的写入速度时,会触发 Galera 的流量控制(Flow Control),将主节点暂停写入。
Ini, TOML
[mysqld]
# 增大 Galera 接收和发送队列容量,防止高延迟下写队列瞬间塞满
gcs.fc_limit = 200 # 触发 Flow Control 的队列上限(默认 16,高延迟 WAN 建议调大至 100-300)
gcs.fc_factor = 0.8 # 队列恢复到上限的 80% 时解除 Flow Control
# 开启并行复制线程(非常重要)
# 建议设置为:CPU逻辑核心数 * 2 到 * 4
wsrep_slave_threads = 16
# 提高网络传输效率
wsrep_provider_options = "repl.commit_order=3" # 允许并行 Commit 验证
3. 减少磁盘 I/O 带来的叠加延迟
Ini, TOML
[mysqld]
# 允许事务提交时无需每次强行 flush 磁盘(数据已由 Galera 多节点内存保障)
innodb_flush_log_at_trx_commit = 2 # 性能提升巨大,写性能提升 3-5 倍
sync_binlog = 0 # 若开启了 binlog,建议调为 0 或大于 100
三、 业务层与架构层优化策略(关键瓶颈突破)
硬件与参数调优只能提升 30%\~50% 的极限,业务侧的读写模式决定了跨机房 Galera 是否真正可用:
1. 严格使用“单点写入(Single-Master)”模式
- 严禁多机房同时写入(Multi-Master): 在高延迟网络下,如果机房 A 和机房 B 同时写同一张表甚至同一行,Galera 的 Certify 冲突率会飙升,导致大量
Deadlock(死锁)报错和事务回滚。 - 做法: 所有应用写流量通过 MaxScale 或 VIP 固定只写入机房 A(主),机房 B 和机房 C 的数据库节点仅作为热备和只读节点(Read-Only)。
2. 事务粒度控制与批量处理
- 合并小事务(Batch Processing): 避免
for循环中单条INSERT提交。单条提交意味着每一次都要等 $2 \\times \\text{RTT}$。将 100 条插入合并为一个INSERT INTO ... VALUES (...), (...)事务提交,能将网络开销降低 99%。 - 控制大事务: 避免超过
wsrep_max_ws_rows(默认 128k 行)或wsrep_max_ws_size(默认 2GB)的大事务,否则跨机房网络传输巨型 Pakcet 会直接卡死集群。
四、 替代方案选型:如果 latency > 50ms 怎么办?
如果机房间网络延迟持续很高(如 $> 50\\text{ms}$,跨国/跨大洲机房),强烈不建议继续使用 Galera 同步复制(写性能会降至个位数 TPS)。
建议改用:“同机房 Galera + 跨机房异步/半同步 Replication”
Plaintext
[ 机房 A (主) ] [ 机房 B (灾备) ]
Node 1 ─┐ Node 4 ─┐
Node 2 ─┼─ (Galera 强同步) Node 5 ─┼─ (Galera 强同步)
Node 3 ─┘ Node 6 ─┘
│ ▲
└─────── MariaDB Master-Slave ───────┘
(跨机房 异步 / 半同步复制)
- 优势: 机房 A 内部写操作是毫秒级(本地低延迟 Galera),跨机房异步/半同步传输,完全解耦了跨机房的网络延迟对本地写性能的影响。
在跨机房单点写入(Single-Master)架构下,为了兼顾高性能与高可用,MaxScale 的配置核心在于:
- 主写节点固化(Master Preference):优先将所有写请求路由至本地/主机房(Site A)的 MariaDB 节点,只有当主机房节点全盘挂掉时,才自动漂移到异地/灾备机房(Site B)。
- 读写分离与延迟隔离:将读请求负载均衡到所有存活节点,同时配置 MaxScale 剔除同步延迟过高的灾备节点。
以下是完整的生产级 MariaDB MaxScale (maxscale.cnf) 配置示例与关键点解析。
MaxScale 核心配置文件示例 (/etc/maxscale.cnf)
Ini, TOML
[maxscale]
threads=auto
log_syslog=1
# ====================================================================
# 1. 节点定义 (Servers)
# ====================================================================
# 主机房 (Site A) - 优先写入节点
[db-node-a1]
type=server
address=192.168.1.10
port=3306
protocol=MariaDBBackend
priority=1 # 优先级最高 (Primary)
[db-node-a2]
type=server
address=192.168.1.11
port=3306
protocol=MariaDBBackend
priority=2 # 主机房次选
# 异地/灾备机房 (Site B) - 备用节点
[db-node-b1]
type=server
address=10.0.1.20
port=3306
protocol=MariaDBBackend
priority=3 # 异地节点,仅当主机房不可用时接管写操作
# ====================================================================
# 2. 监控服务 (Galera Monitor)
# ====================================================================
[Galera-Monitor]
type=monitor
module=galeramon
servers=db-node-a1, db-node-a2, db-node-b1
user=maxscale_user
password=maxscale_secure_password
monitor_interval=2000ms
# 关键配置:基于 Priority 的单点写入控制
use_master_node=true
disable_master_failback=false # 若主机房恢复,是否切回主机房(建议视业务需求配置)
root_node_as_master=true # 结合 priority 选择选票最高的节点作为唯一 Master
# ====================================================================
# 3. 路由服务 (Services)
# ====================================================================
# --- 读写分离服务 (Read-Write Split Service) ---
[RW-Split-Service]
type=service
router=readwritesplit
servers=db-node-a1, db-node-a2, db-node-b1
user=maxscale_user
password=maxscale_secure_password
# 严格保证单主写入 (写请求永远路由到 Priority 最高的 Primary 节点)
master_accept_reads=true
strict_multi_master=false
# 跨机房读优化:当异地节点应用 Galera 队列延迟过高时,将其剔除只读池
max_slave_replication_lag=30
# --- 选填:纯写端口路由 (Forced Master Router) ---
# 如果某些老旧应用不支持读写分离框架,可以单独开一个专门走主节点的端口
[Master-Only-Service]
type=service
router=readconnroute
router_options=master
servers=db-node-a1, db-node-a2, db-node-b1
user=maxscale_user
password=maxscale_secure_password
# ====================================================================
# 4. 监听端口 (Listeners)
# ====================================================================
[RW-Split-Listener]
type=listener
service=RW-Split-Service
protocol=MariaDBProtocol
port=3306
[Master-Only-Listener]
type=listener
service=Master-Only-Service
protocol=MariaDBProtocol
port=3307
关键配置项详解
priority字段与写节点选主机制
- 在
[server]定义中配置priority=N(数值越小,优先级越高)。 galeramon监控器在检测集群时,会在当前处于Synced状态的 Galera 节点中,挑选priority最小的那个节点标记为 Master。- 业务收益:所有写事务(
INSERT/UPDATE/DELETE)被强制锁死在 Site A (192.168.1.10),彻底杜绝双机房同时写入造成的锁冲突与死锁。
- 跨机房故障转移逻辑(Failover)
- 场景 1(主机房单节点故障):
db-node-a1宕机,MaxScale 会立刻将写流量切换至主机房的db-node-a2(priority=2),无须跨机房切换。 - 场景 2(主机房整体网络中断):
Site A节点全部离线,MaxScale 自动把写流量引导至异地Site B的db-node-b1(priority=3)。
max_slave_replication_lag防脏读机制
- 在跨机房 WAN 环境下,由于网络延迟或丢包,
Site B节点的 Galera 接收队列(wsrep_local_recv_queue)可能出现积压。 - 该参数设置为
30秒,一旦异地节点延迟超过此阈值,MaxScale 的readwritesplit会自动停止向该节点路由SELECT读请求,避免业务读取到过期的脏数据。
高可用入口配合(MaxScale + Keepalived)
如果在主机房和备机房各部署了一台 MaxScale 实例,可通过 Keepalived 提供统一的 VIP 接入:
- 主机房应用:优先连接主机房 MaxScale VIP。
- Keepalived 监控探针:让 Keepalived 实时检查 MaxScale 进程及底层 Galera 节点的存活性。
Bash
# Keepalived 存活检查脚本示例 (/etc/keepalived/check_maxscale.sh)
#!/bin/bash
maxctrl show servers | grep -E 'db-node-a1|db-node-a2' | grep -q 'Master'
if [ $? -ne 0 ]; then
# 若主机房已经没有可用节点,让 Keepalived 降低权重,促使 VIP 漂移至灾备机房 MaxScale
exit 1
fi
exit 0