openGauss的DCF组件详解
- 组件介绍
- 功能介绍
- 模块介绍
- 代码仓库
- 数据库对接
目录
1 DCF 组件介绍
DCF(分布式共识框架)目标:构建稳定可靠、低时延、高吞吐的一致性数据复制组件。
这一技术组件需要承载以下工作:
- 副本高可用
- 主备之间备份
- 容灾性自动/手动升主降备
- 跨AZ(可用区)的多副本复制
- 多日志流的复制
- 简化集群管理
- 集群状态发布
- 集群配置管理
- 委托选主
- 分布式全局锁
1.1 需求背景与优势
传统主备集群管理常采用第三方仲裁,如采用Etcd集群实现主备节点间的切换:
这样的第三方仲裁会出现一些问题,如脑裂。有可能第三方仲裁认为节点故障,但实际上没有,此时会出现脑裂的情况。此外,还会出现因中间状态而出现的日志分叉的情况。
openGauss引入DCF自仲裁,DCF作为一个动态库集成在openGauss存储引擎中,在DB内核中自检测。DCF通过一致性协议,协商哪一节点作为主节点,以保证在任何情况下都不会出现脑裂既双主的情况,也不会出现日志分叉的情况。并且相比传统主备集群管理,大大简化了故障检测环节,进而减小集群RTO(容许服务中断的时间长度)。
自仲裁具有很多优势:
并且在openGauss中,同过解耦使得DCF作为一个独立模块,既降低了复杂度,又使得后续的优化更方便。
1.2 一致性协议
DCF组件采用Paxos协议。当前被广泛采用的一致性协议还是Paxos族协议,Paxos算法在这些年已经经过了很多代演进。
1.2.1 两阶段Paxos
1.2.2 Multi-Paxos
在经典Paxos基础上添加租约机制,维持Leader节点状态。
1.2.3 Raft
在Multi-Paxos上进一步做了简化,更容易实现可靠性。
1.2.4 Paxos演进趋势
不同的Paxos算法都是在经典Paxos基础上,根据业务的情况选择了不同的侧重点。
DCF的目标是做一个适用于数据库的一致性日志复制组件。
2 功能介绍
对照数据库中想实现的一些特性,总结出以下想实现的功能:
设计的DCF为一个独立的组件,与内核解耦,最终实现一个位于底层的Paxos日志复制的共识框架,使得DCF不仅可以用在内核中,还可以用于集群管理等地方。DCF通过对节点进行多种角色的分类,使得集群管理更加灵活,降低容灾、数据备份等过程中的成本。
关键设计:
- 支持自选主
- 支持异步多线程框架和无锁cache设计
- 支持多级batch. pipeline操作, 以及日志压缩能力V支持日志多流多复制
- 不同分区主备副本可以在同-节点,方便实现负载均衡和异地多活
- 基于网络带宽及网络时延自动探测的流控算法
- 支持batch size、pipeline并发数自适应调整, 提升系统最大吞吐量
openGauss引入基于Paxos协议的DCF组件,能够保证数据一致性的同时,在高可用方面得到极大增强,主要包括:
- 通过自仲裁、多数派选主能力摆脱第三方仲裁组件,极大缩短RTO时间,且可预防任何故障下的脑裂双主
- 基于Paxos协议拓展的多样化节点角色,能够提供节点同步同异步混合部署等多种集群部署方式
- 高性能、低时延的复制能力,使得openGauss在高可用方面得到极大增强的同时,还提升了主备节点间日志复制效率,提升系统最大吞吐能力
3 模块介绍
DCF模块划分如上图所示,作为一个动态库集成到数据库内核中。
- interface:DCF通过interface接口层与数据库日志模块对接,提供读写等接口。flash刷盘的时候,数据库调DCF的interface接口写入,达成共识后,DCF会异步的通知上层写入成功。
- metadata:元数据管理,定义集群节点信息,如IP端口,角色类型,选举超时时间等。
- election:负责主节点的选举、心跳维持、状态发布。
- replication:推进日志的分发并达成一致。
- storage:负责日志数据的持久化。
- communication:提供节点间的数据通信能力(TCP/UDP)。
- Base:提供基础能力,如线程、日志、锁、队列等。
Gitee上可以查到DCF仓库。
3.1 选举流程
preVote优化:
- 为防止网络断连导致节点频繁发起选主请求,term持续增加
- 在Follower变为Candidate前加入pre-candidate状态,发起term不变的预选举流程,成功后才将term++发起正式选主流程
Lease优化:
- Leader与多数派断连主动降备,防止事实双主
- 在lease时间内不响应term更高的选主消息
DCF在Paxos上增添了预选举环节,增加一次探测,当与大多数节点通信正常时才会发起选举,获得大多数节点的投票后当选为主节点,然后所有Follower跟随主节点做日志的同步。
选举核心之一是多数派原则,通过逻辑推理可以证明数据一定不会丢,因为无论是当选还是日志推进,多数派总是重叠的,以保证数据不丢失。
3.2 主机异常的处理
- 网络异常或节点宕机,导致Leader心跳停止,日志复制停止。
- Follower检测到心跳超时, 转换为candidate, 发起新任期选举
- Follower若接收到其他节 点发起的选举,则判断任期和日志长度,确定是否投票给他
- candidate若得到超过半数的选票,则成为leader
- 新leader开始将自 己的日志发送给其他follower
- Follower接收新leader来的日志信息,判断日志是否跟自己连续匹配,连续匹配则接受。若不连续则返回,leader重新发送前段日志;若term不匹配,则将新leader的日志覆盖到原来的位置,并将后面的日志truncate掉
3.3 网络分区的处理
- 集群网络异常分区,分裂出两个小集群
- 一个集群存在一个原leader, 新集群选举一个新leader, 任期增1
- 原leader也能接受写请求进行写入操作,但是无法达成大多数一致,导致无法提交
- 新leader也能接受写请求进行写入操作,能够达成一致,进行日志提交脑裂消失之后,由于原leader的term比较旧,会切换成follower
- 新leader的日 志复制给就leader,将就leader未提交日志覆盖
主机异常和网络分区都是每个自己检测的,所以节点的状态切换是根据自身的状态,不需要第三方去通知节点状态变更。
3.4 复制流程
client thread指的是xlog中负责落盘的线程,通过调DCF的write接口,把数据写到buffer队列里面,写完后无阻塞立即返回。当本次写入得到大多认可后,会异步的write callback。而buffer里的数据会经过一系列的复制流水线,经过组包发送给备机。备机收到数据包后会回调Replay callback通知数据库内核,然后将数据拷贝到xlog日志里面。
异步流水线
- 日志采用全异步进行发送,不采用一问一答同步方式,提高系统整体吞吐量
- Leader发送完一批log之后,直接更新next index,下次发送从这个点持续发送,不等follower响应回来;
- Follower等落盘线程写完一批log之后,将最新的落盘match_index发送给leader,持续反馈最新的落盘index;
- Leader通过这个来更新各节点的最新match_index,推进commit_index;
数据合并&压缩
- 通信模块将包按大小进行压缩发送,减少网络带宽;
- 根据发送队列情况自动合并数据包;
批量并行落盘
- 应用端调用API write接口,写入内存buffer就返回,不阻塞应用其他流程处理,批量写盘和批量发送,日志到buffer之后,并行的将日志落入本地磁盘和发送到follower节点
多日志流
- 支持DN粒度和分区粒度日志分组能力
吞吐量随时间变化平滑,平且相比同类产品吞吐量有提升。
4 代码仓库
DCF作者在Gitee上建有代码仓库,DCF编译后在数据库中以动态库的形式存在,内核通过 DCF/src/interface/dcf_interface.h 文件调用DCF的能力,那么打开dcf_interface.h看一下几个最核心的接口:
- dcf_start:
启动DCF模块,内核调用 dcf_start 将模块拉起。 - dcf_write:
拉起后调用 dcf_write 做数据写,DCF支持多日志流,但目前鸿蒙gauss里面只需要用一份日志。其中,通过 key 标识哪一份数据得到了承认,index 则标识着序列中的第几个数据得到了承认。 - dcf_read:
dcf_read 方法可以根据 dcf_write 方法中的 index 关键字读取DCF中对应的数据。 - dcf_start:
停止DCF模块。
使用步骤:
- 参数设置:设置buffer大小、压缩参数、心跳超时时间等
- 注册回调函数:leader方 日志达成一致的回调函数、follower apply/replay回调函数、身份变更通知回调函数
- 初始化启动:初始化模块,启动各线程
- 写入log
- 读取已存储的log
- 查询集群状态
5 数据库对接
数据库参数配置:
- enable_ dcf = on
- dcf_ node_ id = 3
- dcf_ data_ path = ‘/dcf_ perf_ 03/px01/cluster/data/dn1/dcf_ _data’
- dcf_ log_ path = ‘/dcf_ perf_ 03/px01/cluster/gaussdb_ log/px01/dcf_ log’
- dcf_ config =
‘[“stream_ id”:1,”node_ id”:1,”ip”:”8.92.1.85”,”port”:16683,”role”:”LEADER”),(“stream_ id”:1,”node_ id”:2,”ipp”:”8.92.1 .86”,”port”:16683,”role”:”FOLLOWER”),”stream_ id”:1,”node_ id”:3,”ip”:”8.92.1.87”,”port”:16683,”role”:”FOLLOWER”]] - dcf_ Ssl = off
- dcf_ mec_ batch_ size=0
openGauss的DCF组件详解