在上一篇中,我们介绍了基于
PostgreSQL + Patroni + etcd的高可用部署方式,其特点包括:
Patroni 负责
PostgreSQL 实例的生命周期管理(启动、停止、角色切换、故障转移等);ETCD 作为外部分布式一致性存储,承担
Leader 选举 与
集群元数据 的职责;ETCD 的
Raft 协议** 来保证配置信息的一致性; 这种架构的优势是成熟、生态完善,但代价是
多引入了一层外部依赖(etcd),部署与运维复杂度也随之上升。今天我们来探索一下
GaussDB 的复制演进。
当
enable_dcf = off 时,
GaussDB 集中式集群为传统的“物理流复制 + 控制面仲裁”模式:
walsender 线程通过 TCP 将 WAL(XLOG)字节流单向推送至备库
walreceiver 线程。尽管包含了内核级优化,但底层仍为点对点日志流复制,
无分布式共识算法参与。-- 流复制总开关 gaussdb=> show enable_stream_replication; enable_stream_replication --------------------------- on (1 row) -- Quorum 仲裁模式,ANY 1 在一主两备架构下,等同于多数派 gaussdb=> show synchronous_standby_names; synchronous_standby_names --------------------------- ANY 1(dn_6002,dn_6003) (1 row) -- 必须等待备库的 walreceiver 线程将该日志成功写入(Flush)磁盘 gaussdb=> show synchronous_commit; synchronous_commit -------------------- on (1 row)
前面多次提到了 DCF(Distributed Consensus Framework) ,那么到底什么是 DCF?GaussDB 又为什么需要自研出这一套共识框架?
因为 基于多数派共识协议(如 Paxos、Raft)实现数据强一致与自愈,已成为现代分布式数据库的主流趋势。当前,主流分布式数据库存储引擎与共识协议对照如下:
| 数据库产品 | 存储引擎 | 副本共识/同步协议 |
|---|---|---|
| OceanBase | LSM-Tree | Multi-Paxos, 自研 Paxos 变体 |
| TiDB | LSM-Tree | Multi-Raft |
| TDSQL for MySQL | B+Tree | Raft + MARS 强同步 |
| TDSQL Boundless | LSM-Tree | Raft |
| GoldenDB | B+Tree | Raft 增强型日志复制 |
相比之下,
GaussDB 走了一条更为灵活的技术路径:它并未一上来就彻底抛弃
PostgreSQL 的继承演进,而是保留了经典的
物理流复制,并在此基础上引入了自研的分布式共识框架 ——
DCF(基于 Paxos 协议),实现了两套高可用模式的平滑切换。
enable_dcf = off(非 DCF 模式):采用传统物理流复制。配合
synchronous_standby_names = 'ANY N' 配置实现 Quorum 多数派同步;集群选主交由上层 CM 组件,依据 Term 与 LSN 位置进行仲裁,不经过 Paxos 协议。enable_dcf = on(DCF 模式):DCF 动态库直接挂载至 DN 进程。底层通过 Paxos 协议实现 DN 内核级的自选主与 XLOG 多副本复制;此时 CM 不再干预 DN 选主,仅负责状态采集与假死检测。两种模式的技术细节对比如下:
| 对比维度 | DCF 模式 (
enable_dcf = on) |
非 DCF 模式 (
enable_dcf = off) |
|---|---|---|
| 副本共识协议 | DCF (Paxos)基于自研 Paxos 协议进行多数派复制。 | 物理流复制基于 PG 流复制 + ANY N (Quorum)。 |
| 存储引擎支持 | ASTore / UStore / CStore | ASTore / UStore / CStore |
| 选主与仲裁 | DN 内置 Paxos 仲裁内核自主选主;CM 仅负责探测。 | CM 外部仲裁由 CM 组件根据 Term 与 LSN 外部选主。 |
开启 DCF 后,可以通过以下命令检查参数:
gaussdb=> show enable_dcf; enable_dcf ------------ on (1 row) gaussdb=> show dcf_run_mode; dcf_run_mode -------------- 1 (1 row) [omm@gauss1 cm]$ cm_ctl list --param --server | grep dn_arbitrate_mode dn_arbitrate_mode = quorum dn_arbitrate_mode = quorum dn_arbitrate_mode = quorum gaussdb=> SELECT application_name, client_addr, state, sync_state, pg_xlog_location_diff(sender_sent_location, receiver_replay_location) AS lag_bytes FROM pg_stat_replication;gaussdb-> gaussdb-> application_name | client_addr | state | sync_state | lag_bytes ------------------+-------------+-------+------------+----------- (0 rows)
可以看到,开启 DCF 之后,传统的流复制视图(如
pg_stat_replication)可能会变为空,这是因为
流复制的底层传输和同步机制已经被 DCF 的 Paxos 框架所接管了。
-- 开启 DCF 后,通过如下命令查看延迟
[omm@gauss1 dn_6001]$ gs_ctl query -D /data/cluster/data/dn/dn_6001
[2026-09-10 15:06:01.797][261164][][gs_ctl]: gs_ctl query ,datadir is /data/cluster/data/dn/dn_6001
HA state:
local_role : Primary
static_connections : 2
db_state : Normal
detail_information : Normal
Paxos replication info:
paxos_write_location : 0/D8A72D0
paxos_commit_location : 0/D8A72D0
local_write_location : 0/D8A72D0
local_flush_location : 0/D8A72D0
local_replay_location : 0/D8A72D0
dcf_replication_info : {"stream_id":1,"local_node_id":1,"role":"LEADER","term":407,"run_mode":1,"work_mode":0,"stg_mode":1,"is_fixed_leader":0,"hb_interval":1000,"elc_timeout":3000,"auto_elc_pri_en":1,"elc_switch_thd":0,"group":0,"priority":212705128,"leader_group":0,"is_in_major":1,"applied_index":8173,"commit_index":8173,"first_index":1,"last_index":227177168,"last_term":407,"dcf_last_index":8173,"dcf_last_disk":8173,"is_arbitrating":0,"cluster_min_apply_idx":8173,"cluster_mode":"primary_cluster","leader_id":1,"leader_ip":"192.168.182.138","leader_port":30106,"nodes":[{"node_id":1,"ip":"192.168.182.138","port":30106,"role":"LEADER","next_index":8174,"match_index":8173,"apply_index":8173},{"node_id":2,"ip":"192.168.182.139","port":30106,"role":"FOLLOWER","next_index":8174,"match_index":8173,"apply_index":8173},{"node_id":3,"ip":"192.168.182.140","port":30106,"role":"LOGGER","next_index":8174,"match_index":8173,"apply_index":8173}]}
gs_ctl query -D /data/cluster/data/dn/$(ls /data/cluster/data/dn/ | head -n 1) 2>/dev/null | tr -cd '\11\12\40-\176' | python3 -c "import sys, json; raw = sys.stdin.read(); kw = 'dcf_replication_info'; idx = raw.find(kw); parts = raw[raw.find('{', idx):raw.rfind('}')+1]; data = json.loads(parts) if parts else None; l_node = next((n for n in data['nodes'] if n['role']=='LEADER'), None) if data else None; l_idx = l_node.get('apply_index', l_node.get('match_index', 0)) if l_node else 'N/A'; print('='*70 + '\n GaussDB DCF Sync Monitor\n' + '='*70 + f'\n Current Role: {data.get(\"role\",\"UNKNOWN\") if data else \"UNKNOWN\"}\n LEADER Index: {l_idx}\n' + '-'*70 + '\n Node ID | IP:Port | Role | Index | Lag Count\n' + '-'*70) if data else print('[Error] Cannot parse DCF info from this node'); [print(f' Node {n[\"node_id\"]:<2} | {n[\"ip\"]+\":\"+str(n[\"port\"]):<20} | {n[\"role\"]:<11} | {n.get(\"apply_index\", n.get(\"match_index\", 0)):<8} | ' + (f'Lags {l_idx - n.get(\"apply_index\", n.get(\"match_index\", 0))}' if l_idx!='N/A' and l_idx - n.get('apply_index', n.get('match_index', 0))>0 else ('-' if n['role']=='LEADER' else 'Healthy')) ) for n in data['nodes']] if data else None; print('='*70)"
======================================================================
GaussDB DCF Sync Monitor
======================================================================
Current Role: LEADER
LEADER Index: 11012
----------------------------------------------------------------------
Node ID | IP:Port | Role | Index | Lag Count
----------------------------------------------------------------------
Node 1 | 192.168.182.138:30106 | LEADER | 11012 | -
Node 2 | 192.168.182.139:30106 | FOLLOWER | 11012 | Healthy
Node 3 | 192.168.182.140:30106 | LOGGER | 11012 | Healthy
======================================================================
关注以下几个位置字段: 在
nodes 列表里会列出所有 3 个节点(Leader、Follower、Logger)的实时 Index:
match_index
:代表该备节点已成功接收并持久化**的 Paxos 日志位置。apply_index
:代表该备节点已实际回放/应用到数据库**的日志位置。paxos_write_location (Paxos 写入点)paxos_commit_location (Paxos 多数派提交点)local_flush_location (本地刷新点)local_replay_location (本地回放点)DCF 作为一个深度嵌入到数据库内核的动态库(Plugin)。一旦开启,数据库内核会 绕过原生的 Sender/Receiver 通道。WAL 日志的传输、确认以及网络心跳,全部由 DCF 内部的线程池和通信模块(基于 Paxos 协议)来独立完成。
Commit 成功时,不再等待本地或传统流复制的 ACK,而是挂起在 DCF 的 Consensus Log Index 屏障上,直到 DCF 返回“多数派提交”通知。WalSender/
WalReceiver 进程隔离)。dn_arbitrate_mode = quorum / cms):CM 负责通过探针轮询 DN 状态,由 CM 外部决策谁来做 Primary、谁来 Promote,极易因网络抖动造成误判或脑裂。dn_arbitrate_mode = paxos):CM 的强行脑裂仲裁逻辑被
完全关闭。选主和状态防脑裂的绝对控制权交给了内核层 DCF 的 Paxos Term/Lease 机制。CM 仅作为集群外部的静态状态监控与运维工具,不再主动“强行插手”DN 的升主降备过程。在
GaussDB 参数体系中,CM 的仲裁模式与 DN 的 DCF 参数存在以下典型组合:
dn_arbitrate_mode |
enable_dcf |
dcf_run_mode |
实际模式 | 谁选主 |
|---|---|---|---|---|
| quorum(默认) | off | — | 纯 Quorum 模式 | CM 仲裁,DN 走流复制 |
| paxos | on |
0 (auto) |
DCF 自动选主 | DCF 自选主,CM 只做假死检测 |
| quorum | on |
1 (manual) |
DCF 手动选主(DCF 搬运日志,CM 仲裁) | CM 仲裁,DCF 只搬日志 |
| share_disk | off | — | 共享存储模式 | 存储层 / CM 配合进行控制与复制 |
注意:
walsender 线程通过原生 TCP 协议,将 WAL 字节流单向、直接地推送至备库的
walreceiver 线程。其内核层面不涉及复杂的分布式共识与投票算法。$DATAPATH/dcf_data)。数据不再是简单的点对点单向推送,而是通过 Paxos Log 的形式在集群内进行多数派表决与确认。synchronous_commit 与
synchronous_standby_names 参数组合。```sql gaussdb=> show synchronous standbynames; synchronous standbynames
ANY 1(dn 6002,dn6003) (1 row)
gaussdb=> show synchronous commit; synchronouscommit
on (1 row) ```
match_index 对齐),该事务就认为达成了共识(Consensus)。Leader 宕机,
Follower 节点会自动发起选举,仅有获得过半数(Quorum)选票且日志最新的节点才能晋升为新 Leader。由于数学逻辑上不可能同时产生两个过半数集群,因此从根源上杜绝了脑裂的可能性。LOGGER(日志节点/仲裁节点),只参与
Paxos 投票和记录共识日志,
不回放数据实体、不存物理数据页。这不仅极大节省了第三台机器的磁盘和内存开销,同时又完美凑齐了多数派所需的奇数节点。
从传统流复制向 DCF 模式的演进,是
GaussDB 走向真正的强一致性分布式架构的里程碑。从传统的物理流复制跨越到 DCF 模式,不仅是日志传输技术的升级,更是一场高可用架构的升维:
DCF 模式代表了未来的方向,通过内置
Paxos 实现了真正的分布式共识,去
ETCD 化,使数据库自身成为一个更自治、更健壮的分布式系统。
这里是《实战派 K8S&DB》,更多干货敬请关注公众号。如果本文对你有所帮助,欢迎点赞、推荐和转发,也欢迎关注后续文章,一起考证、一起学习
GaussDB 分布式数据库。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/31444449/viewspace-3182262/ ,如需转载,请注明出处,否则将追究法律责任。