TDengine 线程模型 --- 网络、调度、执行
分类 :17.内部机制 | 篇章 :02 线程模型
TDengine 是高并发系统,线程模型直接影响吞吐和延迟。本文从原理角度介绍各类线程池和调度机制。
线程池速查表
| 线程池 | 数量参数 | 用途 |
|---|---|---|
| RPC 线程 | numOfRpcThreads | 网络收发 |
| Query 线程 | numOfTaskQueueThreads | 查询执行 |
| Commit 线程 | numOfCommitThreads | 写入落盘 |
| Sync 线程 | 内部 | RAFT 同步 |
| Stream 线程 | 内部 | 流计算 |
| Mgmt 线程 | 内部 | 管理操作 |
详细解析
1. 整体线程架构
┌──────────────────────────────────────┐
│ 网络 I/O 线程池 │
│ - 异步 epoll │
│ - 解码 RPC 消息 │
│ - 路由到对应队列 │
└──────────────────────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ 任务调度层 │
│ - 按 VGroup 分队列 │
│ - 按优先级排序 │
│ - 防止单查询阻塞 │
└──────────────────────────────────────┘
│
├──→ 写入执行线程
├──→ 查询执行线程
├──→ 提交线程
└──→ 同步线程
设计原则:
- I/O 与 CPU 分离
- 任务队列解耦
- 避免单线程瓶颈
- 优先级保证关键路径
2. 网络 I/O 线程
原理:
① 启动时根据 numOfRpcThreads 创建
② 每个线程一个 epoll 实例
③ 连接均衡分配到各线程
④ 异步 read/write
⑤ 数据完整后投递任务
线程职责:
- accept 连接
- 接收 RPC 包
- 解码包头
- 解压数据
- 投递到任务队列
- 异步回发响应
配置:
numOfRpcThreads = CPU 核数 × 0.5 ~ 1
典型:8~16
设计要点:
- 不做重计算
- 不阻塞磁盘 IO
- 快进快出
3. 查询执行线程
原理:
① numOfTaskQueueThreads 控制
② 工作线程池
③ 从任务队列拉取查询任务
④ 执行算子(扫描/过滤/聚合)
⑤ 结果发回客户端
算子级并发:
- 单查询拆为多 Task
- 不同 VGroup 并行
- 同 VGroup 内可分块并行
调度策略:
- 时间片轮转
- 优先级(短查询优先)
- 防止饥饿
QNode(独立查询节点):
- queryPolicy=2/3 时启用
- 大查询从 VNode 卸载到 QNode
- VNode 专注写入与小查询
4. 提交(Commit)线程
原理:
① 内存表达到阈值
② 切换内存表
③ Commit 线程异步处理:
a. 数据排序
b. 列存编码 + 压缩
c. 写入数据块文件
d. 更新索引
e. 清理 WAL
线程池:
numOfCommitThreads 控制
典型:4~8
设计要点:
- 不阻塞写入主路径
- 多 VGroup 并行
- I/O 调度避免拥塞
背压:
- Commit 跟不上 → 内存表堆积
- 触发写入限流
- 保护系统稳定
5. 同步(Sync)线程
RAFT 同步线程:
① 内部线程组
② Leader 复制日志到 Follower
③ Follower 接收、写盘、确认
④ Leader 收到 majority 确认 → 提交
线程类型:
- 发送线程:发送 AppendEntries
- 接收线程:处理回复
- 应用线程:将已提交日志应用到状态机
- 心跳线程:维持 Leader 角色
设计要点:
- 与业务线程隔离
- 高优先级
- 网络异常处理
- 选举超时控制
6. 流计算线程
Stream 执行:
① 流任务调度器
② Source 线程:订阅源数据
③ Computing 线程:窗口计算
④ Sink 线程:写入目标表
与查询共享或独立?
- 默认共享查询线程池
- 大量流可独立线程池
- 防止流计算影响查询
检查点线程:
- 定期触发 CheckPoint
- 持久化流状态
7. 任务队列
队列设计:
① 多级队列:
- 高优先级(管理/心跳)
- 普通优先级(查询/写入)
- 后台优先级(合并/清理)
② 按 VGroup 分区:
- 每 VGroup 独立队列
- 单 VGroup 串行
- 多 VGroup 并行
③ 限流:
- 队列长度上限
- 满则返回繁忙
调度算法:
- Round Robin
- 优先级 + 公平
- 防饥饿
典型场景:
- 一个慢查询不影响其他
- 写入优先级 < 读
- 心跳永不阻塞
8. 性能调优
调优原则:
① 线程数 ≤ CPU 核数 × 2
- 避免上下文切换开销
- I/O 类可适当多
② numOfRpcThreads:
- 高并发场景:核数
- 一般:核数 / 2
③ numOfTaskQueueThreads:
- 查询密集:核数 × 1.5
- 写入密集:核数
④ numOfCommitThreads:
- 多盘 I/O:4~8
- 单盘:2~4
监控指标:
- 队列长度
- 线程繁忙率
- 上下文切换
- CPU 利用率
瓶颈识别:
- RPC 队列堆积 → 加 RPC 线程
- Task 队列堆积 → 加 Task 线程或拆 VGroup
- Commit 慢 → 加 Commit 线程或 SSD
代码示例
配置线程参数
cfg
# /etc/taos/taos.cfg
# 网络
numOfRpcSessions 30000
numOfRpcThreads 16 # 16 核机器,全用
# 查询
numOfTaskQueueThreads 16
queryPolicy 2 # 用 qnode
# 写入
numOfCommitThreads 8
# 流计算
streamMaxThreads 4
监控线程使用
sql
-- 系统资源(看 CPU 利用率反映线程使用)
SELECT endpoint, cpu_usage
FROM log.taosd_dnodes_info
WHERE ts > NOW - 5m;
-- 查询并发
SELECT COUNT(*) AS active_queries
FROM performance_schema.perf_queries;
-- 慢查询(占用线程时间)
SELECT user, exec_usec/1000 AS ms, sql
FROM performance_schema.perf_queries
ORDER BY exec_usec DESC LIMIT 10;
调优案例
案例:写入吞吐不达预期
诊断:
iostat -x 1 # 磁盘 OK
top # CPU 利用率 70%
taos -s "SELECT * FROM log.taosd_dnodes_info"
# 看 commit 是否堆积
发现:commit 单线程
措施:
ALTER ALL DNODES 'numOfCommitThreads' '8';
结果:吞吐提升 2x
案例:查询请求 timeout
诊断:
- 看 active_queries 是否爆满
- 看慢查询列表
发现:大查询阻塞队列
措施:
- queryPolicy=2 用 qnode
- 大查询用专用账号
结果:小查询不再受影响
性能考量
线程开销
| 项 | 开销 |
|---|---|
| 单线程内存栈 | ~ 1 MB |
| 上下文切换 | ~ 微秒级 |
| 锁竞争 | 视并发 |
线程数推荐
| 角色 | 数量公式 |
|---|---|
| RPC | 核数 × 1 |
| Task | 核数 × 1~1.5 |
| Commit | 4~8 |
| Stream | 视流数量 |
FAQ
Q1: 线程越多越好吗?
不是。超过 CPU 核数过多反而损耗(切换开销)。
Q2: 为什么 CPU 没满写入还慢?
可能:
- I/O 瓶颈(磁盘)
- 锁竞争
- 网络瓶颈
- 客户端不并发
Q3: 怎么看是否需要 QNode?
- 大查询阻塞小查询 → 用 QNode
- 查询和写入互相影响 → 用 QNode
Q4: 流计算占用太多 CPU?
- 限制流数量
- 减少 trigger 频率
- 增加节点
Q5: 单查询能用多核吗?
可以。算子级并行(不同 VGroup 并行扫描)。
参考
系统构架篇
- 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 分布式查询执行》
- 11-《TDengine EXPLAIN 与查询优化》
数据写入
- 01-《TDengine SQL INSERT》
- 02-《TDengine 无模式写入》
- 03-《TDengine STMT 写入》
- 04-《TDengine 写入内部流程》
- 05-《TDengine 数据更新删除》
数据订阅
- 01-《TDengine 数据订阅》
- 02-《TDengine 订阅 vs Kafka》
- 03-《TDengine TMQ 消费流程》
- 04-《TDengine 内部机制》
- 05-《TDengine TMQ 最佳实践》
预聚合
索引
SQL 语句
- 01-《TDengine DDL》
- 02-《TDengine DML SELECT》
- 03-《TDengine DML 函数完整参考》
- 04-《TDengine JOIN 完整语法》
- 05-《TDengine 窗口完整语法》
- 06-《TDengine 操作符与表达式》
- 07-《TDengine 系统表》
- 08-《TDengine SQL 与标准 SQL 差异》
客户端与连接器
- 01-《TDengine 的连接方式》
- 02-《TDengine C/C++ 连接器》
- 03-《TDengine java 连接器》
- 04-《TDengine Python 连接器》
- 05-《TDengine Go 与 Rust 连接器》
- 06-《TDengine Node.js 与 C# 连接器》
运维
- 01-《TDengine 部署指南》
- 02-《TDengine 配置详解》
- 03-《TDengine 监控系统》
- 04-《TDengine 备份与恢复》
- 05-《TDengine 版本升级》
- 06-《TDengine 加密使用指南》
安全
生态
- 01-《TDengine taosAdapter》
- 02-《TDengine taosX 与 Explorer》
- 03-《TDengine Grafana 集成》
- 04-《TDengine 第三方工具》
应用案例
- 01-《TDengine IoT 设备监控》
- 02-《TDengine 工业大数据与智能制造》
- 03-《TDengine 车联网与新能源汽车》
- 04-《TDengine 能源与电力监控》
- 05-《TDengine IT 运维与可观测性》
产品对比
内部机制
关于 TDengine
TDengine 专为物联网IoT平台、工业大数据平台设计。其中,TDengine TSDB 是一款高性能、分布式的时序数据库(Time Series Database),同时它还带有内建的缓存、流式计算、数据订阅等系统功能;TDengine IDMP 是一款AI原生工业数据管理平台,它通过树状层次结构建立数据目录,对数据进行标准化、情景化,并通过 AI 提供实时分析、可视化、事件管理与报警等功能。
