MariaDB 中文社区

复制深度:异步 / 半同步 / Galera

MariaDB 三种复制拓扑的对比、故障转移、GTID、延迟排查

复制是高可用的基础,但每种方案都有不同的"一致性 vs 可用性"取舍。这一篇讲清楚怎么选、怎么排查。

三种主流模式

模式一致性写延迟可用性典型场景
异步 (async)最终一致最低主挂可能丢数据读多写少、海量从库
半同步 (semi-sync)准强一致主等至少 1 从 ack主挂数据基本不丢中型业务,默认推荐
Galera Cluster强一致主等多数 ack单节点挂不影响多写、跨 AZ

异步复制

# 主
[mariadb]
server-id=1
log-bin=mysql-bin
binlog_format=ROW
gtid_strict_mode=ON
expire_logs_days=7

# 从
[mariadb]
server-id=2
relay-log=relay-bin
read-only=ON
log_slave_updates=ON     # 从也写 binlog,便于级联

启动复制:

-- 在主上
CREATE USER 'repl'@'%' IDENTIFIED BY 'xxx';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';

-- 主备份 + 记 GTID
mariabackup --backup --target-dir=/backup -uroot

-- 从恢复 + 启复制
CHANGE MASTER TO
  MASTER_HOST='primary',
  MASTER_USER='repl',
  MASTER_PASSWORD='xxx',
  MASTER_USE_GTID=slave_pos;
START SLAVE;

SHOW SLAVE STATUS\G

关键状态

SHOW SLAVE STATUS\G
-- Slave_IO_Running: Yes      ← IO 线程,拉取 binlog
-- Slave_SQL_Running: Yes     ← SQL 线程,应用 binlog
-- Seconds_Behind_Master: 0   ← 复制延迟
-- Gtid_Slave_Pos             ← 当前 GTID

延迟排查

SHOW SLAVE STATUS\G
-- Seconds_Behind_Master 持续 > 10 秒 → 报警

常见原因:

  1. 从库硬件弱于主库 → 升配
  2. binlog_format=STATEMENT 触发慢 SQL → 改 ROW
  3. 大事务(百万行 UPDATE)→ 拆批
  4. 从库被 OLTP 占用 → 拆专用副本
  5. 网络抖动 → 看 Last_IO_Error

平滑故障转移(手动)

-- 在从库等到追平
STOP SLAVE IO_THREAD;
-- 等 SQL 线程跑完
SHOW SLAVE STATUS\G    -- Exec_Master_Log_Pos 与 Read_Master_Log_Pos 相同

-- 提升为新主
STOP SLAVE;
RESET SLAVE ALL;
SET GLOBAL read_only=OFF;

-- 把流量切过去

自动故障转移用 MariaDB MaxScaleOrchestrator

半同步复制

主在提交时等至少一个从 ack 写到 relay log,不丢数据(除非主和那一个从同时挂)。

-- 主
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
SET GLOBAL rpl_semi_sync_master_enabled = 1;
SET GLOBAL rpl_semi_sync_master_timeout = 1000;  -- 1 秒等不到 ack 退回异步

-- 从
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
SET GLOBAL rpl_semi_sync_slave_enabled = 1;
STOP SLAVE IO_THREAD; START SLAVE IO_THREAD;

监控:

SHOW STATUS LIKE 'Rpl_semi_sync%';
-- Rpl_semi_sync_master_status: ON
-- Rpl_semi_sync_master_clients: 1+
-- Rpl_semi_sync_master_no_tx: 0  (越大说明掉到异步越多)

timeout 别设太低:网络抖动会让半同步退化到异步。但太高又会阻塞主库写入。1–5 秒是常用值。

Galera Cluster

完全不同的模型:多主写同步多数派

[mariadb]
wsrep_on=ON
wsrep_provider=/usr/lib/galera/libgalera_smm.so
wsrep_cluster_address="gcomm://node1,node2,node3"
wsrep_cluster_name="prod"
wsrep_node_name=node1
wsrep_sst_method=mariabackup
wsrep_sst_auth=sst:sstpass

binlog_format=ROW
default_storage_engine=InnoDB
innodb_autoinc_lock_mode=2

启动顺序:

# 首次:启动第一个节点
galera_new_cluster

# 其他节点
systemctl start mariadb

监控

SHOW STATUS LIKE 'wsrep_cluster_size';     -- 应该等于节点数
SHOW STATUS LIKE 'wsrep_cluster_status';   -- Primary 才正常
SHOW STATUS LIKE 'wsrep_ready';            -- ON
SHOW STATUS LIKE 'wsrep_local_state_comment';  -- Synced

Galera 的特性

✅ 任何节点都可写 ✅ 节点挂掉不影响其他节点 ✅ 数据强一致

写并发不会线性扩展——每次写要全节点投票 ❌ 长事务 / 大事务很难(容易触发 wsrep_max_ws_size) ❌ DDL 是全集群阻塞的(需要 wsrep_OSU_method=RSU 改 schema) ❌ 跨 region 慢(同步等远端 ack)

何时用 Galera

  • 多 AZ 同写
  • 不能容忍主备切换的秒级抖动
  • 已经能控制写并发不爆炸

否则 半同步 + MaxScale 通常更香。

GTID(全局事务 ID)

MariaDB GTID 格式:<domain>-<server_id>-<seq>,例如 0-1-12345

SELECT @@gtid_current_pos;
-- 0-1-12345,1-2-678

关键参数

gtid_strict_mode=ON          # 强校验,推荐生产
gtid_domain_id=0             # 多源复制时用不同 domain
log_slave_updates=ON         # 从写 binlog,便于级联

用 GTID 启复制(简单)

CHANGE MASTER TO
  MASTER_HOST='primary',
  MASTER_USER='repl',
  MASTER_PASSWORD='xxx',
  MASTER_USE_GTID=slave_pos;

不需要手动记 binlog 文件名和位置——MariaDB 自己根据 GTID 找。

跨 region 复制

方案RPORTO复杂度
异步 binlog秒级到分钟级主 region 挂可手动切
Galera 跨 region同步(受网络限制)自动
MariaDB MaxScale看后端自动路由
MariaDB Xpand (SkySQL)强一致自动商业方案

维护操作

跳过坏事务

-- 复制因为某个事务失败卡住
STOP SLAVE;
SET GLOBAL sql_slave_skip_counter = 1;
START SLAVE;

危险!会导致从库与主数据不一致。只在确实需要时用

重新做主从

# 在主上备份
mariabackup --backup --target-dir=/backup --slave-info

# 拷到从
rsync -av /backup/ slave:/restore/

# 从恢复 + 启复制
mariabackup --prepare --target-dir=/restore
systemctl stop mariadb
rm -rf /var/lib/mysql/*
mariabackup --copy-back --target-dir=/restore
chown -R mysql:mysql /var/lib/mysql
systemctl start mariadb

# 读 /restore/xtrabackup_slave_info 拿到 GTID,CHANGE MASTER

多源复制(MariaDB 独有)

一个从库可以从多个主库拉数据:

CHANGE MASTER 'shard1' TO MASTER_HOST='s1', MASTER_USE_GTID=slave_pos;
CHANGE MASTER 'shard2' TO MASTER_HOST='s2', MASTER_USE_GTID=slave_pos;
START ALL SLAVES;

适合:分库 → 汇总到一个分析库。

延伸

本页目录