TDengine RPC 通信层深度解析 — 协议格式、连接管理与重试机制

适用版本:TDengine v3.x(v3.3.x / v3.4.x) | 最后更新:2026-05-15

概述

RPC(Remote Procedure Call)通信层是 TDengine 分布式系统的网络基础设施。集群中所有节点间的通信------客户端到 taosd、dnode 到 mnode 的心跳、Raft 日志复制、查询分发------都通过 RPC 层完成。

本文深入解析 RPC 通信层的五大核心机制:

  1. 协议格式:消息头结构、魔数校验、序列号追踪
  2. 连接管理:基于 libuv 的 TCP 连接池、空闲回收、多路复用
  3. 重试机制:指数退避、EP 轮转、快速失败
  4. 通道隔离:多 RPC 实例分离不同类型流量
  5. 流控与背压:队列内存限额、连接数上限、磁盘空间检查

核心概念速查表

概念 说明
RPC 消息 所有节点间通信的基本单元,由固定格式的消息头 + 可变长消息体组成
消息类型(msgType) 标识消息用途的枚举值,按模块分段(MND/VND/SCH/SYNC 等)
EP Set 端点集合,包含最多 3 个 mnode 的地址,用于自动切换
连接池 客户端按目标地址维护的可复用 TCP 连接队列
消息队列 服务端按功能划分的处理队列(写队列、读队列、同步队列等)
traceId 贯穿请求全生命周期的追踪标识,用于分布式链路追踪
QID 查询 ID,标识一个查询请求,用于关联请求和响应
魔数 固定值 0x5f375a86,用于快速识别合法的 TDengine 数据包

详细解析

1. 协议格式

1.1 消息头结构

每条 RPC 消息都包含一个固定格式的二进制消息头,紧接着是可变长度的消息体:

复制代码
RPC 消息二进制布局:

  ┌──────────────────────────────────────────────────────────┐
  │                      消息头(固定大小)                    │
  ├──────────────────────────────────────────────────────────┤
  │ 标志位(1B) │ 标志位(1B) │ 时间戳(8B) │ 兼容版本号(4B)    │
  ├──────────────────────────────────────────────────────────┤
  │ 魔数(4B)   │ traceId(16B)        │ QID(8B)             │
  ├──────────────────────────────────────────────────────────┤
  │ 状态码(4B) │ 消息类型(4B) │ 消息总长度(4B) │ 序列号(8B) │
  ├──────────────────────────────────────────────────────────┤
  │                    消息体(可变长度)                      │
  └──────────────────────────────────────────────────────────┘

各字段说明:

字段 大小 说明
version 4 bit RPC 协议版本号,当前固定为 2
comp 2 bit 压缩标志:0=未压缩,1=LZ4 压缩
noResp 2 bit 是否需要响应:0=需要,1=不需要
withUserInfo 2 bit 是否携带用户认证信息
hasEpSet 2 bit 响应中是否包含 EP Set 更新信息
timestamp 8 字节 发送时的时间戳
compatibilityVer 4 字节 客户端/服务端的兼容版本号
magicNum 4 字节 魔数 0x5f375a86,用于包合法性校验
traceId 16 字节 分布式追踪 ID,贯穿请求全链路
qid 8 字节 查询 ID
code 4 字节 响应状态码(请求时为 0)
msgType 4 字节 消息类型枚举值
msgLen 4 字节 消息总长度(消息头 + 消息体)
seqNum 8 字节 每连接递增的序列号
1.2 消息大小限制
限制 说明
单消息最大长度 512 MB 包含消息头的总长度上限
默认最大消息体 10 MB 应用层默认限制(可调整)
压缩头额外开销 8 字节 压缩时额外的长度信息
1.3 消息类型分段

TDengine 将消息类型按目标模块分为多个段(segment),便于路由和管理:

段号 前缀 目标模块 典型消息
0 TDMT_DND_* DNode 管理 创建/删除 vnode、mnode
1 TDMT_MND_* MNode DDL 操作、心跳、元数据查询
2 TDMT_VND_* VNode 数据写入、子表创建
3 TDMT_SCH_* 调度器 查询执行、结果获取
4 TDMT_STREAM_* 流计算 流任务调度
5 TDMT_MON_* 监控 监控数据上报
6 TDMT_SYNC_* Raft 同步 选举、日志复制、心跳
7 TDMT_VND_STREAM_* VNode 流计算 VNode 上的流处理
8 TDMT_VND_TMQ_* TMQ 订阅 消费请求
9 TDMT_MND_ARB_* 仲裁 仲裁心跳与同步

