分类 :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 才能响应取消。通常在秒级清理完毕。
参考
系统构架篇
- 01-《TDengine 整体架构全景》
- 02-《集群拓扑深度解析》
- 03-《MNode 内部机制深度解析》
- 04-《RPC 通信层深度解析》
- 05-《VNode 生命周期》
- 06-《RAFT 共识协议》
- 07-《端到端的消息流》
数据模型
- 01-《数据库创建与参数详解》
- 02-《超级表/子表/普通表》
- 03-《支持数据类型深度解析》
- 04-《TDengine Tag 设计哲学与 Schema 变更机制》
- 05-《TDengine 虚拟表实现原理》
存储引擎
- 01-《TDengine 存储引擎概览》
- 02-《TDengine MemTable 深度解析》
- 03-《TDengine WAL 预写日志机制》
- 04-《TDengine 数据文件格式》
- 05-《TDengine Commit 与 Flush 机制 》
- 06-《TDengine Compaction 合并策略 》
- 07-《TDengine 数据保留与 TTL》
- 08-《TDengine 压缩编码机制》
- 09-《TDengine Cache 与 Last 查询加速》
- 10-《TDengine 逻辑计划生成》
查询引擎
- 01-《TDengine 查询引擎概览》
- 02-《TDengine SQL 解析与词法分析》
- 03-《TDengine 语义分析与 AST 重写》
- 04-《TDengine 逻辑计划生成》
- 05-《TDengine 物理计划生成》
- 06-《TDengine 扫描算子》
- 07-《TDengine 聚合算子》
- 08-《TDengine 聚合算子》
- 09-《TDengine 连接算子》
- 10-《TDengine 排序、填充与投影》
关于 TDengine
TDengine 专为物联网IoT平台、工业大数据平台设计。其中,TDengine TSDB 是一款高性能、分布式的时序数据库(Time Series Database),同时它还带有内建的缓存、流式计算、数据订阅等系统功能;TDengine IDMP 是一款AI原生工业数据管理平台,它通过树状层次结构建立数据目录,对数据进行标准化、情景化,并通过 AI 提供实时分析、可视化、事件管理与报警等功能。