TDengine 三副本高可用方案:RAFT 一致性原理、集群部署与运维命令详解
【免费下载链接】TDengineHigh-performance, scalable time-series database designed for Industrial IoT (IIoT) scenarios项目地址: https://gitcode.com/GitHub_Trending/tde/TDengine
TDengine 三副本方案基于 RAFT 一致性算法,将元数据与时序数据一并纳入多副本保护,使集群在不超过半数节点故障时仍能持续提供读写服务。本文以三副本方案的部署与运维为主线,完整覆盖集群配置、创建/修改副本的 SQL 命令、Out of dnodes与Vnodes exhausted等常见报错的成因与解决方案,并结合 Mnode 副本分配源码剖析建库时的资源调度逻辑。读完本文,你将能够独立完成一套 TDengine 三副本高可用集群的搭建,并理解副本数据一致性的底层机制。
一、三副本的一致性模型:基于 RAFT 的 VGroup
TDengine 的三副本方案采用 RAFT 算法来实现数据的一致性,覆盖元数据和时序数据两部分。核心组织单元是虚拟节点组(VGroup):一个 VGroup 构成一个 RAFT 组,VGroup 中的虚拟节点(Vnode)即该 RAFT 组的成员节点,也称作副本。三副本数据库即意味着每个 VGroup 包含 3 个编号相同的 Vnode,分属 3 个不同的物理节点(Dnode)。
从官方文档与源码结构看,该一致性模型包含以下要点:
- 角色划分:每个 Vnode 都有自己的角色,可以是 Leader(领导者)、Follower(跟随者)、Candidate(候选人)。Vnode 启动时角色不确定,通过组内节点交换版本号、任期等信息完成选主(详见 架构文档中的主从选择说明)。
- 连续日志:每个 Vnode 都维护一份连续的日志,记录数据写入、变更或删除等全部操作指令。日志由一系列有序日志条目组成,每条日志都有唯一编号,用于标识日志协商或执行的进度。
- 高可用边界:Leader 角色的 Vnode 提供读写服务,在故障节点不超过半数(三副本中即允许 1 个节点故障)的情况下保证集群高可用。即使发生节点重启及 Leader 重新选举,RAFT 协议也能保证新选出的 Leader 可以提供已经写入成功的全部完整数据的读写服务。
- 日志同步:每一次对数据库的变更请求(比如数据写入)都对应一条日志。持续写入过程中,各成员节点上会按协议机制产生完全相同的日志记录,并以相同顺序执行数据变更操作,日志以 WAL 文件形式存储在数据文件目录中。
- 提交确认:只有当过半数节点把该条日志追加到 WAL 文件、并且收到确认消息之后,Leader 才认为这条日志是安全的;此时日志进入 committed 状态,完成数据插入,随后被标记为 applied 状态。
完整的写入与复制流程(包括 Leader/Follower 写入路径、同步复制、流水线复制、learner 角色与写请求重定向)可参见 数据写入与复制流程。其中与三副本运维最相关的两点是:
- 重定向机制:写入请求只有 Leader Vnode 接受,客户端 taosc 维护节点组拓扑缓存,被 follower 拒绝时会自动重定向到 leader,应用层无需关心重试;
- 成员变更:调整 VGroup 副本数(如单副本改三副本)时,TDengine 扩展了 RAFT 引入 learner 角色——learner 只接收数据复制、不参与投票,数据差距大时先做快照同步,追上后再转为 follower 参与投票。这正是
alter database ... replica能在集群运行中无缝调整副本的底层机制。
二、集群配置:三副本的最低部署要求
三副本要求集群至少配置三个服务器节点,基本部署与配置步骤如下:
- 确定服务器节点数量、主机名或域名,配置好所有节点的域名解析(DNS 或
/etc/hosts); - 各节点分别安装 TDengine 服务端安装包,按需编辑好各节点
taos.cfg; - 启动各节点
taosd服务,其他服务可按需启动(taosAdapter / taosX / taosKeeper / taosExplorer)。
其中在taos.cfg层面值得特别关注的是supportVnodes参数——它决定了单个 Dnode 可承载的 Vnode 上限,直接影响“三副本能否建库成功”。从源码看,该参数在服务端全局配置中定义:
- tglobal.c#L62 声明了
tsNumOfSupportVnodes,启动时按CPU 核数 × 2 + 5计算默认值且最小为 2(tglobal.c#L1011-L1012); - tglobal.c#L1061 将其注册为服务端可配置项,取值范围为 0~1024;
- 各 Dnode 会在状态上报中携带该值(dmHandle.c#L268),Mnode 据此维护每个 Dnode 的
numOfSupportVnodes(mndDnode.c#L1312),作为后续副本分配的依据。
也就是说,一个 4 核服务器默认支持 13 个 Vnode。如果建库所需的 VGroup 数(vgroups参数)乘以副本数超过了各节点可用 Vnode 余量,就会触发下文“Vnodes exhausted”报错,可通过调大supportVnodes或增加 CPU 核数来解决。
三、运维命令:创建集群、建库与调整副本数
1. 创建集群
首先将三台服务器节点注册进集群(<dnode_ep>为节点地址,<dnode_port>为通信端口,默认 6030):
CREATE dnode <dnode_ep> port <dnode_port>; CREATE dnode <dnode_ep> port <dnode_port>; CREATE dnode <dnode_ep> port <dnode_port>;然后创建三副本的 Mnode(集群元数据管理节点),保证 Mnode 自身高可用:
CREATE mnode on dnode <dnode_id>; CREATE mnode on dnode <dnode_id>; CREATE mnode on dnode <dnode_id>;2. 数据库创建
创建三副本数据库时通过replica参数指定副本数,并可同时指定vgroups(虚拟节点组数)与buffer(单 Vnode 内存)等参数:
create database <dbname> replica 3 vgroups xx buffer xx ...3. 修改数据库副本数
单副本数据库可升级为三副本,反之亦然,使用alter命令在线完成(底层走上文提到的 learner 成员变更流程,不停写):
alter database <dbname> replica 3|1四、源码剖析:Mnode 如何为三副本分配 Vnode
建库时 Mnode 需要为每个 VGroup 挑选replica个不同的 Dnode 来放置副本。核心分配逻辑在 mndGetAvailableDnode()(mndVgroup.c),其步骤如下:
- 打分排序:按 Dnode 负载得分对候选节点排序,得分公式为
(已有 Vnode 数 + 其他节点数 × 0.9) / numOfSupportVnodes(mndGetDnodeScore()),得分低的节点优先被选中,实现副本的均衡分布; - 节点数检查:若在线 Dnode 总数少于
replica,返回TSDB_CODE_MND_NO_ENOUGH_DNODES(对应报错Out of dnodes)(mndVgroup.c#L1050-L1053); - Vnode 容量检查:若目标 Dnode 已有 Vnode 数达到
numOfSupportVnodes上限,返回TSDB_CODE_MND_NO_ENOUGH_VNODES(对应报错Vnodes exhausted)(mndVgroup.c#L1062-L1064); - 内存检查:扣除本 VGroup 所需内存后,若 Dnode 可用内存不足,返回
TSDB_CODE_MND_NO_ENOUGH_MEM_IN_DNODE(mndVgroup.c#L1066-L1073); - 初始角色:分配完成后,单副本 VGroup 的 Vnode 直接标记为 Leader,多副本 VGroup 则全部初始为 Follower,待 Vnode 启动选主后再确定真正的 Leader(mndVgroup.c#L1076-L1080)。
对应的错误码定义见 terror.c#L249 与 terror.c#L364,错误码数值(0x80000334/0x800003BA)可对照 errorCodeTable.ini 查询。
五、常见问题与排查
1. 创建三副本数据库或修改为三副本时,报错:DB error: Out of dnodes
- 服务器节点数不足:原因是服务器节点数少于三个。从源码看,当在线 Dnode 数量小于目标副本数时,分配函数即返回
NO_ENOUGH_DNODES(mndVgroup.c#L1050-L1053);alter database ... replica 3同样受此约束。 - 解决方案:增加服务器节点数量,满足最低要求(三个在线 Dnode)。
2. 创建三副本数据库或 split vgroup 时,报错:DB error: Vnodes exhausted
- 服务器可用 Vnodes 不足:原因是某些服务器节点可用 Vnodes 数少于建库或 split vgroup 的需求数。源码中的触发条件是
numOfVnodes >= numOfSupportVnodes(mndVgroup.c#L1062-L1064),其中numOfSupportVnodes即各节点上报的supportVnodes配置值。 - 解决方案:调整服务器 CPU 数量、或在
taos.cfg中调大supportVnodes配置参数(取值范围 0~1024,默认约为 CPU 核数 × 2 + 5),使单节点可承载的 Vnode 数满足建库要求,然后重启该节点服务使配置生效。
小结
TDengine 三副本方案的本质是以 VGroup 为 RAFT 组、以 WAL 日志为一致性载体:写入经过半数副本确认(committed)后方可生效(applied),从而在允许单节点故障的前提下保证数据完整与可用。运维落地时的关键路径是——部署不少于 3 个节点并完成域名解析与taos.cfg配置(重点关注supportVnodes),通过CREATE dnode/CREATE mnode搭建集群,用create database ... replica 3建库,必要时用alter database ... replica 3|1在线调整副本数;遇到Out of dnodes应检查在线 Dnode 数,遇到Vnodes exhausted应核对各节点的supportVnodes与已有 Vnode 负载。更深入的复制流程、选主与成员变更细节,可继续阅读 数据写入与复制流程 及 Mnode 副本分配源码。
【免费下载链接】TDengineHigh-performance, scalable time-series database designed for Industrial IoT (IIoT) scenarios项目地址: https://gitcode.com/GitHub_Trending/tde/TDengine
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考