每个消息类型都有对应的请求(xxx_REQ)和响应(xxx_RSP)成对定义。

1.4 魔数与版本校验

收到数据包后,RPC 层执行两层校验:

  1. 魔数校验 :检查消息头中的魔数是否为 0x5f375a86。非法包(如端口扫描、误连接)在此步即被丢弃
  2. 版本兼容性校验 :比对客户端和服务端的 compatibilityVer,允许最多 3 个版本的差异。超出范围时返回版本不兼容错误

2. 连接管理

2.1 网络基础 --- libuv

TDengine 的 RPC 层基于 libuv 库构建,使用事件驱动的异步 I/O 模型:

  • 每个 RPC 线程运行一个独立的 uv_loop(事件循环)
  • TCP 连接使用 uv_tcp_t 句柄
  • 线程间通信使用 uv_async_t(异步通知)和 uv_pipe_t(管道)
2.2 服务端架构
复制代码
服务端连接模型:

  ┌─────────────────────────────────────────────────┐
  │              RPC Server (端口 6030)               │
  │                                                   │
  │   Accept 线程                                     │
  │     │  uv_tcp_t (监听 socket)                     │
  │     │                                             │
  │     ├── 新连接到达 → 按轮转分配到 Worker 线程       │
  │     │                                             │
  │   ┌─▼──────────┐  ┌───────────┐  ┌───────────┐  │
  │   │ Worker 0   │  │ Worker 1  │  │ Worker N  │  │
  │   │ uv_loop    │  │ uv_loop   │  │ uv_loop   │  │
  │   │            │  │           │  │           │  │
  │   │ conn pool  │  │ conn pool │  │ conn pool │  │
  │   │ ├ conn A   │  │ ├ conn D  │  │ ├ conn G  │  │
  │   │ ├ conn B   │  │ ├ conn E  │  │ └ conn H  │  │
  │   │ └ conn C   │  │ └ conn F  │  │           │  │
  │   └────────────┘  └───────────┘  └───────────┘  │
  └─────────────────────────────────────────────────┘
  • Accept 线程:负责接受新的 TCP 连接,通过管道将连接分发给 Worker 线程
  • Worker 线程:处理连接上的读写事件,解析消息,将请求分发到对应的处理队列
  • 线程数由 numOfRpcThreads 参数控制
2.3 客户端连接池

客户端(taosc 和 dnode 内部通信)为每个目标地址维护一个连接池

复制代码
客户端连接池模型:

  ┌────────────────────────────────────────────┐
  │           RPC Client 线程 0                  │
  │                                              │
  │  连接池(按目标地址分组):                    │
  │    "node1:6030" → [idle_conn1, idle_conn2]  │
  │    "node2:6030" → [idle_conn3]              │
  │    "node3:6030" → [](无空闲连接)           │
  │                                              │
  │  共享连接堆缓存:                             │
  │    允许多个请求复用同一 TCP 连接              │
  └────────────────────────────────────────────┘

连接复用策略

  1. 发送请求时,先从连接池中查找目标地址的空闲连接
  2. 如果有空闲连接,直接复用
  3. 如果无空闲连接且未达上限,创建新连接
  4. 如果已达连接上限,等待现有连接释放(最多等待 timeToGetAvailableConn 毫秒)
  5. 请求完成后,连接归还到池中供后续请求使用

连接多路复用

在 Linux 上,单个 TCP 连接允许最多 10 个并发的未完成请求(shareConnLimit),通过序列号(seqNum)匹配请求和响应。macOS/Windows 上限制为 1(不启用多路复用)。

2.4 空闲连接回收
复制代码
空闲回收机制:

  连接空闲时间超过阈值 → 自动关闭

  阈值计算:
    基础空闲时间 = max(shellActivityTimer × 1000ms, 90秒)
    实际关闭时间 ≈ 基础空闲时间 × 3.3
    默认情况 ≈ 5 分钟无活动后关闭
2.5 连接建立超时
超时类型 默认值 说明
TCP 连接超时 5 秒 TCP 三次握手的超时时间
读超时 3 秒 等待数据读取的超时
等待可用连接 500 秒 连接池满时等待空闲连接的超时

