TDengine 分布式查询执行 — Scheduler、Task 调度与跨节点协调

分类 :4.查询引擎 | 篇章:11 分布式查询

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

TDengine 的分布式查询由 Client 端 Scheduler 统一调度。Scheduler 把物理计划的 Subplan 拆分为可独立调度的 Task,下发到对应 VNode/QNode,通过 Exchange 拉取结果,汇总后返回客户端。

核心概念速查表

概念 说明
Scheduler 客户端查询调度器
Task Subplan 在具体节点的执行实例
Job 一次查询的所有 Task 集合
Task State NOT_START / EXECUTING / SUCCEED / FAILED
Pull-based Exchange 上层主动拉取下层数据
Backpressure 反压(上层处理慢时下层暂停)

详细解析

1. Scheduler 的职责

复制代码
Client Scheduler 工作流程:

  ① 接收物理计划(含多个 Subplan)
  ② 为每个 Subplan 创建 Task
  ③ 决定 Task 的执行节点:
     - 叶子 Subplan(含 Scan)→ 对应 VGroup 的 Leader VNode
     - 中间 Subplan(含汇总)→ QNode 或 Client
     - 顶层 Subplan → Client
  ④ 按 DAG 依赖关系调度 Task:
     - 叶子 Task 先启动
     - 中间 Task 依赖叶子完成
  ⑤ 通过 Exchange 拉取结果
  ⑥ 汇总后返回应用

2. Task 生命周期

复制代码
Task 状态机:

  ┌──────────┐   被调度    ┌────────────┐
  │NOT_START │ ──────────→ │ EXECUTING  │
  └──────────┘             └─────┬──────┘
                                 │
              ┌──────────────────┼──────────────────┐
              ▼                  ▼                   ▼
        ┌─────────┐        ┌─────────┐          ┌─────────┐
        │ SUCCEED │        │ FAILED  │          │ DROPPING│
        └─────────┘        └─────────┘          └─────────┘
              │                  │                   │
              └──────────────────┴───────────────────┘
                                 ▼
                          ┌─────────────┐
                          │  DROPPED    │
                          └─────────────┘

  
关键状态:
  - NOT_START: 创建但未发送到节点
  - EXECUTING: 服务端正在执行
  - SUCCEED: 完成,结果可拉取
  - FAILED: 失败,需要错误处理或重试
  - DROPPING/DROPPED: 取消中/已取消

3. 节点选择策略

复制代码
Task 分配到节点的规则:

  ① 叶子 Subplan(含 TableScan):
     - 根据涉及的 VGroup 选择对应 VNode
     - 优先选 Leader(写一致性最强)
     - Leader 不可用时选 Follower(仅查询)
     
  ② 中间汇总 Subplan:
     - 集群配置了 QNode → 调度到 QNode
     - 无 QNode → 调度到 Client 端执行
     - 显式 hint USE_QNODE → 强制 QNode
     
  ③ 顶层结果 Subplan:
     - 总是在 Client 端


负载均衡:
  - 多 QNode 时按 Round Robin 或最少负载选择
  - Tag 查询时智能选择 META 缓存较新的节点

4. Pull-based Exchange

复制代码
Exchange 的拉取模式:

  Subplan 0 (Client)
    Exchange Operator (Pull Mode)
        │
        │ Fetch Request (10 blocks)
        ▼
  Subplan 1 (VNode 1)
    DataSink
    Partial Agg
    Scan
  
  
工作流程:
  
  ① Subplan 1 执行后将结果块缓存到 DataSink
  ② Exchange 算子按需发送 Fetch 请求
  ③ DataSink 返回缓存的数据块
  ④ Exchange 处理后继续 Fetch 下一批
  ⑤ DataSink 数据用尽 → 返回 "no more data"
  ⑥ Exchange 标记下层 Subplan 完成


优势:
  - 反压自然实现(上层处理慢则不 Fetch)
  - 内存占用可控(不会缓存全部结果)
  - 失败重试简单(重新 Fetch)

5. 跨 VGroup 并行

