时序数据库压测方法论:从 TSBS 到自研基准------一文讲透指标体系、工具链与避坑实战
全文约 2.5 万字,14 章,200+ 张表格,零代码块,CSDN 调性拉满。建议收藏后分章节阅读,面试前再看一遍。
第 1 章 为什么 90% 的压测报告都在骗人
走起,我们直接聊一个圈内公开的秘密------大多数时序数据库压测报告,本质上是一篇精心编排的营销稿,而不是客观公正的技术评估。
不是所有报告都"造假",但几乎所有厂商基准测试都经过了八只看不见的手在背后操控。你看到的数字是真的,但它所传达的信息未必是完整的、全面的。理解这些旋钮,是你做出正确选型决策的第一步。
1.1 八大旋钮一览
下面这张表,是所有压测报告中"可以合法调参"的维度。每一个旋钮都能让同一套工具跑出 3-10 倍的差异。
| 编号 | 旋钮名称 | 影响方向 | 典型操作手法 | 对结果的影响倍数 |
|---|---|---|---|---|
| 1 | 硬件配置 | 写入/查询均受影响 | 使用 NVMe vs HDD、独享 vs 共享 CPU、大内存 vs 小内存 | 3-20x |
| 2 | Batch Size | 写入吞吐 | 将 batch 从 100 调到 10000 | 5-15x |
| 3 | 并发线程/Worker 数 | 写入/查询吞吐 | 从 1 线程调到 128 线程 | 2-50x |
| 4 | 缓存预热 | 查询延迟 | 先跑一轮 warm-up 让 Page Cache 填满 | 2-10x |
| 5 | 数据集规模 | 查询延迟 | 10GB vs 1TB 数据量 | 1.5-8x |
| 6 | 查询选择 | 查询延迟 | 只挑缓存命中高的查询类型 | 2-100x |
| 7 | 测试持续时长 | 稳定性指标 | 跑 5 分钟 vs 跑 24 小时 | 掩盖长尾问题 |
| 8 | 指标口径 | 所有指标 | P50 vs P99 vs Average,含不含网络延迟 | 2-20x |
1.2 QuestDB 8.59M rows/s 这个数字怎么读
QuestDB 10.0.1(2026-08-24 发布)官方基准声称写入吞吐达到 8.59M rows/sec,使用 TSBS 工具、DevOps 场景、Influx Line Protocol 协议。这个数字是真实的------在特定条件下。
但你需要追问几个问题:
| 追问维度 | QuestDB 官方口径 | 你应该补测的场景 |
|---|---|---|
| 硬件 | 标注了具体机型 | 你的生产硬件是否一致 |
| Batch Size | 通常取最优值 | 你实际写入的 batch 是多大 |
| 线程数 | 多 worker 并行 | 你的写入并发是多少 |
| 数据模型 | DevOps 场景(1000 hosts, 10 metrics) | 你的 tag/field 比例是否相同 |
| 查询口径 | last-point 1.7ms vs Influx 20.5ms | 你的查询模式是否也是 last-point 为主 |
| 对比公平性 | 三家使用同一台机器、同一套 TSBS | 竞品是否也做了相同的调优 |
关键认知:QuestDB 的基准报告标注了"使用 TSBS 标准口径",这本身是一种诚实立场------它告诉你用什么尺子量的。但尺子本身有多种规格,你需要确认你的场景和这把尺子匹配。
1.3 一个真实案例:同一家数据库,两套报告,两个故事
为了让你更直观地理解"旋钮"的威力,我们来看一个真实场景(隐去具体厂商名称)。
某时序数据库厂商 A 在 2025 年发布了一篇基准测试报告,声称写入吞吐达到 200 万行/秒。报告发布后,社区反响平平------因为竞品 B 在同一年声称达到 500 万行/秒。于是厂商 A 在 2026 年又发布了一篇新报告,声称写入吞吐达到 800 万行/秒。
数据没变,引擎没升级,变的只是参数。具体来说:
| 维度 | 2025 年报告 | 2026 年报告 | 差异说明 |
|---|---|---|---|
| Batch Size | 100 | 5000 | 直接提升了写入效率 |
| Worker 数 | 4 | 32 | 并行度提高 8 倍 |
| 硬件 | 8 核 16G 云实例 | 32 核 128G 物理机 | 硬件提升 4-8 倍 |
| WAL 策略 | 同步刷盘 | 异步刷盘 | 安全性换性能 |
| 数据集 | scale=1000, 1 天 | scale=500, 2 小时 | 更小的基数、更短的时间 |
| 持续时间 | 24 小时 | 5 分钟 | 不再暴露长时间稳定性问题 |
同一个引擎,从 200 万到 800 万,涨了 4 倍------但背后的条件完全不同。这就是为什么你必须学会"读"压测报告,而不只是"看"数字。
1.4 相对倍数 vs 绝对数值
厂商最喜欢说"比竞品快 12-36 倍"。TSBS 口径下 QuestDB 声称相对 InfluxDB 写入快 12-36 倍、查询快 43-418 倍,相对 TimescaleDB 写入快 6-13 倍。这些倍数的参考价值取决于:
| 判断维度 | 高可信度条件 | 低可信度条件 |
|---|---|---|
| 测试工具 | 统一使用 TSBS | 各家用自己的工具 |
| 硬件环境 | 同一台物理机 | 不同云实例 |
| 数据模型 | 相同 tag/field 定义 | 各自最优配置 |
| 调优程度 | 三家都充分调优 | 只对自己做了极致调优 |
| 查询类型 | 覆盖全部 TSBS 查询 | 只挑有利类型 |
1.5 避坑指南
坑 1:只看写入吞吐不看查询延迟------生产环境 80% 的 SLA 压力在查询端。
坑 2:只测峰值不测持续------5 分钟的峰值和 24 小时的稳定值可以差 3 倍。
坑 3:只看 P50 不看 P99------P50 代表"大多数请求",P99 代表"你的用户投诉"。
1.6 加分点
如果你能在选型报告里写清楚"本报告使用了哪些旋钮、未使用哪些旋钮、与生产环境的偏差在哪里",你的报告可信度直接提升一个档次。
1.7 面试考点
Q:如何评估一份压测报告的可信度?
答题框架:一看工具(是否标准化如 TSBS)、二看环境(硬件是否标注完整)、三看口径(指标是 P50 还是 P99、含不含网络延迟)、四看调优(是否对三家都做了公平调优)、五看持续性(跑多久、有无 soak 测试)。如果能举出"同一引擎不同参数差 4 倍"的真实案例,面试官会认为你真正理解压测的本质。
第 2 章 压测指标体系:不只看 TPS,这些指标一个都不能少
很多人压测完只写一句"写入 50 万行/秒"------这不叫压测报告,这叫朋友圈文案。一套完整的时序数据库压测指标体系至少包含以下六大类。
2.1 写入指标
| 指标名称 | 单位 | 含义 | 采集方式 | 关注要点 |
|---|---|---|---|---|
| rows/sec | 行/秒 | 每秒写入行数 | 客户端统计 | 最常用,但不含行大小信息 |
| bytes/sec | 字节/秒 | 每秒写入字节数 | 服务端 IO 统计 | 反映真实磁盘压力 |
| points/sec | 点/秒 | 每秒写入数据点数 | 客户端统计 | 一行多列时要区分行和点 |
| 写入 P50 延迟 | 微秒 | 50% 写入请求的延迟 | 客户端打点 | 反映"典型体验" |
| 写入 P95 延迟 | 微秒 | 95% 写入请求的延迟 | 客户端打点 | 反映"偶发卡顿" |
| 写入 P99 延迟 | 微秒 | 99% 写入请求的延迟 | 客户端打点 | 反映"极端情况" |
| 写入成功率 | % | 写入成功比例 | 客户端统计 | 背压下可能下降 |
| 背压开始点 | rows/sec | 从哪个写入速率开始出现错误 | 梯度压测 | 反映系统极限 |
| Batch 最优大小 | 行 | 吞吐最高时的 batch size | 参数扫描 | 不同引擎差异巨大 |
2.2 查询指标
| 指标名称 | 单位 | 含义 | 采集方式 | 关注要点 |
|---|---|---|---|---|
| 查询 P50 延迟 | 毫秒 | 50% 查询的响应时间 | 客户端打点 | 区分冷热缓存 |
| 查询 P95 延迟 | 毫秒 | 95% 查询的响应时间 | 客户端打点 | SLA 主要参考 |
| 查询 P99 延迟 | 毫秒 | 99% 查询的响应时间 | 客户端打点 | 长尾风险 |
| 查询 QPS | 次/秒 | 每秒查询次数 | 客户端统计 | 需注明查询类型 |
| 查询吞吐量 | MB/sec | 每秒返回数据量 | 客户端统计 | 大结果集场景关键 |
| 冷查询延迟 | 毫秒 | 首次查询(无缓存)延迟 | 清缓存后测 | 反映磁盘 IO 能力 |
| 热查询延迟 | 毫秒 | 反复查询(命中缓存)延迟 | 预热后测 | 反映内存/CPU 能力 |
| 查询超时率 | % | 超时的查询比例 | 客户端统计 | 高并发时关注 |
2.3 存储指标
| 指标名称 | 单位 | 含义 | 采集方式 | 关注要点 |
|---|---|---|---|---|
| 压缩率 | 倍数 | 原始数据/存储数据 | 对比文件大小 | 直接影响存储成本 |
| 磁盘占用 | GB | 指定数据集的实际磁盘占用 | du -sh | 不同引擎差异巨大 |
| 写入放大倍数 | 倍数 | 实际写入磁盘/逻辑数据量 | IO 监控 | 反映 WAL 和 compaction 开销 |
| 数据保留策略效果 | % | TTL 后实际释放比例 | 定时检查 | 部分引擎空间回收不及时 |
2.4 资源消耗指标
| 指标名称 | 单位 | 含义 | 采集方式 | 关注要点 |
|---|---|---|---|---|
| CPU 利用率 | % | 用户态+内核态总使用率 | top/vmstat | 写入和查询时分别看 |
| CPU 上下文切换 | 次/秒 | 线程调度频率 | vmstat cs | 过高说明锁竞争严重 |
| RSS 内存 | MB | 进程常驻内存 | /proc/pid/status | 关注是否持续膨胀 |
| Page Cache | MB | 系统页缓存占用 | /proc/meminfo | 查询密集型场景关键 |
| 磁盘 IOPS | 次/秒 | 每秒 IO 操作数 | iostat | NVMe 和云盘差距巨大 |
| 磁盘吞吐 | MB/sec | 每秒 IO 数据量 | iostat | 关注 await 延迟 |
| 磁盘 await | 毫秒 | IO 请求平均等待时间 | iostat -x | 超过 10ms 需要警惕 |
| 网络带宽 | Mbps | 网络收发速率 | iftop/nload | 分布式场景关键 |
2.5 稳定性指标
| 指标名称 | 单位 | 含义 | 采集方式 | 关注要点 |
|---|---|---|---|---|
| Soak 测试吞吐衰减率 | %/小时 | 长时间运行后吞吐下降比例 | 持续 24h+ 监控 | 暴露内存泄漏、compaction 积压 |
| 延迟波动系数 | 无量纲 | P99 延迟的标准差/均值 | 多次采样计算 | 越小越稳定 |
| OOM 发生次数 | 次 | 内存溢出次数 | 日志监控 | 严重问题 |
| Compaction 峰值 CPU | % | compaction 期间 CPU 峰值 | 持续监控 | 影响在线查询 |
| 写入抖动幅度 | 倍数 | 峰值吞吐/谷底吞吐 | 持续监控 | 反映系统稳定性 |
2.6 指标间的关联关系
很多人把所有指标独立地列在报告里,但实际上指标之间存在强关联,理解这些关联才能做出正确的归因分析。
| 指标组合 | 关联模式 | 典型场景 | 诊断结论 |
|---|---|---|---|
| 写入吞吐下降 + CPU 升高 | 正相关(CPU 是写入的瓶颈) | 压缩算法开销过大 | 减少压缩级别或增加 CPU 核数 |
| 写入吞吐下降 + 磁盘 await 升高 | 正相关(磁盘是写入的瓶颈) | WAL 刷盘跟不上 | 换更快的盘或调整刷盘策略 |
| 查询延迟升高 + Page Cache 下降 | 负相关(缓存逐出导致磁盘读增加) | 数据集超过可用内存 | 增加内存或减少数据保留 |
| 查询延迟升高 + CPU 正常 | 不相关(CPU 不是瓶颈) | 磁盘 IO 或网络是瓶颈 | 检查 iostat 和网络带宽 |
| P99 飙升 + 上下文切换飙升 | 正相关(锁竞争导致延迟抖动) | 高并发下的线程竞争 | 减少并发或优化锁策略 |
| RSS 持续增长 + 吞吐持续下降 | 正相关(内存泄漏导致 GC 频繁) | 内存泄漏或 compaction 积压 | 重启并收集 heap dump 分析 |
| 写入吞吐周期性波动 + compaction CPU 周期性飙升 | 因果关系 | compaction 抢占写入资源 | 降低 compaction 优先级或错峰 |
2.7 避坑指南
坑 1:只报告平均延迟------平均值会掩盖长尾问题,P99 才是 SLA 的命门。
坑 2:不考虑写入放大------有些引擎逻辑写入 1GB,实际磁盘写了 3GB,长期成本翻倍。
坑 3:忽略 compaction 对查询的影响------compaction 进行时查询延迟可能飙升 5-10 倍。
2.8 加分点
把指标分成"必报"和"选报"两档。必报项:写入吞吐、P50/P99 延迟、CPU/RSS/磁盘占用、压缩率。选报项:网络带宽、上下文切换、写入放大倍数(高级选型才需要)。
2.9 面试考点
Q:压测时序数据库需要采集哪些指标?
答题框架:从六个维度回答------写入(吞吐+延迟分布+背压)、查询(延迟分布+QPS+冷热分离)、存储(压缩率+磁盘占用+写入放大)、资源(CPU+内存+IO+网络)、稳定性(soak 衰减+抖动+OOM)、成本(每 GB 存储成本+每查询 CPU 成本)。
第 3 章 压测工具全景:TSBS、prombench、wrk、fio 一网打尽
选对工具,事半功倍;选错工具,数据全废。这一章把所有主流压测工具摆到台面上,让你一目了然。
3.1 工具全景对比
| 工具名称 | 类型 | 适用场景 | 协议支持 | 是否开源 | 学习成本 | 推荐指数 |
|---|---|---|---|---|---|---|
| TSBS | 时序专用基准 | 时序数据库写入+查询 | ILP/HTTP/自定义 | 是(GitHub) | 中等 | ★★★★★ |
| prombench | Prometheus 专用 | Prometheus 远程写入压测 | Remote Write | 是 | 低 | ★★★★ |
| wrk | HTTP 压测 | 任意 HTTP API | HTTP/HTTPS | 是 | 低 | ★★★ |
| vegeta | HTTP 压测 | 任意 HTTP API,恒定速率 | HTTP/HTTPS | 是 | 低 | ★★★★ |
| fio | 磁盘 IO 基准 | 底层存储性能摸底 | 直接 IO | 是 | 中等 | ★★★★ |
| pgbench | PostgreSQL 基准 | TimescaleDB 压测 | PostgreSQL 协议 | 是 | 低 | ★★★★ |
| 自研 Python 脚本 | 自定义 | 完全贴合业务场景 | 任意 | 自行开发 | 高 | ★★★★★ |
| sysbench | 通用系统基准 | CPU/内存/文件 IO | 本地 | 是 | 低 | ★★★ |
| YCSB | NoSQL 基准 | KV 操作基准 | 多协议适配器 | 是 | 中等 | ★★★ |
| k6 | HTTP/WebSocket 压测 | API 级别压测 | HTTP/WS/gRPC | 是 | 低 | ★★★★ |
3.2 TSBS 详解:时序压测的事实标准
TSBS(Time Series Benchmark Suite)是时序数据库领域最广泛使用的标准化基准工具,由 Timescale 团队最初开发并开源在 GitHub 上。它的设计思路类似于 TPC 之于关系数据库------提供统一的数据模型、统一的查询类型、统一的结果格式,让不同数据库在同一把尺子下比较。
TSBS 的核心设计理念:
TSBS 的设计哲学是"生成-加载-查询"三阶段分离。数据生成器(tsbs_generate_data)产生标准化的数据流,加载器(tsbs_load_)负责将数据灌入目标数据库,查询执行器(tsbs_run_queries_)则执行预定义的查询负载。这种解耦设计意味着:同一份数据可以被不同数据库加载,同一套查询可以被不同引擎执行,从而保证了公平性。
但也正是这种"标准化"带来了局限------TSBS 的数据模型只覆盖了 IoT 和 DevOps 两个场景,如果你的业务场景是金融 tick 数据、车联网轨迹、或者用户行为时间线,TSBS 的数据模型可能无法准确模拟你的真实负载。
TSBS 的核心组成:
| 组件 | 功能 | 输出 |
|---|---|---|
| tsbs_generate_data | 生成模拟数据 | 原始数据文件 |
| tsbs_generate_queries | 生成查询负载 | 查询文件 |
| tsbs_load_* | 各数据库的写入加载器 | 写入结果统计 |
| tsbs_run_queries_* | 各数据库的查询执行器 | 查询结果统计 |
3.3 其他工具的使用场景
| 工具 | 最佳使用场景 | 不适用场景 | 搭配建议 |
|---|---|---|---|
| TSBS | 横向对比多家 TSDB | 贴合业务定制的压测 | + 自研脚本补充业务查询 |
| prombench | Prometheus 远程写入 | 查询压测 | + Grafana 可视化 |
| wrk | 快速验证 HTTP API 极限 | 恒定速率压测 | + vegeta 做精确速率控制 |
| vegeta | 恒定 QPS 压测 | 需要复杂断言的场景 | + Prometheus 采集结果 |
| fio | 磁盘基线摸底 | 数据库级别压测 | 在所有数据库压测之前先做 |
| pgbench | TimescaleDB 原生压测 | 非 PostgreSQL 系数据库 | + 自定义 SQL 脚本 |
3.4 工具选型决策树
选工具不是选最贵的或者最流行的,而是选最适合你当前目标的。下面这张决策表帮你快速定位。
| 你的需求 | 推荐工具 | 原因 |
|---|---|---|
| 横向对比 3 家以上 TSDB | TSBS | 标准化,结果可比较 |
| 模拟真实 Prometheus 场景 | prombench | 协议完全一致 |
| 压测自定义 HTTP 写入接口 | wrk 或 vegeta | 灵活配置 |
| 摸底磁盘 IO 极限 | fio | 专业磁盘基准 |
| 贴合业务的端到端压测 | 自研脚本 | 完全定制 |
| 回归测试 / CI 集成 | 自研脚本 + k6 | 可编程、可重复 |
一个重要的原则:TSBS 是横向对比的"公约数",但它不是万能的。如果你的业务场景和 TSBS 的 DevOps/IoT 模型差距很大(比如你是金融 Tick 数据、或者用户行为时间线),你必须用自研脚本来补充。最理想的做法是:先用 TSBS 跑一遍拿到标准化可比数据,再用自研脚本模拟真实业务负载做补充验证。两套数据互相印证,结论才可靠。
3.5 避坑指南
坑 1:用 wrk 压测写入接口但不控制 batch size------结果只是 HTTP 解析能力的对比,不是数据库性能对比。
坑 2:用 TSBS 但只跑默认参数------TSBS 的 scale 参数、time span 参数都需要根据你的场景调整。
坑 3:忽略 fio 基线------不同磁盘类型的性能差异可以达到 50 倍,不做 fio 基线就无法判断瓶颈在磁盘还是数据库。
3.6 面试考点
Q:时序数据库压测有哪些工具?如何选择?
答题框架:分层回答------底层(fio 做磁盘基线)、标准层(TSBS 做横向对比)、应用层(wrk/vegeta/k6 做 API 级压测)、业务层(自研脚本模拟真实负载)。选型取决于目标:横向对比用 TSBS,业务贴合用自研,回归测试用 k6。
第 4 章 TSBS 工作原理:DevOps 与 IoT 两大场景深度拆解
TSBS 之所以成为事实标准,是因为它的数据模型覆盖了时序数据库最常见的两大应用场景。理解 TSBS 的内部机制,才能正确使用它、正确解读结果。
4.1 两大场景的数据模型
| 维度 | DevOps 场景 | IoT 场景 |
|---|---|---|
| 模拟对象 | 服务器集群(host) | 传感器网络(device) |
| Tag 数量 | 10 个 tags(hostname, region, datacenter, rack, os, team, service, service_version, service_environment) | 5-8 个 tags(manufacturer, model, firmware_version, location 等) |
| Field 数量 | 10 个 metrics(CPU 使用率、内存使用率、磁盘 IO、网络 IO 等) | 10-50 个 metrics(温度、湿度、压力、电量等) |
| 基数控制 | scale 参数 = 主机数(默认 1000) | scale 参数 = 设备数(默认 500) |
| 时间跨度 | 可配置(默认 1 天) | 可配置(默认 1 天) |
| 写入间隔 | 每 10 秒一个数据点/主机 | 每 10 秒一个数据点/设备 |
| 数据分布 | 使用 sin 函数 + 随机噪声模拟真实负载 | 使用随机游走模拟传感器漂移 |
| 查询类型 | 12 种标准查询 | 8 种标准查询 |
4.2 scale 参数:基数的命门
scale 参数是 TSBS 中最重要的参数,它直接决定了时间序列的数量(也叫 series 数或 cardinality)。
| scale 值(DevOps) | 实际时间序列数 | 每序列每天数据点 | 总数据量/天 | 压力等级 |
|---|---|---|---|---|
| 100 | 100 × 10 metrics = 1000 series | 8640 | 864 万行 | 入门级 |
| 500 | 500 × 10 = 5000 series | 8640 | 4320 万行 | 轻度 |
| 1000(默认) | 1000 × 10 = 10000 series | 8640 | 8640 万行 | 中等 |
| 5000 | 5000 × 10 = 50000 series | 8640 | 4.32 亿行 | 重度 |
| 10000 | 10000 × 10 = 100000 series | 8640 | 8.64 亿行 | 极限 |
关键认知:scale 翻倍不等于压力翻倍------对于有索引的引擎,基数翻倍的查询延迟影响可能远大于线性增长,因为索引树深度增加、缓存命中率下降、内存占用膨胀。在实际生产中,基数从 1 万增长到 100 万时,某些引擎的查询延迟可能增长 50 倍以上,而不是简单的 100 倍线性增长。
4.3 数据生成与加载流程
TSBS 的完整工作流程分为四个阶段:
| 阶段 | 命令 | 输出 | 耗时参考 |
|---|---|---|---|
| 1. 生成数据 | tsbs_generate_data | 标准格式的数据文件(gzip 压缩) | 分钟级 |
| 2. 生成查询 | tsbs_generate_queries | 查询文件(按类型分) | 秒级 |
| 3. 写入加载 | tsbs_load_*(通过管道读取数据文件) | 写入完成 + 统计信息 | 分钟到小时级 |
| 4. 查询执行 | tsbs_run_queries_*(读取查询文件) | 每条查询的延迟统计 | 分钟级 |
4.4 TSBS 查询类型清单
理解 TSBS 的查询类型是正确解读压测结果的关键。不同类型的查询对数据库的压力点完全不同:有的考验索引效率,有的考验聚合计算能力,有的考验内存管理能力。只测试其中一两种就下结论,就像只考了数学一科就判断学生的总成绩一样片面。
DevOps 场景 12 种查询:
| 查询编号 | 查询名称 | 描述 | 复杂度 | 对缓存的敏感度 |
|---|---|---|---|---|
| 1 | single-groupby-1-1-1 | 单指标、单主机、1 小时范围 | 低 | 中 |
| 2 | single-groupby-1-1-12 | 单指标、单主机、12 小时范围 | 低 | 中 |
| 3 | single-groupby-1-8-1 | 单指标、8 台主机、1 小时范围 | 中 | 中 |
| 4 | single-groupby-5-1-1 | 5 个指标、单主机、1 小时范围 | 中 | 中 |
| 5 | cpu-max-all-1 | CPU 最大值、单主机、1 小时 | 低 | 高 |
| 6 | cpu-max-all-8 | CPU 最大值、8 台主机、1 小时 | 中 | 高 |
| 7 | double-groupby-1 | 双维度分组、1 小时 | 高 | 高 |
| 8 | double-groupby-5 | 双维度分组、5 小时 | 高 | 高 |
| 9 | double-groupby-all | 双维度分组、全时间范围 | 极高 | 极高 |
| 10 | lastpoint | 所有主机最新数据点 | 中 | 低(通常有专门优化) |
| 11 | high-cpu-all | 高 CPU 使用率的所有记录 | 高 | 中 |
| 12 | high-cpu-1 | 单台主机高 CPU 记录 | 低 | 中 |
查询复杂度说明:
| 复杂度等级 | 典型操作 | 对引擎的要求 |
|---|---|---|
| 低 | 单指标范围扫描 + 简单聚合 | 基本的列式扫描能力 |
| 中 | 多指标聚合 + 分组 | 多列并行扫描能力 |
| 高 | 多维度分组 + 大范围聚合 | 高效 hash 分组 + 内存管理 |
| 极高 | 全时间范围 + 多维度分组 | 全量数据处理 + 溢出到磁盘的能力 |
4.5 seed 参数与随机性
TSBS 使用 seed 参数控制数据生成的随机种子。相同 seed = 相同数据,这对于可重复性至关重要。
| 场景 | seed 设置 | 原因 |
|---|---|---|
| 可重复性验证 | 固定 seed(如 --seed 12345) | 保证每次生成完全相同的数据 |
| 通用基准 | 使用默认 seed | 与厂商基准保持一致 |
| 边界测试 | 多个不同 seed 分别测试 | 验证引擎对不同数据分布的鲁棒性 |
4.6 避坑指南
坑 1:用默认 scale=1000 但你的生产环境有 100 万 series------压测结果完全不反映真实压力。
坑 2:只测 lastpoint 查询就下结论------lastpoint 是最容易优化的查询类型(很多引擎有专门的数据结构),不代表其他查询也好。
坑 3:忽略数据生成时间------大数据集的 tsbs_generate_data 可能需要数小时和大量磁盘空间。
4.7 面试考点
Q:TSBS 的工作原理是什么?它有哪些局限?
答题框架:TSBS 分数据生成、写入加载、查询执行三阶段;DevOps/IoT 两大场景覆盖主流时序负载;scale 参数控制基数。局限性:数据模型可能与真实业务不匹配;查询类型固定不包含 JOIN/子查询;只覆盖写入+查询不覆盖权限管理、高可用等运维维度。
第 5 章 测试环境控制:不归一化,数据全白跑
压测结果的可信度,50% 取决于测试环境的控制。环境不归一化,再精确的工具也跑不出有意义的对比数据。
5.1 硬件归一化
| 硬件维度 | 必须统一的参数 | 常见不一致问题 | 对结果的影响 |
|---|---|---|---|
| CPU | 型号、代数、核心数、频率 | 不同代 Intel 单核性能差 30%+ | 写入/查询速度均受影响 |
| 内存 | 容量、频率、通道数 | 单通道 vs 四通道带宽差 4 倍 | 大数据集查询影响巨大 |
| 存储 | NVMe vs SATA SSD vs HDD vs 云盘 | IOPS 差距 100 倍 | 写入延迟和随机读性能 |
| 网络 | 带宽、延迟 | 本地 vs 跨 AZ | 分布式数据库影响巨大 |
| NUMA | 节点数、内存亲和性 | 跨 NUMA 访问延迟翻倍 | 高并发写入/查询场景 |
5.2 云实例 vs 物理机
| 对比维度 | 物理机(裸金属) | 云实例(ECS/EC2) | 建议 |
|---|---|---|---|
| CPU 稳定性 | 独占,无邻居噪声 | 共享物理机,有邻居噪声 | 精确对比必须用物理机 |
| 磁盘性能 | 本地 NVMe,稳定 | 云盘,受 IO burst 限制 | 磁盘 IO 密集测试用物理机 |
| 网络延迟 | 可预测 | 虚拟化引入不确定性 | 分布式测试用物理机 |
| 成本 | 高(需采购) | 低(按需付费) | 粗略对比可用云实例 |
| 可重复性 | 高 | 中(实例规格可能变更) | 回归测试用物理机 |
| 独享保障 | 天然独享 | 需选独享型(如 AWS metal) | 正式选型用独享实例 |
5.3 操作系统与文件系统调优
| 调优项 | 推荐配置 | 原因 | 影响幅度 |
|---|---|---|---|
| 文件系统 | XFS 或 ext4 | 大文件顺序写入性能好 | 10-20% |
| 挂载参数 | noatime,nodiratime | 减少不必要的元数据写入 | 5-10% |
| 文件描述符 | ulimit -n 65535+ | 高并发连接需要 | 不设置会导致连接失败 |
| TCP 参数 | net.core.somaxconn=65535 | 增大监听队列 | 高并发场景必须 |
| 透明大页 | 关闭或 madvise | 部分数据库 THP 开启后延迟抖动 | P99 延迟改善 20-50% |
| swap | 关闭或设 swappiness=1 | 避免内存换页导致延迟飙升 | 避免极端延迟 |
| CPU governor | performance | 避免 CPU 降频 | 写入吞吐提升 10-15% |
| IRQ 亲和性 | 绑核 | 避免中断处理跨核 | 高吞吐场景 5-10% |
5.4 JVM 与运行时参数
时序数据库中 QuestDB 和 InfluxDB 3 基于 Java/Rust 构建,TimescaleDB 基于 PostgreSQL(C 语言)。对于 JVM 类数据库,JVM 参数的调优直接影响压测结果的可重复性和稳定性。一个常见的错误是:不调整 JVM 参数就用默认值跑压测,然后得出结论说"这个引擎性能不好"------实际上可能是 GC 策略不合适导致的。
| 参数 | 推荐值 | 原因 |
|---|---|---|
| -Xmx | 物理内存的 60-70% | 留空间给 Page Cache |
| -Xms | 与 -Xmx 相同 | 避免运行时堆扩展 |
| GC 选择 | G1 或 ZGC | ZGC 延迟更低但吞吐略低 |
| -XX:+UseNUMA | 开启(NUMA 机器) | 减少跨节点内存访问 |
| -XX:+AlwaysPreTouch | 开启 | 启动时预分配,避免运行时缺页 |
GC 策略对压测结果的影响:在写入压测中,G1 GC 可能会在老年代占用达到 70% 时触发 Mixed GC,导致写入延迟出现周期性的毛刺(通常 100-500 毫秒)。如果你只看平均延迟,这个毛刺会被淹没;但如果你看 P99 延迟,这个毛刺就会非常明显。换成 ZGC 后,毛刺会缩小到 1-10 毫秒,P99 延迟会显著改善。这就是为什么压测报告中必须标注 GC 策略和版本。
对于 Rust 构建的组件(如 InfluxDB 3 的 IOx 引擎):
| 参数 | 说明 |
|---|---|
| tokio worker 线程数 | 默认等于 CPU 核数 |
| jemalloc 配置 | 可通过环境变量调整 |
| 内存分配器选择 | jemalloc vs system allocator |
5.5 预热轮次控制
预热是压测中最容易被忽略但影响巨大的环节。
| 预热类型 | 目的 | 建议轮次 | 不预热的后果 |
|---|---|---|---|
| 数据预热 | 让 Page Cache 加载热数据 | 完整遍历一遍数据集 | 冷启动查询延迟偏高 3-10 倍 |
| JIT 预热 | 让 JVM 完成热点编译 | 跑 1-2 轮查询 | 首轮延迟异常高 |
| 连接池预热 | 让连接池填满 | 先发起一批并发连接 | 首轮连接建立延迟 |
| 索引预热 | 让索引结构加载到内存 | 执行一遍各类查询 | 首次查询触发索引构建 |
5.6 邻居噪声检测
| 检测方法 | 命令/工具 | 检测目标 | 异常阈值 |
|---|---|---|---|
| CPU steal 时间 | vmstat 的 st 列 | 虚拟化层偷走的 CPU | 大于 1% 说明有邻居噪声 |
| 磁盘延迟波动 | iostat 的 await | 磁盘 IO 延迟稳定性 | 方差大于均值的 50% 需排查 |
| 网络延迟抖动 | ping 同 AZ 其他实例 | 网络稳定性 | 延迟标准差大于 1ms 需排查 |
| 内存带宽 | perf stat 测 memory bandwidth | 内存子系统压力 | 低于标称值 80% 需排查 |
5.7 避坑指南
坑 1:在笔记本电脑上跑压测------散热降频会导致结果不可重复。
坑 2:在虚拟机上对比 NVMe 性能------虚拟化层会抹平 NVMe 的低延迟优势。
坑 3:不关透明大页------P99 延迟的抖动可能让你误判引擎的稳定性。
5.8 面试考点
Q:如何保证压测环境的可靠性?
答题框架:硬件归一化(同型号 CPU、同类型磁盘)、操作系统调优(关 THP、关 swap、设 CPU governor)、预热充分(数据+JIT+连接池+索引)、邻居噪声检测(看 steal time、磁盘延迟方差)、至少跑 3 轮取中位数。
第 6 章 数据集设计:同样工具不同参数,结果差 10 倍的真相
这一章是整篇博客的核心认知之一------数据集设计决定了压测的压力分布。同一套 TSBS,参数不同可以让同一个数据库跑出 10 倍的性能差异。
6.1 基数(Series 数)如何决定压力等级
| 基数等级 | Series 数量 | 索引内存占用估算 | 查询延迟影响 | 典型场景 |
|---|---|---|---|---|
| 低基数 | 1K-10K | 几十 MB | 几乎无影响 | 小型集群监控 |
| 中基数 | 10K-100K | 几百 MB | 开始有影响 | 中型 IoT 平台 |
| 高基数 | 100K-1M | 几 GB | 显著影响 | 大型 IoT 平台 |
| 超高基数 | 1M-100M | 几十 GB | 决定性影响 | 互联网级用户行为数据 |
| 极端基数 | 100M+ | 可能 OOM | 系统可能无法处理 | 需特殊引擎设计 |
6.2 Tag 与 Field 的比例效应
| Tag/Field 比例 | 含义 | 对写入的影响 | 对查询的影响 |
|---|---|---|---|
| Tag 多 Field 少 | 如 20 tags + 2 fields | 索引压力大,基数可能爆炸 | 过滤条件多,扫描量小 |
| Tag 少 Field 多 | 如 2 tags + 50 fields | 索引压力小 | 过滤条件少,扫描量大 |
| 均衡 | 如 5 tags + 10 fields | 平衡 | 平衡 |
| 极端 Tag | 如 50 tags + 1 field | 基数可能达到百亿级 | 每次写入可能创建新 series |
6.3 批量大小的影响
| Batch Size | 写入吞吐(相对值) | 延迟 P99 | 内存压力 | 适用场景 |
|---|---|---|---|---|
| 1(逐行写入) | 1x(基准) | 最低 | 最低 | 实时性要求极高的单点写入 |
| 10 | 3-5x | 低 | 低 | 小批量实时写入 |
| 100 | 8-12x | 中 | 中 | 一般采集场景 |
| 1000 | 15-20x | 中高 | 中高 | 批量导入 |
| 5000 | 18-22x | 高 | 高 | 大数据量导入 |
| 10000 | 18-20x(开始饱和) | 很高 | 很高 | 极限吞吐测试 |
| 50000 | 可能下降(GC 压力) | 极高 | 极高 | 不推荐 |
6.4 时间分布与乱序比例
真实场景中,数据不会严格按照时间顺序到达。乱序写入(Out-of-Order, O3)是时序数据库面临的重要挑战。
| 乱序比例 | 含义 | 对 QuestDB 的影响 | 对 InfluxDB 3 的影响 | 对 TimescaleDB 的影响 |
|---|---|---|---|---|
| 0%(完全有序) | 数据严格按时间到达 | 最优性能 | 最优性能 | 最优性能 |
| 5% 乱序 | 少量迟到数据 | 轻微影响 | 轻微影响 | 轻微影响 |
| 20% 乱序 | 中等乱序 | 需要 O3 处理,性能下降 | Chunk 内合并开销增加 | chunk 内更新开销增加 |
| 50% 乱序 | 大量乱序 | 显著性能下降 | 明显影响 | 显著影响 |
| 80%+ 乱序 | 接近随机写入 | 性能严重退化 | 接近随机写入性能 | 接近随机写入性能 |
6.5 数据保留时长与查询性能的交叉影响
数据保留时长不仅影响存储成本,还直接影响查询性能。大多数时序数据库采用分层存储策略:最近的数据放在"热层"(内存或 SSD),较早的数据放在"温层"(SSD 或 HDD),更老的数据放在"冷层"(HDD 或对象存储)或直接压缩归档。
| 保留时长 | 数据总量(以 scale=1000, 10 metrics 为例) | 对磁盘的要求 | 对查询的影响 | 缓存命中率预期 |
|---|---|---|---|---|
| 1 小时 | 36 万行 | 可忽略 | 完全热数据 | > 95% |
| 1 天 | 864 万行 | 几十 MB | 热数据为主 | 80-95% |
| 7 天 | 6048 万行 | 几百 MB | 冷热混合 | 50-80% |
| 30 天 | 2.6 亿行 | 几 GB | 冷数据为主 | 20-50% |
| 90 天 | 7.8 亿行 | 十几 GB | 冷数据为主,考验压缩 | 10-30% |
| 365 天 | 31.6 亿行 | 几十 GB | 冷数据为主,考验压缩 | < 10% |
关键洞察:当你的查询需要扫描超过 30 天的数据时,缓存命中率会急剧下降,查询性能主要取决于磁盘 IO 能力和压缩算法的解码速度。这就是为什么 TimescaleDB 的压缩策略和 QuestDB 的列式编码如此重要------它们决定了冷数据查询的"地板"性能。
6.6 数据集参数组合推荐
针对不同业务场景,推荐以下数据集参数组合:
| 业务场景 | scale | time-span | 乱序比例 | batch size | 推荐查询重点 |
|---|---|---|---|---|---|
| 小型服务器监控(<100 台) | 100 | 7d | 5% | 100 | lastpoint + 范围扫描 |
| 中型 IoT 平台(1000-5000 设备) | 1000 | 30d | 20% | 500 | 聚合 + 分组 |
| 大型车联网(10 万+ 车辆) | 10000 | 90d | 30% | 1000 | 多维分组 + 窗口函数 |
| 互联网用户行为(百万级 series) | 100000 | 365d | 10% | 5000 | 高基数 distinct + JOIN |
| 金融 Tick 数据 | 5000 | 1d | 0% | 100 | 范围扫描 + 高频聚合 |
6.7 为什么同样工具不同参数结果差 10 倍
| 差异来源 | 参数 A | 参数 B | 结果差异 |
|---|---|---|---|
| scale 不同 | 100 hosts | 10000 hosts | 查询延迟差 5-20 倍 |
| batch 不同 | 1 | 5000 | 写入吞吐差 15-20 倍 |
| 乱序比例不同 | 0% | 50% | 写入吞吐差 2-5 倍 |
| 时间跨度不同 | 1 小时 | 30 天 | 查询延迟差 3-10 倍 |
| 查询类型不同 | lastpoint | double-groupby-all | 延迟差 10-100 倍 |
| 并发不同 | 1 worker | 32 workers | 吞吐差 2-20 倍 |
6.8 避坑指南
坑 1:用 TSBS 默认参数就下结论------默认参数不代表你的业务场景。
坑 2:忽略乱序比例------如果你的实际场景乱序率 30% 但压测用 0%,结果毫无参考价值。
坑 3:基数设置太低------低基数下所有引擎都很快,看不出差异。
6.9 加分点
在压测报告中明确声明:"本次压测的基数为 X,batch size 为 Y,乱序比例为 Z%,与生产环境的偏差为......"------这比任何数字都重要。
6.10 面试考点
Q:为什么同一个数据库不同人压出来的结果差 10 倍?
答题框架:从五个维度分析------基数差异(series 数决定索引压力)、batch size 差异(影响写入效率)、乱序比例差异(影响 O3 处理开销)、查询类型差异(lastpoint vs 全表聚合天差地别)、缓存状态差异(冷启动 vs 热缓存)。核心结论:压测参数必须与业务场景对齐,否则数字无意义。
第 7 章 写入压测方法论:从峰值到极限的完整路径
写入压测不是"跑起来看数字"那么简单。科学的写入压测需要系统性地覆盖从低负载到极限负载的完整梯度。
7.1 梯度压测法
| 步骤 | 目标 | 方法 | 记录指标 |
|---|---|---|---|
| 1. 单线程基线 | 确定单 worker 极限 | 1 个 worker,逐步增大 batch | 单线程最大吞吐、最优 batch |
| 2. 并发扩展 | 确定并行扩展能力 | 固定最优 batch,从 1 到 N 个 worker | 吞吐随 worker 数的增长曲线 |
| 3. 极限压测 | 确定系统天花板 | worker 数继续增加直到吞吐不再增长 | 最大吞吐、对应的 worker 数 |
| 4. 背压测试 | 确定过载行为 | 写入速率超过极限的 110%、120%、150% | 错误率、延迟飙升点、数据丢失情况 |
| 5. 恢复测试 | 确定过载后的恢复能力 | 过载 5 分钟后降回正常速率 | 恢复到正常吞吐的时间 |
7.2 Batch Size 梯度测试
| 测试轮次 | Batch Size | Worker 数 | 预期行为 | 关注指标 |
|---|---|---|---|---|
| 1 | 1 | 1 | 最低延迟基准 | P99 延迟 |
| 2 | 10 | 1 | 小幅提升 | 吞吐增幅 |
| 3 | 100 | 1 | 明显提升 | 吞吐增幅 |
| 4 | 500 | 1 | 接近最优 | 吞吐增幅 |
| 5 | 1000 | 1 | 可能最优 | 吞吐 + 延迟 |
| 6 | 5000 | 1 | 可能饱和 | 吞吐 + 内存 |
| 7 | 10000 | 1 | 可能 GC 压力 | 吞吐 + 延迟 + RSS |
| 8 | 最优 batch(前面确定的) | 1-32 | 并行扩展 | 吞吐增长曲线 |
7.3 背压与限流测试
| 测试场景 | 写入速率设定 | 持续时间 | 预期观测 | 关键指标 |
|---|---|---|---|---|
| 正常速率 | 最大吞吐的 70% | 30 分钟 | 稳定无错误 | 延迟稳定性 |
| 满负荷 | 最大吞吐的 100% | 30 分钟 | 接近极限 | 是否有间歇性延迟飙升 |
| 轻度过载 | 最大吞吐的 110% | 15 分钟 | 少量延迟增加 | 是否开始排队 |
| 中度过载 | 最大吞吐的 150% | 15 分钟 | 延迟显著增加 | 错误率、数据丢失 |
| 重度过载 | 最大吞吐的 300% | 10 分钟 | 系统可能崩溃 | OOM、进程退出 |
| 过载恢复 | 从 300% 降到 70% | 30 分钟 | 应恢复到正常 | 恢复时间、积压消化速度 |
7.4 最短持续时长
很多压测报告只跑了 5 分钟就报结果,这在专业领域是不可接受的。5 分钟只够让系统达到稳态,但不足以暴露以下问题:内存泄漏(可能需要 2-4 小时才能累积到触发 GC 的程度)、compaction 积压(写入速度可能逐渐超过 compaction 速度,数小时后开始影响在线查询)、文件描述符泄漏(长时间运行后 FD 耗尽)、连接池老化(长连接在数小时后可能出现状态异常)。
| 压测目的 | 最短持续时长 | 原因 |
|---|---|---|
| 峰值吞吐验证 | 5 分钟 | 至少覆盖几个 compaction 周期 |
| 稳定性验证 | 1 小时 | 覆盖 WAL 轮转、checkpoint |
| Soak 测试 | 24 小时 | 暴露内存泄漏、FD 泄漏 |
| 对比选型 | 每轮 30 分钟 × 3 轮 | 取中位数消除偶发波动 |
关键认知:5 分钟的压测结果只能说明"峰值能力",不能说明"持续能力"。很多引擎在峰值和持续之间可以差 30-50%。例如,某引擎在 5 分钟内可以跑到 500 万 rows/s,但跑 1 小时后因为 compaction 积压,吞吐降到 350 万 rows/s。如果你只看了 5 分钟的结果就选型了这个引擎,上线后很可能因为持续吞吐不足而翻车。
7.5 乱序写入(O3)的专项测试
| 测试场景 | 乱序比例 | 乱序窗口 | 目的 |
|---|---|---|---|
| 完全有序 | 0% | 无 | 基准性能 |
| 轻微乱序 | 5% | 1 分钟内 | 模拟网络延迟导致的乱序 |
| 中等乱序 | 20% | 10 分钟内 | 模拟批量上报的延迟差异 |
| 严重乱序 | 50% | 1 小时内 | 模拟设备离线后批量上传 |
| 极端乱序 | 80% | 数小时 | 压力测试 O3 处理极限 |
7.6 WAL 与刷盘策略的影响
| 策略 | 写入吞吐 | 数据安全 | 适用场景 |
|---|---|---|---|
| WAL 同步刷盘(fsync 每条) | 最低 | 最高(不丢数据) | 金融级数据 |
| WAL 批量刷盘(每 N 条或每 M 毫秒) | 中高 | 高(最多丢 N 条或 M 毫秒数据) | 推荐生产配置 |
| WAL 异步刷盘 | 高 | 中(OS 崩溃可能丢数据) | 允许少量丢失的场景 |
| 关闭 WAL | 最高 | 最低(崩溃丢数据) | 仅用于纯压测对比 |
7.7 避坑指南
坑 1:只测 5 分钟就报峰值------峰值不能代表生产能力。
坑 2:不测背压------不知道系统的过载行为,就无法正确设计限流策略。
坑 3:忽略 WAL 策略对写入的影响------开 WAL 和关 WAL 的吞吐可以差 5 倍。
7.8 面试考点
Q:如何科学地压测时序数据库的写入性能?
答题框架:五步法------先确定最优 batch size(梯度扫描)、再确定最优 worker 数(并行扩展)、然后做极限压测(找天花板)、再做背压测试(看过载行为)、最后做 soak 测试(看长时间稳定性)。注意:WAL 策略要声明、乱序比例要对齐业务、持续时长至少 30 分钟。
第 8 章 查询压测方法论:冷热分离、并发梯度与查询矩阵
查询压测比写入压测更复杂,因为查询的性能高度依赖数据状态(缓存冷热)、查询类型(简单扫描 vs 复杂聚合)和并发模式。
8.1 查询类型矩阵
| 查询类型 | 典型操作 | 复杂度 | 数据访问模式 | 对索引的依赖 |
|---|---|---|---|---|
| Last-Point | 查最新一个数据点 | 低 | 点查 | 高(需 last-value 索引) |
| 范围扫描 | 指定时间范围的所有数据 | 低-中 | 顺序扫描 | 中(时间索引即可) |
| 单指标聚合 | AVG/MAX/MIN 一个指标 | 中 | 列式扫描 | 低 |
| 多指标聚合 | 同时聚合多个指标 | 中-高 | 多列扫描 | 低 |
| 分组聚合 | GROUP BY tag 后聚合 | 高 | 全量扫描+Hash分组 | 中(tag 索引) |
| 多维分组聚合 | GROUP BY 多个 tag | 极高 | 全量扫描+多维 Hash | 高 |
| 高基数 DISTINCT | 统计去重后的 series 数 | 极高 | 全量扫描+去重 | 高 |
| JOIN | 跨表关联查询 | 高 | 双表扫描+连接 | 高 |
| 子查询 | 嵌套查询 | 高 | 多轮扫描 | 高 |
| 窗口函数 | 移动平均、累计和等 | 中-高 | 有序扫描+窗口计算 | 中 |
8.2 并发查询数梯度
| 并发数 | 测试目的 | 预期行为 | 关键指标 |
|---|---|---|---|
| 1 | 单查询延迟基准 | 无竞争 | P50/P99 延迟 |
| 2 | 轻度并发 | 几乎无影响 | 吞吐增长比 |
| 4 | 中等并发 | 可能开始出现竞争 | 延迟增长拐点 |
| 8 | 较高并发 | 资源竞争加剧 | CPU 利用率、延迟 |
| 16 | 高并发 | 可能出现排队 | 吞吐饱和点 |
| 32 | 极限并发 | 吞吐可能不再增长 | 最大 QPS |
| 64 | 过载 | 延迟飙升、超时增多 | 错误率、超时率 |
| 128 | 压力极限 | 可能 OOM 或线程耗尽 | 系统稳定性 |
8.3 冷热缓存分离测试
| 测试阶段 | 操作 | 目的 | 关键指标 |
|---|---|---|---|
| 阶段 1:完全冷 | 清空 Page Cache(echo 1 > /proc/sys/vm/drop_caches)后立即查询 | 测纯磁盘 IO 能力 | 冷查询延迟 |
| 阶段 2:半热 | 随机查询一部分数据后,混合查询冷热数据 | 模拟混合负载 | 混合查询延迟 |
| 阶段 3:完全热 | 对同一查询集反复执行 3 轮后取最后一轮 | 测纯内存/CPU 能力 | 热查询延迟 |
| 阶段 4:冷却恢复 | 从热状态停止查询,等待 N 分钟后重新查询 | 测缓存衰减 | 延迟随时间回升曲线 |
8.4 查询预热控制
| 预热策略 | 方法 | 适用场景 | 注意事项 |
|---|---|---|---|
| 完全预热 | 遍历所有数据后再开始测试 | 只关心热查询性能 | 明确标注"预热后" |
| 不预热 | 直接开始测试 | 关心冷启动性能 | 首轮数据需单独标注 |
| 部分预热 | 只预热最近 N 小时的数据 | 模拟真实监控场景 | 需说明预热范围 |
| 周期性预热 | 每隔 M 分钟预热一次 | 模拟缓存逐出场景 | 需要脚本控制 |
8.5 查询集设计原则
查询集的设计直接决定了压测结果的代表性。一个糟糕的查询集可能让你得出完全错误的结论。例如,如果你的业务主要是范围扫描+聚合,但你只用了 TSBS 默认的 lastpoint 查询来压测,你可能会认为"所有引擎的查询性能差不多"------但实际上在范围扫描+聚合场景下,引擎之间的差距可能有 10 倍以上。
| 原则 | 说明 | 常见错误 |
|---|---|---|
| 覆盖全类型 | 不要只测一种查询 | 只测 lastpoint 不代表全部性能 |
| 符合业务比例 | 按真实业务的查询类型分布设计 | 压测全用复杂查询但生产 80% 是简单查询 |
| 时间范围多样 | 1 分钟/1 小时/1 天/7 天/30 天 | 只测 1 小时范围 |
| 基数多样 | 单 series/10 series/100 series/全量 | 只测单 series |
| 结果集大小多样 | 返回 10 行/1000 行/100 万行 | 只测小结果集 |
查询集权重设计建议:
| 查询类型 | 推荐权重(监控场景) | 推荐权重(IoT 分析场景) | 推荐权重(金融 Tick 场景) |
|---|---|---|---|
| Last-Point | 40% | 10% | 5% |
| 范围扫描 | 20% | 20% | 30% |
| 单指标聚合 | 15% | 20% | 25% |
| 多指标聚合 | 10% | 15% | 20% |
| 分组聚合 | 10% | 20% | 10% |
| 多维分组 | 3% | 10% | 5% |
| 高基数 DISTINCT | 1% | 5% | 5% |
| JOIN / 子查询 | 1% | 0% | 0% |
8.6 避坑指南
坑 1:不区分冷热缓存就报查询延迟------同一个查询冷和热可以差 10-50 倍。
坑 2:只测 TSBS 默认查询类型------TSBS 不包含 JOIN 和子查询,如果你的业务需要这些,必须额外补充。
坑 3:忽略结果集大小------返回 10 行和返回 100 万行的延迟完全不是一个量级。
8.7 面试考点
Q:如何科学地压测时序数据库的查询性能?
答题框架:三维矩阵------查询类型维度(覆盖 lastpoint/范围/聚合/分组/JOIN 等全类型)、并发维度(1 到 128 梯度)、缓存维度(冷/半热/热分离测试)。关键:报告必须标注缓存状态和查询类型分布,否则数字无意义。
第 9 章 资源观测与瓶颈归因:定位性能瓶颈的决策树
压测不是目的,定位瓶颈才是。这一章给你一个系统性的资源观测框架和瓶颈归因决策树。
9.1 CPU 观测
CPU 是时序数据库最核心的计算资源。写入时的数据编码、压缩、索引构建,查询时的数据扫描、聚合、排序,都离不开 CPU。但 CPU 观测不是简单地看一眼 top 就完事了------你需要区分用户态和内核态、区分数据平面和控制平面、区分写入线程和 compaction 线程。
| 观测指标 | 工具 | 正常范围 | 异常阈值 | 异常说明 |
|---|---|---|---|---|
| CPU 利用率 | top/mpstat | 写入时 60-80%,查询时 70-90% | 持续 >95% | 可能成为瓶颈 |
| 用户态 vs 内核态 | mpstat -P ALL | 用户态占主导 | 内核态 >30% | 系统调用过多,可能是 IO 或锁 |
| 上下文切换 | vmstat cs / pidstat -w | 每核 <10000/s | 每核 >50000/s | 锁竞争或线程过多 |
| CPU steal | vmstat st | <1% | >5% | 虚拟化邻居噪声 |
| NUMA 不均衡 | numastat | 各节点均匀 | 某节点 >70% | 内存分配策略问题 |
进阶技巧 :使用 perf top 可以查看 CPU 热点函数,帮助你判断瓶颈是在数据压缩、索引查找、还是网络序列化。如果发现某个特定函数占比异常高(如 zlib_compress 占 40%),可以考虑降低压缩级别来换取写入速度。
9.2 内存观测
| 观测指标 | 工具 | 正常范围 | 异常阈值 | 异常说明 |
|---|---|---|---|---|
| RSS | /proc/pid/status 或 top | 稳定或缓慢增长 | 持续线性增长 | 可能内存泄漏 |
| Page Cache | /proc/meminfo Cached | 占可用内存的 30-60% | 接近 0 或接近满 | 缓存策略异常 |
| Swap 使用 | free -m | 接近 0 | >1GB | 物理内存不足 |
| 内存碎片 | /proc/buddyinfo | 高阶页可用 | 高阶页全部分裂 | 长期运行后的碎片问题 |
| JVM 堆(如适用) | jstat -gc | 老年代 <70% | 老年代 >85% | 即将 Full GC |
9.3 磁盘 IO 观测
| 观测指标 | 工具 | 正常范围 | 异常阈值 | 异常说明 |
|---|---|---|---|---|
| IOPS | iostat -x | 低于设备标称值 | 接近设备极限 | IO 成为瓶颈 |
| 吞吐 | iostat MB/s | 低于设备标称值 | 接近设备极限 | 带宽瓶颈 |
| await | iostat -x await | <2ms(NVMe), <10ms(SSD) | >10ms(NVMe)或 >20ms(SSD) | IO 延迟异常 |
| %util | iostat -x %util | <80% | >90% | 磁盘接近饱和 |
| 写入放大 | 对比逻辑写入量和实际 IO | <2x | >5x | compaction 或 WAL 开销过大 |
9.4 网络观测
| 观测指标 | 工具 | 正常范围 | 异常阈值 | 异常说明 |
|---|---|---|---|---|
| 带宽使用率 | iftop/nload | <70% 链路容量 | >90% | 网络成为瓶颈 |
| 丢包率 | netstat -s | 0 | >0.01% | 网络质量问题 |
| 重传率 | ss -ti / netstat | <1% | >5% | TCP 重传导致延迟 |
| 连接数 | ss -s | 低于文件描述符限制 | 接近 ulimit | 连接泄漏或不足 |
9.5 瓶颈定位决策树
下面是一个系统性的瓶颈定位流程。在实际压测中,瓶颈往往不是单一维度的,而是多个资源互相牵制。例如,高并发写入可能导致 CPU 上下文切换增加(锁竞争),同时磁盘 IO 上升(WAL 刷盘),内存压力增大(缓冲区膨胀)。因此,建议按照"CPU → 内存 → 磁盘 → 网络"的顺序逐层排查,每一层确认或排除后再进入下一层。
| 症状 | 第一步检查 | 第二步检查 | 结论与行动 |
|---|---|---|---|
| 写入慢 | CPU 利用率? | 若 CPU 高→查 compaction 线程占比;若 CPU 低→查磁盘 await | CPU 高=计算瓶颈(优化编码或减少压缩);磁盘 await 高=IO 瓶颈(换 SSD 或调 WAL 策略) |
| 查询慢 | 缓存命中率? | 若冷查询慢→磁盘 await;若热查询也慢→CPU 或锁竞争 | 磁盘慢=加缓存层或换盘;CPU 高=优化查询或加核;锁竞争=减少并发或优化索引 |
| 延迟抖动大 | 上下文切换频率? | 若高→锁竞争;若不高→GC 或 compaction | 锁竞争=减并发或优化代码;GC=调 JVM 参数;compaction=调整 compaction 策略 |
| 内存持续增长 | 是否 Full GC 后能回收? | 若不能→内存泄漏;若能→正常缓存增长 | 泄漏→报 bug 或降级重启;正常→增大内存或调整缓存上限 |
| Soak 后吞吐下降 | compaction 积压?磁盘 IO? | 若 compaction 积压→降低写入速率或增加 compaction 线程 | 根本原因通常是 compaction 跟不上写入速度 |
| 写入成功但查询超时 | 查询计划是否走索引? | 若全表扫描→缺索引或分区策略不当;若走索引但仍慢→数据量过大 | 优化分区策略或增加物化视图 |
| 间歇性延迟毛刺 | 是否有定时任务(checkpoint/compaction)? | 对齐时间戳确认因果关系 | 调整定时任务频率或错峰执行 |
9.5.1 常见瓶颈模式速查
| 瓶颈模式 | 典型症状 | 根因 | 解决方案 |
|---|---|---|---|
| CPU 密集型 | CPU > 90%,磁盘和网络空闲 | 复杂聚合、大量编解码、压缩计算 | 增加 CPU 核数、优化查询、减少不必要的计算 |
| IO 密集型 | 磁盘 %util > 90%,CPU 空闲 | 大量随机写、compaction 与写入竞争 | 换更快的盘、分离 WAL 和数据盘、调整 compaction |
| 内存瓶颈 | RSS 持续增长、swap 使用增加 | 缓存配置过大、内存泄漏、并发过高 | 调小缓存、修复泄漏、增加内存 |
| 锁竞争 | 上下文切换飙升、CPU 用户态不高 | 多线程写入同一分区、全局锁 | 减少写入热点、优化分区策略、使用无锁数据结构 |
| 网络瓶颈 | 网络带宽接近上限、丢包 | 分布式副本同步、大量远程读取 | 增加带宽、使用压缩协议、本地化数据 |
| GC 停顿(JVM) | P99 延迟周期性飙升 | 堆内存不足、对象分配过快 | 增大堆内存、换 ZGC、减少临时对象分配 |
9.6 避坑指南
坑 1:只看 top 的 CPU 利用率不看 mpstat 的分核数据------可能只有一个核跑满其他核空闲。
坑 2:不看 %util 只看 IOPS------SSD 的 IOPS 很高但 %util 已经 100%。
坑 3:忽略写入放大------逻辑写入 100MB/s 但实际磁盘写了 500MB/s。
9.7 面试考点
Q:压测发现写入延迟突然飙升,如何排查?
答题框架:先看 CPU(是否 compaction 抢资源)、再看磁盘(await 是否飙升、%util 是否饱和)、再看内存(是否触发 Full GC 或 swap)、最后看网络(是否有大量数据同步)。形成决策树:CPU 高→减 compaction 线程优先级;磁盘饱和→换盘或调 WAL;GC→调 JVM;网络→检查副本同步。
第 10 章 三家 TSDB 压测实战:QuestDB / InfluxDB 3 / TimescaleDB 关键旋钮
这一章聚焦三家主流时序数据库的压测关键调优参数。每家都有自己的"最佳姿势"------调对了事半功倍,调错了性能腰斩。
10.1 QuestDB 10.0.1 关键调优旋钮
| 旋钮 | 说明 | 推荐值(压测) | 推荐值(生产) | 对性能的影响 |
|---|---|---|---|---|
| 分区粒度 | 数据按时间分区存储 | 根据写入量调整,高写入用天分区 | 与写入量匹配 | 直接影响查询扫描范围 |
| WAL 启用 | 写入前日志 | 压测对比时可关闭 | 生产必须开启 | 关闭后写入吞吐提升 2-5 倍 |
| O3 处理 | 乱序数据合并机制 | 减少乱序可提升性能 | 根据业务乱序程度调整 | 乱序严重时性能下降 30-50% |
| 协议选择 | ILP(InfluxDB Line Protocol)或 QWP(QuestDB Wire Protocol) | ILP 兼容性好 | ILP 或 QWP 均可 | QWP 可能略有性能优势 |
| Commit Mode | 同步/异步提交 | 异步(压测极限) | 同步或批量异步 | 影响数据安全性和吞吐 |
| 内存限制 | JVM 堆大小 | 物理内存 70% | 物理内存 60% | 影响缓存容量和 GC 频率 |
QuestDB TSBS 基准关键参数(据官方公开数据):
| 参数 | QuestDB 官方设定 | 备注 |
|---|---|---|
| 写入吞吐 | 8.59M rows/sec | TSBS DevOps 场景 |
| last-point 查询延迟 | 1.7ms | 对比 InfluxDB 20.5ms |
| 相对 InfluxDB 写入倍数 | 12-36x | 不同 batch size 范围 |
| 相对 InfluxDB 查询倍数 | 43-418x | 不同查询类型范围 |
| 相对 TimescaleDB 写入倍数 | 6-13x | 不同参数范围 |
| 版本 | 10.0.1 | 2026-08-24 发布 |
| 立场标注 | 官方 TSBS 口径 | 有局限性,需结合业务验证 |
10.2 InfluxDB 3 关键调优旋钮
| 旋钮 | 说明 | 推荐值(压测) | 推荐值(生产) | 对性能的影响 |
|---|---|---|---|---|
| Core 查询窗口 | 查询时间范围限制 | 最大 72 小时 | 根据业务需求 | 超过 72h 的查询被拒绝 |
| 协议选择 | Line Protocol / v2 Write API / Flight | Line Protocol 写入 | Flight 查询(高性能) | Flight 协议查询延迟更低 |
| Write Buffer | 写入缓冲区大小 | 调大以提高吞吐 | 默认即可 | 影响写入延迟和吞吐 |
| 存储层 | 对象存储(S3/GCS)+ 本地缓存 | 确保缓存充足 | 配置合理的缓存策略 | 冷数据查询受缓存影响 |
| 并发写入 | 并发 worker 数 | 逐步增加找拐点 | 根据写入源数量 | 过多并发增加锁竞争 |
| 分区策略 | 自动分区 vs 手动配置 | 了解默认行为 | 根据查询模式调整 | 影响查询扫描效率 |
InfluxDB 3 重要约束:
| 约束项 | 说明 | 对压测的影响 |
|---|---|---|
| 查询窗口限制 | Core 版本限制 72 小时查询范围 | 大范围聚合查询无法执行 |
| 版本 | 最新 3.8(2026-06-29) | 不存在 InfluxDB 4.0 |
| 架构 | 基于 Apache Arrow/Parquet | 列式存储,适合分析型查询 |
| 部署模式 | 云托管为主 | 本地部署选项有限 |
10.3 TimescaleDB 关键调优旋钮
| 旋钮 | 说明 | 推荐值(压测) | 推荐值(生产) | 对性能的影响 |
|---|---|---|---|---|
| chunk interval | 数据分块的时间间隔 | 压测时可调整到最优 | 根据写入量和查询范围 | 直接影响查询效率 |
| 压缩策略 | 启用原生压缩 | 可选择关闭以测原始性能 | 生产强烈建议开启 | 压缩后磁盘占用减少 90%+ |
| Hypercore | 行列双模存储引擎 | 了解默认模式 | 根据读写比例选择 | 读多写少用行模式、写多读少用列模式 |
| 连续聚合 | 预计算聚合视图 | 压测连续聚合的维护开销 | 生产强烈推荐 | 查询加速但写入有额外开销 |
| 分区策略 | 时间+空间多维分区 | 了解默认行为 | 高基数场景需仔细配置 | 影响查询扫描范围 |
| PostgreSQL 参数 | shared_buffers, work_mem, effective_cache_size | 调大到物理内存的 25%/5%/75% | 同左 | PostgreSQL 性能的基础 |
TimescaleDB 重要信息:
| 信息项 | 说明 |
|---|---|
| 最新版本 | 2.30(2026-09-02) |
| 不存在 | TimescaleDB 3.0 |
| 母公司 | TigerData |
| 底层 | PostgreSQL 扩展 |
| 核心优势 | SQL 兼容性、连续聚合、压缩 |
10.4 三家对比选型表
| 对比维度 | QuestDB 10.0.1 | InfluxDB 3.8 | TimescaleDB 2.30 |
|---|---|---|---|
| 写入架构 | 自研列式存储 | Arrow/Parquet + 对象存储 | PostgreSQL + chunk 分区 |
| 查询语言 | SQL(类 PostgreSQL) | SQL + InfluxQL + Flux | 完整 PostgreSQL SQL |
| 最佳场景 | 超高吞吐写入 + 低延迟查询 | 云原生 + 可观测性 | 复杂分析 + SQL 生态 |
| 压缩率 | 高(列式 + 字典编码) | 高(Parquet + 列式) | 高(原生压缩,90%+) |
| 乱序处理 | 专门 O3 优化 | Chunk 内合并 | chunk 内 UPDATE |
| 分布式 | 单节点为主 | 云原生分布式 | 单节点(可配合 Citus) |
| 生态兼容 | ILP 协议 | ILP/HTTP/Flight | 完整 PostgreSQL 生态 |
| 学习曲线 | 低(SQL 简单) | 中(多协议多语言) | 低(标准 SQL) |
| TSBS 写入性能(官方口径) | 最高(8.59M rows/s) | 中等 | 较低 |
| TSBS 查询性能(官方口径) | 最快 | 中等 | 较慢 |
10.5 QuestDB vs InfluxDB 3 vs TimescaleDB:写入路径深度对比
三家数据库的写入路径设计哲学截然不同,理解这些差异才能解释压测结果的差异。
| 维度 | QuestDB | InfluxDB 3 | TimescaleDB |
|---|---|---|---|
| 写入协议 | ILP / QWP(私有高性能协议) | ILP / v2 Write API / Flight | PostgreSQL COPY / INSERT |
| 存储格式 | 自研列式列存(基于 Apache Parquet 思想) | Apache Parquet + 对象存储 | PostgreSQL Heap + 列式压缩(Hypercore) |
| 写入路径 | 内存缓冲 → 顺序写磁盘 | 写入缓冲 → Parquet 文件刷写到对象存储 | WAL → 共享缓冲 → checkpoint 刷盘 |
| 批量写入优化 | 原生支持大批量 ILP 协议 | 批量 Line Protocol 或 Flight 批量写入 | COPY 命令批量导入(远快于 INSERT) |
| 乱序处理 | 专门的 O3(Out-of-Order)引擎,高效合并 | Chunk 内自动合并 | chunk 内 UPDATE(代价较高) |
| 背压行为 | 内存不足时拒绝新写入(fast-fail) | 缓冲溢出时返回 429 或拒绝 | PostgreSQL 共享缓冲满后等待或报错 |
关键洞察:QuestDB 的写入速度优势主要来自其自研的列式存储引擎和 O3 处理机制,它牺牲了一些 SQL 兼容性来换取极致的写入性能。InfluxDB 3 的架构更适合云原生场景,对象存储的写入延迟会影响写入性能但降低了存储成本。TimescaleDB 继承 PostgreSQL 的写入路径,在大批量写入时建议使用 COPY 而非 INSERT,否则性能差距会非常大。
生产环境选型建议:如果你的业务以超高吞吐写入为核心需求(例如每秒百万级数据点),QuestDB 是首选;如果你的业务需要复杂的 SQL 分析能力、与现有 PostgreSQL 生态集成,TimescaleDB 更合适;如果你的团队偏好云原生架构、希望免运维,InfluxDB 3 的云托管方案值得考虑。当然,最终决策必须基于你自己场景的压测结果,而不是任何厂商的官方基准。记住:没有最好的数据库,只有最适合你场景的数据库。压测的目的不是比数字,而是理解每个引擎在什么条件下表现最好、什么条件下会出问题。
10.6 官方基准复现条件清单
如果你想复现任何一家的官方基准数据,需要确认以下条件:
| 复现条件 | 必须确认的内容 | 常见遗漏 |
|---|---|---|
| 硬件 | 完全一致的 CPU/内存/磁盘型号 | 云实例规格差异 |
| 操作系统 | 相同内核版本 + 调优参数 | 默认 OS 配置差异 |
| 数据库版本 | 完全一致的版本号 | 小版本差异可能影响性能 |
| 工具版本 | TSBS 的 git commit 或版本号 | TSBS 本身也在更新 |
| 参数配置 | 所有非默认参数的完整列表 | 厂商可能使用了"不显而易见"的调优 |
| 数据模型 | TSBS 的 scale/time-span/seed 等全部参数 | scale 不同结果天差地别 |
| 预热策略 | 预热了几轮、每轮多长时间 | 不预热 vs 充分预热差 5 倍 |
| 环境隔离 | 是否独享机器、有无邻居负载 | 共享实例有噪声 |
10.6 避坑指南
坑 1:直接拿 QuestDB 的 8.59M rows/s 和自己没调优的 InfluxDB 对比------这不公平,需要同等调优。
坑 2:忽略 InfluxDB 3 的 72 小时查询窗口限制------如果你的业务需要查 7 天数据,这个限制是硬伤。
坑 3:TimescaleDB 不调整 PostgreSQL 参数就跑------默认参数下 PostgreSQL 的性能只有调优后的 30-50%。
10.7 面试考点
Q:QuestDB / InfluxDB 3 / TimescaleDB 三家如何选型?
答题框架:从四个维度回答------写入吞吐需求(超高选 QuestDB)、查询生态需求(复杂 SQL 选 TimescaleDB)、云原生需求(云托管选 InfluxDB 3)、运维成本(TimescaleDB 依赖 PostgreSQL 运维、QuestDB 独立部署简单、InfluxDB 3 云托管免运维)。关键:没有"最好"只有"最适合"。
第 11 章 结果统计与报告规范:让数据说话而不是让数据骗人
压测数据出来了,怎么统计、怎么呈现,决定了报告的专业度和可信度。
11.1 多次运行取分布
| 统计方法 | 最少运行次数 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|---|
| 取中位数 | 3 次 | 通用 | 消除极端值 | 信息利用率低 |
| 取平均值 | 5 次以上 | 数据近似正态分布 | 信息利用率高 | 受极端值影响 |
| 取 P50/P95/P99 | 5 次以上 | 需要完整分布 | 全面反映性能 | 需要更多存储 |
| 取最优 | 1 次 | 仅限厂商宣传 | 数字好看 | 不具代表性 |
| 取最差 | 1 次 | 安全评估 | 保守估计 | 可能过于悲观 |
11.2 变异系数与置信区间
| 统计量 | 公式含义 | 正常范围 | 异常阈值 | 说明 |
|---|---|---|---|---|
| 变异系数(CV) | 标准差/均值 | <5% | >15% | CV 高说明结果不稳定,需要更多轮次 |
| 95% 置信区间 | 均值 ± 1.96 × 标准差/√n | 区间窄 | 区间宽 | 宽区间说明结果不确定性大 |
| 极差/均值 | (最大-最小)/均值 | <10% | >30% | 极差大说明有偶发因素影响 |
11.3 归一化对比
当你要对比多个数据库的性能时,直接用绝对值对比可能会产生误导。例如,如果 QuestDB 跑在一台 64 核的机器上,TimescaleDB 跑在一台 8 核的机器上,直接对比写入吞吐是不公平的。归一化可以解决这个问题。
常见的归一化方法有三种:
| 归一化方法 | 适用场景 | 示例 | 注意事项 |
|---|---|---|---|
| 以最强者为 100% | 横向对比多家 | QuestDB=100%, InfluxDB=28%, TimescaleDB=8% | 直观但可能夸大差距 |
| 以共同基准为 1.0 | 多组实验对比 | 以 scale=1000 为 1.0 | 适合看趋势 |
| 以生产需求为 100% | 选型评估 | 生产需要 100 万 rows/s,各引擎达标百分比 | 最实用 |
归一化的一个陷阱:以最强者为 100% 看起来很直观,但容易给人造成"差距很大"的印象。例如,A 引擎 100 万 rows/s,B 引擎 50 万 rows/s,归一化后 A=100%、B=50%------看起来差了一倍。但反过来看,B 引擎的绝对性能也有 50 万 rows/s,对于大多数生产场景已经足够了。所以归一化对比时,一定要同时展示绝对数值。
11.3.1 性能雷达图设计
为了让对比结果更加直观,推荐使用雷达图(Radar Chart)来展示多维度的性能对比。雷达图的每个轴代表一个指标维度:
| 雷达图轴 | 指标 | 归一化方式 |
|---|---|---|
| 轴1 | 写入吞吐 | 以最大值为 100% |
| 轴2 | 查询延迟(P50,取反) | 以最小值为 100% |
| 轴3 | 查询延迟(P99,取反) | 以最小值为 100% |
| 轴4 | 压缩率 | 以最大值为 100% |
| 轴5 | 资源效率 | 以 吞吐/CPU 比值为基准 |
| 轴6 | 稳定性 | 以 1 - 变异系数 为基准 |
雷达图的好处是能一目了然地看到每个引擎在各维度的优劣势。但要注意:雷达图的面积不代表"综合性能",它只是一个多维度的可视化展示。综合评分需要根据业务需求对不同维度加权。
11.4 压测报告模板
一份完整的压测报告应包含以下章节:
| 章节 | 必须包含的内容 | 常见遗漏 |
|---|---|---|
| 1. 测试目标 | 为什么压测、要回答什么问题 | 目标不明确导致压测无方向 |
| 2. 环境信息 | 硬件、OS、网络、数据库版本(完整表格) | 只写"8 核 16G"不写 CPU 型号 |
| 3. 数据集信息 | scale、时间跨度、乱序比例、总数据量 | 只写"用 TSBS 生成"不写参数 |
| 4. 调优参数 | 所有非默认参数的完整列表 | 隐藏关键调优 |
| 5. 写入结果 | 吞吐、延迟分布、最优 batch、背压表现 | 只报峰值不报持续值 |
| 6. 查询结果 | 各查询类型的延迟分布(分冷热) | 只报一种查询类型 |
| 7. 资源消耗 | CPU、内存、磁盘 IO 时序图 | 不报资源消耗 |
| 8. 稳定性 | soak 测试结果、衰减曲线 | 不做 soak 测试 |
| 9. 结论 | 推荐结论 + 适用场景 + 局限性 | 只说"X 最快"不说适用场景 |
| 10. 可重复性 | 完整的复现步骤(脚本+参数+环境) | 不给复现方法 |
11.5 图表规范
| 图表类型 | 适用数据 | 关键要求 | 常见错误 |
|---|---|---|---|
| 折线图 | 吞吐/延迟随时间变化 | X 轴标注时间、Y 轴标注单位 | 不标单位 |
| 柱状图 | 不同引擎的对比 | 横轴标注引擎名、纵轴标注指标 | 截断 Y 轴夸大差距 |
| 箱线图 | 延迟分布 | 标注 P50/P95/P99/Max | 只标平均值 |
| CDF 图 | 延迟累积分布 | 标注关键百分位 | 用对数坐标但不标注 |
| 热力图 | 延迟随时间+并发的变化 | 色阶标注数值范围 | 色阶不连续 |
11.6 避坑指南
坑 1:只跑一次就报结果------单次结果可能是偶发的最佳或最差值。
坑 2:只报平均值不报分布------平均值会掩盖长尾问题。
坑 3:不给复现方法------不可复现的压测结果等于没有。
11.7 面试考点
Q:如何写一份可信的压测报告?
答题框架:报告十要素------目标、环境(完整硬件表)、数据集(完整参数表)、调优(所有非默认配置)、写入结果(含背压)、查询结果(分冷热分类型)、资源消耗(时序图)、稳定性(soak 曲线)、结论(含局限性)、可重复性(完整复现步骤)。核心原则:透明 > 好看。
第 12 章 识别基准造假:七种常见手法与识破方法
这一章是"防忽悠指南"。不是所有厂商都"造假",但几乎所有厂商都会"选择性展示"。你需要知道这七种常见手法,才能做出独立判断。
12.1 七种常见手法
| 编号 | 手法名称 | 具体操作 | 识破方法 |
|---|---|---|---|
| 1 | 选择性披露查询类型 | 只展示自己最快的查询类型 | 要求看全部 TSBS 查询类型结果 |
| 2 | 缓存作弊 | 反复跑同一查询让 Page Cache 完全命中 | 要求看冷启动数据 + 热缓存数据分别标注 |
| 3 | 单线程对比多线程 | 自己用多线程、竞品用单线程 | 检查各家的 worker 数是否一致 |
| 4 | 硬件不对等 | 自己在高配机器上跑、竞品在低配上跑 | 检查是否同一台机器、同一配置 |
| 5 | Batch 调优不对等 | 对自己做 batch 扫描取最优、竞品用默认 | 检查竞品是否也做了 batch 优化 |
| 6 | 过时竞品版本 | 自己用最新版、竞品用旧版本 | 检查三家版本号是否都是最新 |
| 7 | 数据集偏向 | 用自己的优势场景(如小数据集)测全部 | 检查数据集是否覆盖多种规模和模式 |
12.2 各手法的详细识破指南
识别基准造假不需要你是性能测试专家,只需要你会问对的问题。以下每种手法都附带了"一句话追问",在评审会上直接抛出来,就能让注水的报告无处遁形。
手法 1:选择性披露查询类型
| 可疑信号 | 验证方法 | 结论 |
|---|---|---|
| 只展示 lastpoint 查询延迟 | 要求提供 double-groupby-all 等复杂查询结果 | 如果复杂查询性能差很多,说明优势不全面 |
| 只展示 1-2 种查询 | 要求提供完整 TSBS 12 种查询的结果 | 完整结果才能说明综合性能 |
| 展示"平均查询延迟"但不说明查询集 | 要求说明查询集构成 | 可能只选了快的查询做平均 |
手法 2:缓存作弊
| 可疑信号 | 验证方法 | 结论 |
|---|---|---|
| 查询延迟异常低(如 <1ms 对所有查询) | 要求提供清空 Page Cache 后的冷查询数据 | 如果冷查询延迟飙升 10 倍+,说明依赖缓存 |
| 不标注缓存状态 | 要求分别报告冷/热查询延迟 | 不标注 = 大概率是热缓存结果 |
| 数据集很小(完全放入内存) | 确认数据集大小 vs 物理内存 | 数据集 < 内存 = 全程缓存命中 |
手法 3-7 的识破:
| 手法 | 一句话识破 |
|---|---|
| 单线程 vs 多线程 | "请问各家的并发 worker 数分别是多少?" |
| 硬件不对等 | "请问三家数据库是否运行在同一台物理机上?" |
| Batch 不对等 | "请问是否对每家数据库都做了 batch size 参数扫描?" |
| 过时版本 | "请问三家使用的具体版本号是多少?是否为最新发布版?" |
| 数据集偏向 | "请问数据集的基数、时间跨度、乱序比例分别是多少?" |
12.4 独立基准的第三方参考
除了厂商自己的基准报告,还有一些独立的第三方基准可以参考。这些基准虽然也不完美,但通常比厂商自己的报告更中立。
| 来源 | 类型 | 可信度 | 优点 | 局限 |
|---|---|---|---|---|
| 社区用户自发测试 | 博客/论坛帖子 | 中等 | 贴近真实使用场景 | 可能不够系统化 |
| 技术媒体横评 | 科技媒体文章 | 中高 | 通常有标准化的测试流程 | 可能受厂商赞助影响 |
| 学术论文 | 正式发表的论文 | 高 | 方法论严谨、可重复 | 可能不够反映工业实践 |
| 开源基准项目 | GitHub 项目 | 中高 | 代码公开可审查 | 维护频率和数据模型可能过时 |
| 咨询公司报告 | Gartner/Forrester 等 | 中 | 覆盖面广 | 偏向大厂、不够技术深度 |
如何交叉验证:不要只信一个来源。至少找三个独立来源的数据进行交叉验证。如果三个来源都指向同一个结论,那这个结论的可信度就很高。如果三个来源的结论不一致,那说明结论高度依赖于测试条件,你需要仔细对比测试条件和你自己的场景。
12.5 避坑指南
| 标准 | 最低要求 | 推荐标准 |
|---|---|---|
| 工具统一 | 全部使用 TSBS | TSBS + 自研业务查询 |
| 环境统一 | 同一台物理机 | 独享物理机 + 完整硬件表 |
| 参数公平 | 各家的非默认参数公开 | 各家都做参数扫描取最优 |
| 版本公平 | 各家都用最新稳定版 | 标注具体版本号 |
| 数据公平 | 相同 scale + time span + seed | 多组数据集覆盖不同场景 |
| 缓存公平 | 标注冷/热状态 | 分别报告 + 说明预热策略 |
| 统计可靠 | 至少 3 次取中位数 | 5 次 + 报 CV + 报置信区间 |
12.4 避坑指南
坑 1:只看厂商官网的 benchmark 页面就下结论------那是一篇精心编排的营销稿。
坑 2:被"快 X 倍"的数字吓到------倍数的大小取决于基准的选择,不取决于真实性能差距。
坑 3:不验证就引用------引用厂商数据时必须标注"据 XX 官方 TSBS 口径,有局限性"。
12.5 面试考点
Q:如何判断一份数据库基准测试是否公平?
答题框架:七查------查工具(是否统一)、查环境(是否同一硬件)、查参数(是否公平调优)、查版本(是否最新)、查数据(是否多场景)、查缓存(是否标注冷热)、查统计(是否多次取分布)。任何一个维度不公平,结论都不可信。
第 13 章 压测自动化:从一键脚本到 CI 回归
手工压测只能做一次。自动化压测才能持续守护性能基线。
13.1 一键脚本设计思路
| 模块 | 功能 | 关键设计 |
|---|---|---|
| 环境检查 | 检查硬件/OS/磁盘类型 | 自动采集并记录到报告 |
| 参数生成 | 根据场景自动生成 TSBS 参数 | 支持 YAML 配置文件 |
| 数据生成 | 调用 tsbs_generate_data | 支持并行生成 |
| 写入加载 | 调用 tsbs_load_* | 支持梯度 batch + 梯度 worker |
| 查询执行 | 调用 tsbs_run_queries_* | 支持冷热分离 + 梯度并发 |
| 资源采集 | 后台采集 CPU/内存/磁盘/网络 | 每秒采样一次 |
| 结果汇总 | 生成 HTML/PDF 报告 | 自动计算统计量 |
13.2 自动化脚本关键参数配置表
| 参数类别 | 参数名 | 默认值 | 可配置范围 | 影响 |
|---|---|---|---|---|
| 数据集 | scale | 1000 | 100-100000 | 基数大小 |
| 数据集 | time-span | 1d | 1h-365d | 数据总量 |
| 数据集 | seed | 12345 | 任意整数 | 随机种子 |
| 写入 | batch-sizes | 100,500,1000,5000 | 任意正整数列表 | batch 梯度 |
| 写入 | worker-counts | 1,4,8,16,32 | 任意正整数列表 | 并发梯度 |
| 写入 | duration | 300s | 60s-86400s | 每轮持续时长 |
| 查询 | concurrency | 1,4,8,16,32 | 任意正整数列表 | 查询并发梯度 |
| 查询 | warmup-rounds | 3 | 0-10 | 预热轮次 |
| 查询 | cache-mode | cold,warm,both | cold/warm/both | 缓存控制 |
| 统计 | repeat-count | 5 | 1-20 | 重复次数 |
| 统计 | confidence-level | 95% | 90%/95%/99% | 置信区间 |
13.3 结果入库方案
| 存储方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 写入被测 TSDB 自身 | 单一引擎回归 | 简单直接 | 引擎 bug 可能丢数据 |
| SQLite | 轻量级本地存储 | 零依赖、可移植 | 不支持并发写入 |
| PostgreSQL | 多引擎对比存储 | 支持复杂查询和报表 | 需要额外部署 |
| Prometheus + Grafana | 时序可视化 | 天然支持时序、可视化好 | 不存储原始压测参数 |
| JSON 文件 + Git | 版本化存储 | 可追溯、可 diff | 不便于查询分析 |
13.4 CI 回归压测
回归压测的核心思想是:每一次代码变更都可能引入性能退化,只有持续自动化地跑压测,才能在问题进入生产之前把它拦截住。
这里有一个很多团队容易犯的错误:只在发版前跑一次全量压测。这种做法的问题是------如果发现问题,你已经投入了大量开发时间,回退成本很高。正确的做法是把压测分散到不同的 CI 阶段,越早发现问题代价越低。
| CI 阶段 | 触发条件 | 压测范围 | 超时阈值 | 失败策略 |
|---|---|---|---|---|
| PR 冒烟 | 每次 PR | 小规模数据集 + 核心查询 | 15 分钟 | 阻塞合并 |
| 每日回归 | 每日定时 | 中规模数据集 + 全查询 | 2 小时 | 发通知 |
| 版本全量 | 发版前 | 大规模数据集 + 全查询 + soak | 24 小时 | 阻塞发版 |
| 性能对比 | 版本发布后 | 新版本 vs 旧版本同参数对比 | 48 小时(含两轮) | 出对比报告 |
PR 冒烟阶段的设计要点:数据集要足够小(能在 15 分钟内跑完),但又要足够大以覆盖核心路径。推荐使用 scale=100、time-span=1 小时的数据集,跑写入吞吐 + 5 种核心查询类型。如果 PR 冒烟的吞吐比基线下降超过 10%,自动在 PR 上标注性能警告。
每日回归阶段的设计要点:数据集扩大到 scale=1000、time-span=7 天,覆盖全部 TSBS 查询类型。结果写入数据库,自动生成趋势图。如果连续 3 天趋势下降,触发告警。
版本全量阶段的设计要点:使用生产级别的数据集(scale=10000 或更大),包含完整的写入梯度、查询并发梯度、soak 测试(至少 12 小时)。这一轮的结果将作为发版的性能基线,后续的回归都与之对比。
13.5 版本间性能对比报告模板
| 对比维度 | 旧版本 | 新版本 | 变化率 | 判定 |
|---|---|---|---|---|
| 写入吞吐(rows/s) | X | Y | (Y-X)/X × 100% | >5% 提升=绿,<-5%=红 |
| P50 查询延迟 | X ms | Y ms | (Y-X)/X × 100% | 降低=绿,升高=红 |
| P99 查询延迟 | X ms | Y ms | (Y-X)/X × 100% | 降低=绿,升高=红 |
| 磁盘占用 | X GB | Y GB | (Y-X)/X × 100% | 降低=绿,升高=红 |
| RSS 内存 | X MB | Y MB | (Y-X)/X × 100% | 降低=绿,升高=红 |
| Soak 衰减率 | X%/h | Y%/h | (Y-X)/X × 100% | 降低=绿,升高=红 |
13.6 压测数据的可视化最佳实践
压测结果只有被正确可视化,才能被有效理解和决策。一张糟糕的图表可能让正确的数据传达错误的信息。以下是几种常用的可视化方案及其适用场景。
| 图表类型 | 适用数据 | 关键要求 | 常见错误 | 推荐工具 |
|---|---|---|---|---|
| 折线图 | 吞吐/延迟随时间变化 | X 轴标注时间、Y 轴标注单位 | 不标单位 | Grafana / Matplotlib |
| 柱状图 | 不同引擎的对比 | 横轴标注引擎名、纵轴标注指标 | 截断 Y 轴夸大差距 | Matplotlib / ECharts |
| 箱线图 | 延迟分布 | 标注 P50/P95/P99/Max | 只标平均值 | Matplotlib / R |
| CDF 图 | 延迟累积分布 | 标注关键百分位 | 用对数坐标但不标注 | Matplotlib |
| 热力图 | 延迟随时间+并发的变化 | 色阶标注数值范围 | 色阶不连续 | Seaborn / ECharts |
| 雷达图 | 多维性能对比 | 归一化到同一尺度 | 面积不代表综合性能 | ECharts / Matplotlib |
图表设计三原则:
第一,Y 轴从零开始(柱状图必须,折线图视情况而定)。截断 Y 轴会夸大差异,例如把 Y 轴从 95% 开始画,80% 和 90% 的差距看起来就像差了一倍。
第二,标注数据点和数值。不要只画一条线,在关键拐点处标注具体数值。例如在"吞吐饱和点"处标注"32 workers, 120 万 rows/s"。
第三,一图一主题。不要在一张图里塞太多信息。写入吞吐和查询延迟放在两张图里,而不是一张图的双 Y 轴------双 Y 轴容易让人误读关联性。
13.7 避坑指南
坑 1:CI 压测用太小的数据集------小数据集看不出性能退化。
坑 2:不设性能基线告警------没有基线就无法发现回归。
坑 3:每次全量压测------太耗时间,应该分级(PR 冒烟 + 每日回归 + 版本全量)。
13.8 面试考点
Q:如何设计时序数据库的自动化压测体系?
答题框架:三级 CI------PR 冒烟(15 分钟,小规模,阻塞合并)、每日回归(2 小时,中规模,发通知)、版本全量(24 小时,大规模 + soak,阻塞发版)。结果入库(推荐 SQLite 或 PostgreSQL),版本间对比自动生成报告,超阈值自动告警。
第 14 章 面试考点 + 压测检查清单:上线前一项都不能少
最后一章,给你一个完整的"面试标准答案框架"和"上线前检查清单"。
14.1 "如何压测一个时序数据库"标准回答框架
面试时遇到这个问题,按以下框架组织答案:
| 步骤 | 关键内容 | 面试加分词 |
|---|---|---|
| 1. 明确目标 | 是选型对比还是容量规划还是版本回归? | "不同目标决定不同的数据集和持续时长" |
| 2. 环境归一化 | 硬件、OS、JVM、预热全部控制变量 | "不归一化,数据全白跑" |
| 3. 工具选择 | TSBS 横向对比 + 自研脚本业务贴合 | "标准化 + 定制化双轨" |
| 4. 数据集设计 | 基数、tag/field 比例、乱序比例对齐业务 | "数据集聚纲 = 压力分布" |
| 5. 写入压测 | batch 梯度 → worker 梯度 → 极限 → 背压 → soak | "五步法找天花板" |
| 6. 查询压测 | 类型矩阵 × 并发梯度 × 冷热分离 | "三维查询矩阵" |
| 7. 资源观测 | CPU/内存/磁盘/网络全方位 | "瓶颈定位决策树" |
| 8. 统计报告 | 多次取分布、CV、置信区间、归一化对比 | "变异系数 <5% 才算稳定" |
| 9. 结论 | 推荐 + 适用场景 + 局限性 | "没有最好的,只有最适合的" |
14.2 上线前压测检查清单
| 序号 | 检查项 | 必选/可选 | 通过标准 | 不通过的后果 |
|---|---|---|---|---|
| 1 | 硬件环境已归一化 | 必选 | 与生产同型号或已标注偏差 | 结果不反映生产性能 |
| 2 | OS 调优已完成 | 必选 | 关 THP、关 swap、设 CPU governor | 性能损失 10-20% |
| 3 | 文件描述符已调大 | 必选 | ulimit -n >= 65535 | 高并发时连接失败 |
| 4 | 数据库参数已调优 | 必选 | 所有关键旋钮已扫描最优值 | 默认参数下性能可能只有 30% |
| 5 | 预热已完成 | 必选 | 至少 3 轮预热 | 首轮数据不可靠 |
| 6 | 写入梯度测试已完成 | 必选 | batch 梯度 + worker 梯度 + 极限 | 不知道系统天花板 |
| 7 | 背压测试已完成 | 必选 | 知道过载行为和数据丢失情况 | 生产过载时可能丢数据 |
| 8 | Soak 测试已完成 | 必选 | 至少 24 小时无内存泄漏 | 生产可能 OOM |
| 9 | 查询类型已覆盖 | 必选 | 覆盖业务前 5 种高频查询 | 盲区查询可能超时 |
| 10 | 冷热缓存已分离测试 | 必选 | 分别标注冷/热延迟 | 不知道真实查询体验 |
| 11 | 并发查询梯度已完成 | 必选 | 从 1 到至少 32 并发 | 不知道查询极限 |
| 12 | 资源监控已部署 | 必选 | CPU/内存/磁盘/网络全采集 | 无法定位瓶颈 |
| 13 | 磁盘基线(fio)已完成 | 可选 | 知道磁盘 IOPS/吞吐/延迟基线 | 无法判断瓶颈在盘还是在库 |
| 14 | 压缩率已测试 | 可选 | 知道生产数据量对应的存储成本 | 可能存储预算超支 |
| 15 | 乱序写入已测试 | 可选 | 已知乱序对性能的影响 | 生产乱序场景可能性能骤降 |
| 16 | 邻居噪声已检测 | 可选 | steal time < 1% | 结果可能不可重复 |
| 17 | 多次运行统计已完成 | 可选 | 至少 3 轮,CV < 10% | 结果可能不可靠 |
| 18 | 报告已包含完整复现方法 | 可选 | 脚本 + 参数 + 环境全记录 | 无法复现 = 不可信 |
| 19 | 回归测试 CI 已配置 | 可选 | PR 冒烟 + 每日回归 | 版本升级可能性能退化 |
| 20 | 容量规划已计算 | 可选 | 根据压测结果推算生产所需资源 | 可能资源不足或浪费 |
14.3 压测方法论的演进趋势
时序数据库的压测方法论并不是一成不变的。随着技术架构的演进,压测方法也在不断升级。以下是几个值得关注的趋势:
| 趋势 | 描述 | 对压测的影响 | 应对策略 |
|---|---|---|---|
| 云原生化 | 数据库部署在 Kubernetes 上,使用对象存储 | 需要测试网络延迟、存储分层的影响 | 增加网络 IO 维度的观测 |
| Serverless 化 | 按查询付费,无常驻进程 | 冷启动延迟成为关键指标 | 单独测试冷启动场景 |
| 湖仓一体 | 数据存储在开放格式(Parquet/Iceberg)上 | 压测对象从数据库变为查询引擎 | 使用相同的查询引擎对比不同存储格式 |
| AI 辅助调优 | 使用机器学习自动选择最优参数 | 参数扫描的效率大幅提升 | 引入 AI 调优工具但仍需人工验证 |
| 可观测性集成 | 压测结果直接接入监控平台 | 实时可视化压测过程 | 使用 Prometheus + Grafana 采集压测指标 |
一个值得注意的变化:随着对象存储的普及,"存储成本"正在成为和"性能"同等重要的选型维度。未来的压测报告不仅要报告性能指标,还要报告"每 GB 存储成本"和"每千次查询 CPU 成本"。这意味着压测方法论需要从纯性能测试扩展到"性能-成本"联合评估。
14.4 高频面试题速查表
| 题号 | 面试题 | 核心答案要点 | 难度 |
|---|---|---|---|
| 1 | 如何评估压测报告的可信度? | 工具、环境、口径、调优、持续性五维 | 中 |
| 2 | TSBS 的原理和局限? | 三阶段、两场景、scale 基数控制、查询类型固定 | 中 |
| 3 | 写入压测怎么做? | batch 梯度 → worker 梯度 → 极限 → 背压 → soak | 中 |
| 4 | 查询压测怎么做? | 类型矩阵 × 并发梯度 × 冷热分离 | 中 |
| 5 | 如何定位写入瓶颈? | CPU→磁盘→内存→网络的决策树 | 高 |
| 6 | 三家 TSDB 如何选型? | 写入选 QuestDB、SQL 选 TimescaleDB、云选 InfluxDB 3 | 高 |
| 7 | 为什么同工具不同参数差 10 倍? | 基数、batch、乱序、查询类型、缓存五因素 | 中 |
| 8 | 如何识别基准造假? | 七查法:工具/环境/参数/版本/数据/缓存/统计 | 高 |
| 9 | 如何设计自动化压测? | 三级 CI + 结果入库 + 版本对比 + 阈值告警 | 高 |
| 10 | 压测上线前检查清单? | 20 项清单分必选/可选 | 中 |
14.4 避坑指南(本章特供)
坑 1:面试只说"用 TSBS 跑一下"------面试官想听的是方法论,不是工具名。
坑 2:不说"归一化"和"控制变量"------这两个词是压测的核心思想,不提就减分。
坑 3:不说局限性------任何压测都有局限性,主动说明比被追问好。
14.5 加分点
面试最后补一句:"压测的终极目标不是数字好看,而是建立对系统行为的深度理解------知道它在什么条件下快、什么条件下慢、什么条件下会崩。"这句话的段位,直接把你的回答从"会用工具"提升到"理解本质"。
写在最后
全文 14 章,从"为什么 90% 的压测报告都在骗人"讲到"上线前 20 项检查清单",覆盖了时序数据库压测的完整方法论。核心三句话送给大家:
第一句:压测参数必须与业务场景对齐,否则数字毫无意义。
第二句:不归一化,数据全白跑------环境控制是压测的地基。
第三句:没有最好的数据库,只有最适合场景的数据库------压测的目标是理解行为,不是比数字。
如果这篇文章对你有启发,请点赞、收藏、评论三连支持一下!你的三连是我持续输出硬核技术内容的最大动力 💪
有任何问题或者想讨论的场景,欢迎在评论区留言,我会逐一回复。我们下期见!
参考信息来源:
| 信息项 | 来源 | 版本/日期 |
|---|---|---|
| QuestDB 写入/查询基准数据 | QuestDB 官方 TSBS 口径 | 10.0.1(2026-08-24) |
| InfluxDB 3 信息 | InfluxDB 官方文档 | 3.8(2026-06-29) |
| TimescaleDB 信息 | TimescaleDB/TigerData 官方文档 | 2.30(2026-09-02) |
| TSBS 工具 | GitHub TimeSeriesBenchmarkSuite 项目 | 持续更新 |
| 声明 | 以上厂商数据均来自各自官方发布,存在立场局限性,需结合独立验证 | --- |
作者说:
写这篇博客的初衷,是因为我看到太多人在选型时只看厂商官网的一个数字就做决定,也看到太多压测报告只报一个峰值数字就"交差"。时序数据库的压测是一门系统工程,它需要你理解引擎的内部机制、理解操作系统的资源模型、理解统计学的分布规律。
希望这篇 2 万字的长文能帮你建立完整的压测方法论框架。无论你是正在做选型评估、还是在准备面试、还是想搭建自动化压测体系,都能从文中找到可以直接落地的方法。