3. 重试机制

3.1 指数退避算法

当 RPC 请求失败时,客户端使用指数退避策略进行重试:

复制代码
重试算法:

  第 1 次重试:等待 10ms
  第 2 次重试:等待 20ms    (10 × 2¹)
  第 3 次重试:等待 40ms    (10 × 2²)
  第 4 次重试:等待 80ms    (10 × 2³)
  ...
  第 N 次重试:等待 min(10 × 2^(N-1), 1000ms)
  
  最大重试间隔:1000ms(不再增长)
  总超时限制:20秒(默认)
  
  超过总超时 → 放弃重试,返回错误给上层

关键参数

参数 默认值 说明
retryMinInterval 10 ms 首次重试等待时间
retryStepFactor 2 退避倍数
retryMaxInterval 1000 ms 单次重试最大等待时间
maxRetryWaitTime 20000 ms 总重试超时(可配置,范围 3秒~24小时)
3.2 可重试的错误码

RPC 层只对临时性错误进行重试,永久性错误(如权限不足、SQL 语法错误)直接返回:

错误码 含义 重试原因
TSDB_CODE_RPC_NETWORK_UNAVAIL 网络不可达 可能是瞬时网络波动
TSDB_CODE_RPC_BROKEN_LINK 连接断开 服务端可能重启中
TSDB_CODE_MNODE_NOT_FOUND MNode 不可达 Leader 可能在切换
TSDB_CODE_SYN_NOT_LEADER 非 Leader 节点 需要切换到新 Leader
TSDB_CODE_SYN_RESTORING Raft 恢复中 等待恢复完成
TSDB_CODE_APP_IS_STARTING 服务启动中 等待服务就绪
TSDB_CODE_APP_IS_STOPPING 服务关闭中 切换到其他节点
TSDB_CODE_VND_STOPPED VNode 已停止 可能在迁移中
3.3 不重试的消息类型

