核心目标:建立 TDengine 性能心智模型,能定位写入/查询瓶颈,并用建模与配置手段系统化优化。
前置知识:Part 6(写入)、Part 4(查询)、Part 9(集群);会用 taosBenchmark。
验证环境:TDengine 3.4.x(3.4.1.6);taosBenchmark;固定基准模板(见第 4 节)。
0. 本篇问题场景
数据量上来后,同样的代码"变慢"了:
- 采集端写入吞吐从 5 万行/s 掉到 8 千行/s,重启也没用;
- 报表查询超时,明明数据量只翻了一倍;
- 一台机器 CPU 打满,但不知道该砍哪个配置;
- 面试/评审被问"你凭什么说这个方案快",拿不出可复测的数据;
- 大屏"最新值"秒回,但历史曲线越来越慢。
性能问题最忌讳"拍脑袋改配置"。本篇建立一套可复测的方法:
- 性能模型:写入/查询的路径开销各在哪,瓶颈长什么样;
- 基准方法:固定模板测出基线,改动一次只测一个变量;
- 调优决策树:从现象(慢/满/卡)到根因到对策;
- 常用配置:哪些参数值得动、动了有什么代价。
1. 心智模型:写入与查询的瓶颈分层
1.1 写入路径开销分解(回顾 Part 6,量化视角)
客户端组包(stmt 绑定) → 网络 RTT → taosd 解析/路由
→ vnode:WAL(fsync 策略)→ 内存表 → 异步落盘合并
按影响排序,写入瓶颈通常来自:
- 批量太小(RTT 与解析次数)------最常见,改动收益最大;
- 乱序数据(排序/重排路径)------采集端可治理;
- WAL 配置 (
wal_level/fsync)------安全换吞吐的旋钮; - 副本数(跨节点同步)------安全换吞吐(Part 9);
- vgroup 数量与热点------单 vgroup 打满(如某子表数据量巨大)。
1.2 查询路径开销分解(回顾 Part 4)
qnode 计划 → vnode 并行扫描(时间裁剪 → 列裁剪 → 预过滤)→ 聚合 → 回传
查询瓶颈通常来自:
- 无时间范围(全量扫描)------接口层最常犯;
- 窗口粒度/扫描量 (
INTERVAL越小、范围越大,读得越多); - 标签基数爆炸/过滤失效(Part 2 的建模问题);
- FILL 与插值代价 (
LINEAR需要排序两端点); - 结果集过大(客户端缓冲内存)。
1.3 性能不是单点,是链路
"变慢"先回答"哪一段变慢":是写入慢 、查询慢 还是资源不够。用 Part 10 的监控指标(写入延迟/查询延迟/磁盘/CPU/连接数)把现象钉在链路的某一段,再动手。
2. 最小可运行示例:一次规范的基准
2.1 固定基准模板(项目 docs/bench/ 固化)
text
环境:CPU 型号/核数、内存、磁盘类型、TDengine 版本、网络拓扑(本机/跨机)
数据:设备数、指标数、时间戳精度、行数、乱序比例
变量:批量大小(100/1000/10000)、线程数(1/4/8)、副本数、wal_level
测量:总耗时、行/s、P99 单批延迟、CPU/内存峰值
复现:命令完整记录(./build/part6_stmt_write 或 taosBenchmark 配置)
2.2 用 taosBenchmark 交叉验证
bash
# 写场景配置(设备数/表数/批量/线程/乱序比例)
taosBenchmark -f bench_write.json
# 查询场景
taosBenchmark -f bench_query.json
原则 :自己的程序(part6_stmt_write)与官方工具各测一遍,两个口径对上才算数;所有数字注明环境,禁止"无条件快 N 倍"。
2.3 单变量实验纪律
text
基线 → 改一个变量(如批量 1000→5000)→ 复测 → 记录差异 → 决定保留/回退
一次只改一个变量,否则结论无法归因。每次实验的记录进项目 docs/bench/,这是 Part 12 排障与"评审拿数据"的底气。
3. 机制拆解:关键参数与代价
3.1 写入侧参数
| 参数 | 作用 | 代价/注意 |
|---|---|---|
| 批量大小 | 减少 RTT/解析 | 有甜点区(数百~数千行/批) |
buffer |
每 vnode 内存表上限 | 越大落盘越少但内存占用高 |
wal_level/fsync |
WAL 落盘策略 | 0 最快但崩溃丢最近数据 |
replicas |
副本数 | 越多写越慢、磁盘×N |
vgroups |
分片数 | 决定写入并行与订阅并行(Part 7) |
| 乱序治理 | 采集端排序 | 乱序写入吞吐骤降 |
3.2 查询侧参数与习惯
| 项 | 作用 | 注意 |
|---|---|---|
| 时间范围 | 裁剪扫描 | 接口强制参数 |
| 列裁剪 | 只选需要的列 | 少扫列即少 IO |
| 窗口粒度 | 结果精度 | 粒度越细扫描越多 |
queryTimeout |
查询超时 | 超长查询提前失败比拖死好 |
| 标签过滤 | 元数据裁剪 | 建模正确性前提(Part 2) |
3.3 Read Cache 与流计算的关系
- 最新值 →
LAST_ROW+cachemodel='both'(内存缓存); - 历史聚合 → 流计算预聚合表(Part 8);
- 二者配合后,大屏秒回、报表快查,原始表只被低频扫描------这是"查询快"的架构答案,不是单点参数。
4. ems-lab 工程实战:调优案例集
4.1 案例 A:采集端批量太小
现象:写入吞吐低、CPU 高。定位:监控看解析占比高;代码审查发现逐条 exec。
对策:换 stmt_writer 批量(Part 6),吞吐提升一个数量级(实测留档)。
4.2 案例 B:乱序风暴
现象:某时段写入吞吐骤降。定位:监控确认乱序比例;日志/采集端发现网络抖动重发。
对策:采集端按时间戳缓冲排序 + 迟到数据单独处理(Part 6 的架构)。
4.3 案例 C:无时间范围查询
现象:报表接口超时。定位:慢查询日志 + EXPLAIN 显示全量扫描。
对策:接口强制时间范围参数;历史全量分析用流计算预聚合(Part 8)。
4.4 案例 D:标签基数爆炸
现象:SHOW 变慢、过滤查询不裁剪。定位:检查标签设计(Part 2 失败实验)。
对策:高基数标识移出标签(改子表名),标签只留低基数分组维度。
每个案例按模板记录:现象 → 定位(指标/EXPLAIN/日志)→ 对策 → 复测数据。
5. 失败实验与根因
5.1 只调参数不测量
实验:buffer/wal_level 凭感觉改一通。
现象:无法归因、可能更差。根因:违反单变量实验纪律。教训:先基线再改动,一次一个变量,留档。
5.2 把"自己程序快"当结论
实验:只用 part6_stmt_write 自测就宣称吞吐。
现象:与官方 taosBenchmark 口径对不上。根因:程序差异(并发/批量/数据形态)导致结论不可迁移。教训:双口径验证,注明环境。
5.3 副本数当性能参数
实验:写入慢就降 replicas。
现象:吞吐上去了,可用性降了。根因:副本是安全参数(Part 9)。教训:先定安全需求再定副本,性能优化从批量/乱序/WAL 入手。
5.4 缓存开满以为万能
实验:cachemodel='both' + 超大 cachesize。
现象:内存占用升高,历史查询没变快。根因:缓存只管最新值(LAST/LAST_ROW),不管历史扫描。教训:缓存解决"最新值秒回",历史快查靠预聚合与索引。
6. 版本与环境差异
| 维度 | 说明 |
|---|---|
| 参数默认值 | 3.4.x 与 3.3.6 LTS 的 buffer/WAL 默认值可能不同,以 SHOW/官方文档为准 |
| stmt2 | 3.3+ 新写入模式,极致吞吐场景可对比 stmt1(Part 6) |
| 流引擎 | 3.3.7+ 新流引擎资源模型与旧引擎不同(Part 8) |
| 硬件 | 时序库吃磁盘顺序 IO 与内存;SSD/内存配置差异直接体现在基准上 |
| Docker | 容器资源限制(CPU/内存/IO)会显著影响基准,标注清楚 |
发布前核对:性能数字只对"记录时的环境"负责;目标环境复测后再下结论。
7. 测试与验收
7.1 自动化验证
- 建立基准基线脚本(写入/查询各一组,输出 JSON 留档);
- CI/定时任务复测,与基线对比(如吞吐下降 > 20% 触发告警);
- 调优案例的"前/后"数据成对存档,可复现命令完整。
7.2 本篇验收清单
- 能画出写入/查询路径开销分解,并把任意"变慢"现象定位到链路某一段;
- 用固定模板完成写入基准(批量 × 线程矩阵)并 taosBenchmark 交叉验证;
- 完成至少 2 个调优案例(建议批量与乱序),前后数据留档;
- 能说清
buffer/wal_level/replicas/vgroups/cachemodel各自的代价; - 遵守"一次只改一个变量"纪律,所有结论带环境说明。
8. 常见误区
| 误区 | 事实 |
|---|---|
| "改配置就能快" | 先定位瓶颈在链路哪段,再动对应参数 |
| "参数越大越好" | buffer/cachesize 吃内存,批量有甜点区 |
| "自己测的快就是结论" | 双口径 + 环境说明 + 可复现命令 |
| "降副本提速" | 副本是安全参数,不是性能旋钮 |
| "缓存解决一切查询慢" | 缓存只管最新值;历史快查靠预聚合与裁剪 |
| "性能优化是最后一篇才做的事" | 建模(Part 2)、写入(Part 6)早已决定大部分性能 |
9. 本篇小结
性能调优是"测量驱动的工程",不是玄学:
- 模型:写入瓶颈在批量/乱序/WAL/副本,查询瓶颈在裁剪/粒度/标签设计;
- 方法:固定模板 → 基线 → 单变量实验 → 复测留档,taosBenchmark 交叉验证;
- 旋钮 :批量大小、
buffer、wal_level、vgroups、cachemodel、queryTimeout------每个都知道代价再用; - 架构:最新值走缓存、历史走预聚合、原始表低频扫描------快是设计出来的;
- 证据:所有结论带环境与命令,可复测可追溯。
现在你已经有了完整的单机+集群的知识与工具。最后一篇把它们串起来:端到端实战、系统化排障与 2.x 迁移。