复制代码
并行度示例:

  超级表 meters 跨 8 个 VGroup
  
  SELECT location, AVG(current) FROM meters GROUP BY location;
  
  Job 启动:
    Task 0 → Client (Final Agg + Exchange)
    Task 1 → VNode of VG1 (Partial Agg + Scan)
    Task 2 → VNode of VG2 (Partial Agg + Scan)
    ...
    Task 8 → VNode of VG8 (Partial Agg + Scan)
    
  并行执行:
    Task 1~8 同时启动 → 8 个 VNode 并行扫描
    任一完成后 Client 开始 Fetch 该 Task 结果
    全部完成后 Client 输出 Final Agg 结果
    
  并行度:min(VGroup 数, 网络带宽容量)

6. 失败处理与重试

复制代码
Task 失败的处理:

  ① VNode 临时不可用(如重启):
     - 切换到 Follower 重试
     - 仍失败 → 整个 Job 失败
     
  ② 网络超时:
     - 自动重试有限次数
     - 超过阈值 → Job 失败
     
  ③ 查询超时(maxQueryTime):
     - 主动取消所有 Task
     - 返回超时错误
     
  ④ 服务端 OOM:
     - Task 失败上报
     - Job 整体失败

  
取消机制:
  - 客户端取消查询 → Scheduler 向所有 Task 发送 DROP 请求
  - 服务端响应 → 停止执行并清理资源
  - 防止"孤儿"查询占用资源

7. 查询资源隔离

复制代码
资源隔离层级:

  ① 全局:maxConnections(最大连接数)
  
  ② 单查询:
     - queryBufferSize: 单查询内存上限
     - maxQueryTime: 单查询时间上限
     
  ③ 节点级:
     - numOfVnodeQueryThreads: 查询线程数
     - 查询队列长度限制
  
  ④ 用户级(企业版):
     - 资源组(CPU/内存配额)
     - 查询优先级
  
  
查询排队:
  - 当查询线程都忙 → 新 Task 排队
  - 队列满 → 拒绝新查询并返回错误
  - 不会无限等待造成雪崩

8. 监控分布式查询

sql 复制代码
-- 查看当前运行的查询
SELECT * FROM performance_schema.perf_queries;

-- 查看连接信息
SELECT * FROM performance_schema.perf_connections;

-- 查看应用信息
SELECT * FROM performance_schema.perf_apps;

-- 关键字段:
-- exec_usec: 已执行时间(微秒)
-- sub_num: Subplan 数量
-- pid: 客户端进程
-- sql: SQL 文本

代码示例

配置 QNode

sql 复制代码
-- 创建 QNode
CREATE QNODE ON DNODE 3;

-- 查看 QNode
SHOW QNODES;

-- 删除 QNode
DROP QNODE ON DNODE 3;

查询超时控制

sql 复制代码
-- 全局配置(taos.cfg)
-- maxQueryTime 600   -- 秒

-- 客户端单次设置
-- 通过连接参数或 SDK API 设置超时

取消运行中的查询

sql 复制代码
-- 查找 QID(查询 ID)
SELECT * FROM performance_schema.perf_queries;

-- 取消查询
KILL QUERY 'conn_id:qid';

性能考量

分布式开销分析

阶段 典型耗时
Plan 生成 1~10ms
Task 分发(每节点) 1~5ms
Task 启动延迟 < 10ms
Exchange 网络往返 取决于数据量
Final 汇总 取决于中间结果量

优化建议

场景 建议
集群规模大(> 10 节点) 部署 QNode 隔离查询
大量小查询并发 用连接池复用连接
单查询超大数据量 用 LIMIT 限制返回量
查询超时频繁 调大 maxQueryTime 或优化 SQL

FAQ

Q1: QNode 失效会怎样?

如果集群有多个 QNode,会自动切换到其他 QNode。如果只有一个 QNode 且失效,查询会回退到 Client 端汇总(性能可能下降)。

Q2: Follower 节点能服务查询吗?

可以。TDengine 支持 Follower 读(视配置)。但 Leader 数据最新,关键查询仍优先 Leader。

Q3: 单个 Task 失败会重试吗?

视失败类型:

  • 网络瞬时错误:会重试
  • 服务端错误(如表不存在):不重试,直接失败
  • 节点不可用:切换其他副本重试

Q4: 客户端断开后服务端查询会立即停止吗?

不会立即停止。Scheduler 会发送 DROP 信号,但服务端正在执行的算子可能需要走完当前 Block 才能响应取消。通常在秒级清理完毕。

参考

系统构架篇

数据模型

存储引擎

查询引擎

关于 TDengine

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