以下消息类型不进行 RPC 层重试(由上层自行处理):

  • 查询执行消息(QUERY / MERGE_QUERY
  • 结果获取消息(FETCH / MERGE_FETCH
  • 查询心跳消息
  • 任务通知和任务清理消息

原因:这些消息是有状态的查询操作,简单重试可能导致重复执行或状态不一致。

3.4 EP Set 轮转

当请求发往 MNode 失败时,RPC 层会自动切换到 EP Set 中的下一个地址重试:

复制代码
EP Set 轮转示例:

  EP Set = [node1:6030, node2:6030, node3:6030]
  当前使用 = node1 (inUse=0)
  
  请求失败 → inUse 前移到 node2 (inUse=1) → 重试
  再次失败 → inUse 前移到 node3 (inUse=2) → 重试
  再次失败 → inUse 回绕到 node1 (inUse=0) → 等待退避后重试

这保证了 MNode Leader 切换时,客户端能自动找到新 Leader。

3.5 快速失败机制

为了避免对已确认故障的节点持续发送请求,RPC 层实现了快速失败:

  • 连续 3 次 请求失败(failFastThreshold = 3
  • 5 秒 内(failFastInterval = 5000ms
  • → 后续请求直接返回失败,不再尝试连接该节点
  • 超过 5 秒后恢复正常重试

4. 通道隔离

4.1 服务端 --- 单端口多队列

TDengine 服务端只监听一个 TCP 端口(默认 6030),但通过消息队列实现不同类型请求的隔离:

复制代码
服务端消息分发:

  TCP 端口 6030 (所有请求)
        │
        ▼
  消息头解析 → 提取 msgType + vgId
        │
        ├── TDMT_MND_* (mnode 消息)
        │     ├── DDL 操作 → 写队列
        │     ├── SHOW 命令 → 读队列
        │     └── 心跳状态 → 状态队列
        │
        ├── TDMT_VND_* (vnode 消息)
        │     ├── 数据写入 → 写队列(检查磁盘空间)
        │     ├── 子表创建 → 写队列
        │     └── 查询执行 → 查询队列
        │
        ├── TDMT_SCH_* (调度消息)
        │     ├── 查询 → 查询队列(带预处理)
        │     └── 获取结果 → 获取队列
        │
        ├── TDMT_SYNC_* (Raft 消息)
        │     ├── 选举/日志 → 同步队列
        │     └── 心跳 → 同步读队列
        │
        └── TDMT_STREAM_* (流计算消息)
              ├── 普通任务 → 流计算队列
              ├── 控制消息 → 流计算控制队列
              └── 长任务 → 长执行队列
4.2 服务端队列类型
队列 用途 特点
写队列 DDL、数据写入 写入前检查磁盘空间
读队列 元数据查询、SHOW 命令 只读操作,可高并发
查询队列 SQL 查询执行 请求预处理后入队
获取队列 查询结果获取 轻量操作
同步队列 Raft 选举、日志复制 高优先级
同步读队列 Raft 心跳 高频低延迟
应用队列 Raft 提交应用 有独立内存限额
流计算队列 流任务处理 可能长时间执行
流控制队列 流管理操作 控制面消息
检查点队列 流计算状态持久化 周期性触发
状态队列 DNode 心跳上报 MNode 专用
仲裁队列 Arbitrator 通信 独立隔离
4.3 客户端 --- 多 RPC 实例

客户端(包括 dnode 内部通信)使用多个独立的 RPC 实例,分离不同类型的流量:

RPC 实例 线程数 用途 为什么隔离
通用实例 numOfRpcThreads / 2 dnode 间一般通信 默认通道
状态实例 1 心跳/状态上报到 MNode 防止被大量业务消息阻塞,保证心跳不超时
同步实例 numOfRpcThreads / 2 Raft 日志复制 防止 Raft 消息被业务消息饿死

为什么要隔离心跳?

如果心跳和数据写入共用同一个 RPC 实例,当写入量极大时,心跳消息可能被积压在队列中无法及时发送,导致 MNode 误判节点离线。独立的状态 RPC 实例保证心跳消息始终有专用通道。

4.4 客户端(taosc)RPC 实例

用户应用程序通过 taosc 驱动连接时,使用一个独立的 RPC 实例:

参数
线程数 numOfRpcThreads
最大会话数 1024
连接池上限 10~1000(按配置计算)
消息批量发送 未启用
连接多路复用 shareConnLimit 控制

5. 认证与安全

5.1 用户信息传递

RPC 层使用首次消息携带的方式完成认证:

复制代码
认证流程:

  客户端                          服务端
    │                              │
    │  首次请求(withUserInfo=1)    │
    │  [消息头][用户名+密码哈希]     │
    │─────────────────────────────→│
    │                              │  提取用户信息
    │                              │  绑定到连接对象
    │                              │  后续请求无需再传
    │                              │
    │  后续请求(withUserInfo=0)    │
    │  [消息头][消息体]             │
    │─────────────────────────────→│
    │                              │  从连接对象获取用户
  • 每个新建的 TCP 连接,第一条消息会附带用户名和密码摘要
  • 服务端验证后将用户信息绑定到该连接
  • 后续消息不再传递用户信息,减少网络开销
5.2 IP 白名单

服务端支持按用户配置 IP 白名单

  • 每次收到请求时,检查发送方 IP 是否在该用户的白名单中
  • 白名单信息从 MNode 同步,带有版本号用于增量更新
  • 不在白名单中的请求返回 TSDB_CODE_IP_NOT_IN_WHITE_LIST
sql 复制代码
-- 配置 IP 白名单
ALTER USER test_user ADD HOST '192.168.1.0/24';
ALTER USER test_user DROP HOST '10.0.0.0/8';
5.3 版本兼容性校验

每条消息头都携带发送方的兼容版本号(compatibilityVer)。服务端收到请求后:

  • 比对客户端版本与服务端版本
  • 允许最多 3 个版本号的差异
  • 超出范围时返回版本不兼容错误

这确保了滚动升级时,新旧版本节点可以短暂共存通信。

6. 消息压缩

6.1 LZ4 压缩

RPC 层支持对消息体进行 LZ4 压缩,减少网络传输量:

复制代码
压缩判断逻辑:

  消息体大小 > compressMsgSize?
    ├── 是 → 执行 LZ4 压缩
    │         ├── 压缩后更小 → 使用压缩数据,标记 comp=1
    │         └── 压缩后反而更大 → 保持原始数据
    └── 否 → 不压缩
6.2 压缩配置
compressMsgSize 行为
-1(默认) 不压缩任何消息
0 压缩所有消息
N > 0 仅压缩消息体超过 N 字节的消息

配置范围:-1 到 100000000(100MB)。

建议 :在跨机房或带宽受限的网络环境中,设置 compressMsgSize = 65536(64KB)可以显著减少大批量写入时的网络流量,但会增加少量 CPU 开销。

7. 流控与背压

7.1 队列内存限额

服务端对消息处理队列实施内存限制,防止请求堆积导致 OOM:

复制代码
内存限额计算:

  总可用内存 = 系统总内存
  RPC 队列内存 = 总可用内存 × 10% × 60%
  应用队列内存 = 总可用内存 × 10% × 40%
  
  示例(64GB 内存机器):
    RPC 队列上限 ≈ 3.84 GB
    应用队列上限 ≈ 2.56 GB

当队列内存使用超过限额时:

  • 新请求被拒绝,返回 TSDB_CODE_OUT_OF_RPC_MEMORY_QUEUE
  • 客户端收到此错误后会进入重试逻辑
  • 相当于 TCP 层面的流控------告知客户端"我处理不过来,请稍后再试"
7.2 连接数限制
限制维度 参数 默认值 说明
服务端最大连接数 maxShellConns 50000 所有客户端连接总数上限
客户端单目标连接数 connLimitNum 自动计算(10~1000) 到同一目标地址的最大连接数
客户端总会话数 numOfRpcSessions 30000 所有目标的连接总数

超过连接数限制时返回 TSDB_CODE_RPC_MAX_SESSIONS

7.3 磁盘空间检查

写队列有额外的前置检查------将消息入队前验证磁盘空间是否充足:

  • 磁盘空间不足时直接拒绝写入请求
  • 返回 TSDB_CODE_NO_ENOUGH_DISKSPACE
  • 避免消息入队后因磁盘满而处理失败
7.4 消息批量发送

dnode 间通信(非客户端)支持消息批量发送------将多条待发送消息合并为一次 TCP 写入:

  • 减少系统调用次数
  • 降低网络开销(TCP 小包问题)
  • 批量大小有上限,防止单次发送过大

8. 请求的完整生命周期

以客户端发送一条写入请求为例:

复制代码
RPC 请求完整生命周期:

  客户端应用
    │
    │ 1. 调用 API(如 taos_query)
    ▼
  taosc 客户端驱动
    │ 2. 构建消息体(序列化 SQL/数据)
    │ 3. 根据表名 hash 确定目标 VGroup
    │ 4. 从 Catalog 缓存获取 Leader 地址
    ▼
  RPC 客户端层
    │ 5. 选择 RPC 线程(轮转分配)
    │ 6. 从连接池获取/创建 TCP 连接
    │ 7. 填充消息头(msgType, traceId, qid, seq, timestamp, magic)
    │ 8. 压缩判断(消息体 > compressMsgSize?)
    │ 9. 首次连接?附加用户认证信息
    │ 10. uv_write() 发送到网络
    ▼
  网络传输(TCP)
    ▼
  RPC 服务端层
    │ 11. Worker 线程的 uv_loop 收到数据
    │ 12. 解析消息头,校验魔数和版本
    │ 13. 解压缩(如果 comp=1)
    │ 14. 提取用户信息(如果 withUserInfo=1)
    │ 15. IP 白名单检查
    │ 16. 根据 msgType 确定目标队列
    │ 17. 检查队列内存限额
    │ 18. 入队
    ▼
  业务处理层
    │ 19. Worker 从队列取出消息
    │ 20. 执行业务逻辑(写入 WAL、MemTable 等)
    │ 21. 构建响应消息
    ▼
  RPC 服务端层
    │ 22. 填充响应头(code, EP Set 更新等)
    │ 23. uv_write() 发送响应
    ▼
  网络传输(TCP)
    ▼
  RPC 客户端层
    │ 24. 收到响应,通过 seqNum 匹配请求
    │ 25. 检查 code:成功?需要重试?
    │     ├── 成功 → 回调上层
    │     └── 可重试错误 → 指数退避后重发
    │ 26. 归还连接到连接池
    ▼
  taosc 客户端驱动
    │ 27. 解析响应,返回结果给应用
    ▼
  客户端应用

代码示例

配置 RPC 参数

bash 复制代码
# /etc/taos/taos.cfg

# RPC 线程数(默认 CPU 核数/2)
numOfRpcThreads    4

# 最大会话数
numOfRpcSessions   30000

# 消息压缩阈值(字节,-1=不压缩)
compressMsgSize    65536

# 服务端最大连接数
maxShellConns      50000

# 空闲连接基础超时(秒)
shellActivityTimer 3

# 读超时(秒)
readTimeout        900

# 最大重试等待时间(毫秒)
maxRetryWaitTime   20000

# 连接多路复用上限
shareConnLimit     10

监控 RPC 连接状态

sql 复制代码
-- 查看当前活跃连接
SHOW CONNECTIONS;

-- 输出示例:
-- connId | user  | program    | pid  | endpoint        | login_time          | last_access
--      1 | root  | taos       | 1234 | 192.168.1.10:56789 | 2024-01-15 10:00:00 | 2024-01-15 10:05:30

-- 查看查询(可间接反映 RPC 活跃度)
SHOW QUERIES;

-- 杀掉特定连接
KILL CONNECTION <connId>;

排查连接问题

bash 复制代码
# 检查端口是否监听
netstat -tlnp | grep 6030

# 检查 FQDN 解析
ping node1.example.com

# 检查防火墙(6030 是唯一需要开放的端口)
telnet node1.example.com 6030

# 检查 RPC 相关日志(包含 traceId 用于链路追踪)
grep "RPC" /var/log/taos/taosdlog.* | tail -20

跨机房部署的压缩优化

bash 复制代码
# 场景:客户端和服务端不在同一机房,带宽有限
# 建议开启消息压缩

# 客户端 taos.cfg
compressMsgSize    0    # 压缩所有消息(跨机房场景)

# 或者只压缩大消息(> 64KB)
compressMsgSize    65536

高并发场景的 RPC 调优

bash 复制代码
# 场景:大量客户端并发连接,每秒数万请求
# 在服务端 taos.cfg 中:

# 增加 RPC 线程数
numOfRpcThreads    8

# 增加最大连接数
maxShellConns      100000

# 增加会话数
numOfRpcSessions   50000

# 场景:客户端到服务端延迟高(如跨地域)
# 在客户端 taos.cfg 中:

# 增加重试等待时间
maxRetryWaitTime   60000

# 增加读超时
readTimeout        1800

# 增加连接多路复用(减少连接数)
shareConnLimit     20

性能考量

RPC 延迟构成

复制代码
一次 RPC 请求的延迟 = 
    客户端序列化 + 
    TCP 传输(往返) + 
    服务端反序列化 + 
    队列排队等待 + 
    业务处理 + 
    响应序列化 + 
    TCP 传输(返回) + 
    客户端反序列化

典型值(同机房):
    网络往返:0.1~0.5ms
    序列化:< 0.1ms
    队列等待:0~数ms(取决于负载)
    业务处理:视操作而定
    
    总体:简单操作 0.5~2ms,复杂查询取决于执行时间

关键调优参数总结

场景 建议调整
高并发连接 增加 numOfRpcThreadsmaxShellConns
跨机房/高延迟 增加 maxRetryWaitTimereadTimeout、开启压缩
大批量写入 增加 shareConnLimit 复用连接
内存紧张 减少 numOfRpcSessions,降低连接池规模
频繁超时 检查网络、增加 shellActivityTimer

性能瓶颈识别

现象 可能原因 排查方式
请求延迟突增 队列积压 查看 TSDB_CODE_OUT_OF_RPC_MEMORY_QUEUE 错误
连接被拒绝 达到连接上限 查看 TSDB_CODE_RPC_MAX_SESSIONS 错误
频繁重连 空闲超时过短 增大 shellActivityTimer
写入超时 磁盘满 查看 TSDB_CODE_NO_ENOUGH_DISKSPACE 错误
偶发失败后恢复 正常重试行为 检查日志中的 retry 信息

FAQ

Q1: TDengine 使用什么网络协议通信?

TCP。TDengine 的 RPC 层基于 libuv 构建,所有节点间通信(客户端→服务端、dnode→mnode、Raft 复制)都使用 TCP 长连接。不使用 UDP,也不使用 HTTP(HTTP/WebSocket 由 taosAdapter 提供,是另一层封装)。

Q2: 只需要开放一个端口就够了吗?

是的。TDengine v3.x 只使用一个 TCP 端口(默认 6030)。所有类型的消息(写入、查询、心跳、Raft 复制)都通过这一个端口传输,在内部通过消息类型路由到不同的处理队列。

v2.x 时代需要开放多个端口(6030~6042),v3.x 简化为单端口。

Q3: 客户端到服务端的连接会一直保持吗?

不会无限保持。默认情况下,空闲约 5 分钟后连接会被自动关闭。下次请求时会自动重新建立连接。这个行为对应用程序是透明的。

如果需要保持长连接(如实时监控场景),可以增大 shellActivityTimer 参数。

Q4: 网络断开后会自动重连吗?

是的。RPC 层会在发送请求失败时自动重试(指数退避,默认总超时 20 秒)。在此期间如果网络恢复,请求会自动成功。如果超过总超时仍然失败,会返回错误码给应用程序,应用层可以自行决定是否继续重试。

Q5: 为什么 SHOW CONNECTIONS 显示的连接数比客户端数多?

因为客户端和服务端之间可能建立多条 TCP 连接(连接池机制)。此外,dnode 之间的内部通信(心跳、Raft)也会占用连接。每个独立的 TCP 连接都会显示为一行。

Q6: compressMsgSize 设为 0 会影响性能吗?

会有轻微的 CPU 开销(LZ4 压缩/解压)。但对于可压缩性高的数据(如时序数据的批量写入),网络传输减少带来的收益通常远大于 CPU 开销。

建议:

  • 同机房、万兆网络:不压缩(默认 -1
  • 跨机房或带宽受限:设为 065536
  • CPU 瓶颈场景:不压缩

Q7: RPC 超时参数应该如何调整?

场景 maxRetryWaitTime readTimeout
同机房,低延迟 20000(默认) 900(默认)
跨城市,中等延迟 60000 1800
跨国际,高延迟 120000 3600
大查询,结果集很大 20000 3600~86400

readTimeout 特别重要------如果查询执行时间超过这个值,连接会被断开。对于复杂的大数据量查询,务必设置足够大的 readTimeout

Q8: traceId 有什么用?如何利用?

traceId 是一个 128 位的标识符,在请求发起时生成,贯穿整个处理链路(客户端 → RPC → 服务端 → 写入/查询)。所有相关日志都会打印 traceId,用于:

  1. 问题排查:根据 traceId 搜索 taosd 日志,追踪一个请求的完整执行路径
  2. 性能分析:对比请求在各阶段的耗时
  3. 关联分析:将客户端错误与服务端日志对应起来
bash 复制代码
# 根据 traceId 搜索日志
grep "QID:0x<qid_hex>" /var/log/taos/taosdlog.*

参考

第一篇 系统构架

关于 TDengine

TDengine 专为物联网IoT平台、工业大数据平台设计。其中,TDengine TSDB 是一款高性能、分布式的时序数据库(Time Series Database),同时它还带有内建的缓存、流式计算、数据订阅等系统功能;TDengine IDMP 是一款AI原生工业数据管理平台,它通过树状层次结构建立数据目录,对数据进行标准化、情景化,并通过 AI 提供实时分析、可视化、事件管理与报警等功能。

相关推荐
BD_Marathon1 小时前
SQL学习指南——创建和填充数据库
数据库·sql
KaMeidebaby1 小时前
卡梅德生物技术快报|噬菌体筛选全流程技术方案:弧菌抑菌菌株筛选、特性鉴定与效果测试
前端·数据库·其他·百度·新浪微博
蜀道山老天师1 小时前
从零搭建 Prometheus 监控 MySQL:含二进制安装、授权、exporter 配置全流程
运维·数据库·mysql·adb·云原生·prometheus
yubin12855709231 小时前
mysql正则函数REGEXP
android·数据库·mysql
yoyo_zzm1 小时前
PHP vs Java:后端语言终极选择指南
java·spring boot·后端·架构·php
塔能物联运维1 小时前
存量机房低成本改造:塔能两相液冷实现投入与效益双赢
大数据·数据库·人工智能
2401_850491651 小时前
PHP 中处理会话数组时的类型错误解析与修复指南
jvm·数据库·python
JSMSEMI111 小时前
JSM13N50F 500V N 沟道功率 MOSFET
大数据·网络·人工智能