时间序列基准测试套件 (TSBS)
此代码库包含用于对多个时间序列数据库进行基准测试的代码,包括TimescaleDB、MongoDB、InfluxDB、CrateDB和Cassandra。本代码基于InfluxDB最初在 https://github.com/influxdata/influxdb-comparisons 公开的工作的分支。
目前支持的数据库:
- Akumuli (补充文档)
- Cassandra (补充文档)
- ClickHouse (补充文档)
- CrateDB (补充文档)
- InfluxDB (补充文档)
- MongoDB (补充文档)
- QuestDB (补充文档)
- SiriDB (补充文档)
- TimescaleDB (补充文档)
- Timestream (补充文档)
- VictoriaMetrics (补充文档)
概述
时间序列基准测试套件 (TSBS) 是一系列Go程序的集合,用于生成数据集并对各种数据库的读写性能进行基准测试。其目的是使TSBS具有可扩展性,以便包含和测试各种用例(如开发运维、物联网、金融等)、查询类型和数据库。为此,我们希望帮助潜在的数据库管理员找到最适合他们需求和工作负载的数据库。此外,如果您是时间序列数据库的开发者,并希望将您的数据库纳入TSBS,欢迎开启一个拉取请求来添加它!
当前用例
目前,TSBS支持两种用例。
开发运维
一个"开发运维"用例,有两种形式。完整形式用于生成、插入和测量来自9个"系统"的数据,这些系统可能在真实世界的开发运维场景中被监控(例如,CPU、内存、磁盘等)。这9个系统每个读取间隔共生成100个指标。另一种形式仅关注CPU指标,提供更简单、更精简的用例。这个用例每次读取生成10个CPU指标。
除了指标读数外,还为数据集中每个有读数的主机生成"标签"(包括主机位置、操作系统等)。每组唯一的标签标识数据集中的一个主机,生成的不同主机数量由scale
标志定义(见下文)。
物联网 (IoT)
第二个用例旨在模拟物联网环境中的数据负载。这个用例模拟来自一家虚构卡车公司的一组卡车的数据流。它模拟每辆卡车的诊断数据和指标,并引入环境因素,如乱序数据和批量摄取(对于一段时间离线的卡车)。它还跟踪卡车元数据,并将其用于将指标和诊断作为查询集的一部分联系起来。
作为这个用例一部分生成的查询将涵盖实时卡车状态和分析,这些分析将查看时间序列数据,以更好地预测卡车行为。这个用例的规模因素将基于跟踪的卡车数量。
并非所有数据库都实现了所有用例。下表显示了每个数据库实现的用例:
数据库 | 开发运维 | 物联网 |
---|---|---|
Akumuli | X¹ | |
Cassandra | X | |
ClickHouse | X | |
CrateDB | X | |
InfluxDB | X | X |
MongoDB | X | |
QuestDB | X | X |
SiriDB | X | |
TimescaleDB | X | X |
Timestream | X | |
VictoriaMetrics | X² |
¹ 不支持groupby-orderby-limit
查询
² 不支持groupby-orderby-limit
、lastpoint
、high-cpu-1
、high-cpu-all
查询
TSBS测试什么
TSBS用于测试批量加载性能和查询执行性能。(目前不测量并发插入和查询性能,这是未来的优先事项。)为了公平地完成这项工作,要插入的数据和要运行的查询都是预先生成的,并尽可能使用原生Go客户端连接到每个数据库(例如,MongoDB使用mgo
,Timestream使用aws sdk
)。
尽管数据是随机生成的,但TSBS的数据和查询完全是确定性的。通过向生成程序提供相同的PRNG(伪随机数生成器)种子,每个数据库都会加载相同的数据并使用相同的查询进行查询。
安装
TSBS是一系列Go程序的集合(还有一些辅助bash和Python脚本)。获取和安装Go程序的最简单方法是使用go get
,然后使用make all
安装所有二进制文件:
# 获取TSBS及其依赖项
$ go get github.com/timescale/tsbs
$ cd $GOPATH/src/github.com/timescale/tsbs
$ make
如何使用TSBS
使用TSBS进行基准测试涉及3个阶段:数据和查询生成、数据加载/插入以及查询执行。
数据和查询生成
为了确保基准测试结果不受动态生成数据或查询的影响,TSBS要求您首先生成想要测试的数据和查询,然后您可以(重复)使用它作为基准测试阶段的输入。
数据生成
所需变量:
- 用例。例如,
iot
(从cpu-only
、devops
或iot
中选择) - 用于确定性生成的PRNG种子。例如,
123
- 要生成的设备/卡车数量。例如,
4000
- 数据时间戳的开始时间。例如,
2016-01-01T00:00:00Z
- 结束时间。例如,
2016-01-04T00:00:00Z
- 每个设备每次读数之间的时间间隔,以秒为单位。例如,
10s
- 您想要为哪个数据库生成数据。例如,
timescaledb
(从cassandra
、clickhouse
、cratedb
、influx
、mongo
、questdb
、siridb
、timescaledb
或victoriametrics
中选择)
根据上述步骤,您现在可以使用tsbs_generate_data
工具生成数据集(如果您选择为多个数据库生成,则可以生成多个数据集),用于对所选数据库进行数据加载基准测试:
$ tsbs_generate_data --use-case="iot" --seed=123 --scale=4000 \
--timestamp-start="2016-01-01T00:00:00Z" \
--timestamp-end="2016-01-04T00:00:00Z" \
--log-interval="10s" --format="timescaledb" \
| gzip > /tmp/timescaledb-data.gz
# 每个额外的数据库都需要单独调用。
注意:我们将输出通过管道传输到gzip以减少磁盘空间。这也要求您在运行测试时通过gunzip管道传输。
上面的示例将生成一个伪CSV文件,可用于批量加载数据到TimescaleDB。每个数据库都有自己的数据存储格式,以便其相应的加载器最容易写入数据。上述配置将生成略超过1亿行(10亿个指标),这通常是一个不错的起点。 增加一天的时间段将增加约3300万行,因此,例如,30天将产生10亿行(100亿个指标)。
IoT用例
iot
用例与其他用例的主要区别在于它生成的数据可能包含乱序、缺失或空条目,以更好地表示与该用例相关的真实场景。
使用指定的种子意味着我们可以以确定性和可重现的方式进行多次数据生成。
查询生成
所需变量:
- 与数据生成中使用的相同用例、种子、设备数量和开始时间
- 结束时间比数据生成的结束时间晚一秒。例如,对于
2016-01-04T00:00:00Z
,使用2016-01-04T00:00:01Z
- 要生成的查询数量。例如,
1000
- 您想要生成的查询类型。例如,
single-groupby-1-1-1
或last-loc
对于最后一步,有许多可选的查询类型,列在附录I中。此外,scripts/generate_queries.sh
文件包含所有这些查询类型作为环境变量QUERY_TYPES
的默认值。如果您要生成多种类型的查询,我们建议您使用辅助脚本。
生成给定类型的一组查询:
$ tsbs_generate_queries --use-case="iot" --seed=123 --scale=4000 \
--timestamp-start="2016-01-01T00:00:00Z" \
--timestamp-end="2016-01-04T00:00:01Z" \
--queries=1000 --query-type="breakdown-frequency" --format="timescaledb" \
| gzip > /tmp/timescaledb-queries-breakdown-frequency.gz
注意:我们将输出通过管道传输到gzip以减少磁盘空间。这也要求您在运行测试时通过gunzip管道传输。
生成多种类型的查询集:
$ FORMATS="timescaledb" SCALE=4000 SEED=123 \
TS_START="2016-01-01T00:00:00Z" \
TS_END="2016-01-04T00:00:01Z" \
QUERIES=1000 QUERY_TYPES="last-loc low-fuel avg-load" \
BULK_DATA_DIR="/tmp/bulk_queries" scripts/generate_queries.sh
完整的查询类型列表可以在本README末尾的附录I中找到。
基准测试插入/写入性能
TSBS有两种方法来基准测试插入/写入性能:
- 使用
tsbs_load
进行实时模拟和加载 - 预先生成数据到文件,然后使用
tsbs_load
或特定数据库的可执行文件tsbs_load_*
加载
使用统一的tsbs_load
可执行文件
tsbs_load
可执行文件可以加载数据到任何支持的数据库。
它可以使用预生成的数据文件作为输入,或者实时模拟数据。
首先,通过以下命令生成一个填充了每个属性默认值的配置yaml文件:
$ tsbs_load config --target=<db-name> --data-source=[FILE|SIMULATOR]
例如,为TimescaleDB生成一个示例,从文件加载数据:
$ tsbs_load config --target=timescaledb --data-source=FILE
示例配置已写入:./config.yaml
然后,您可以使用生成的配置文件运行tsbs_load:
$ tsbs_load load timescaledb --config=./config.yaml
有关如何使用tsbs_load的更多详细信息,请查看补充文档
使用特定数据库的tsbs_load_*
可执行文件
TSBS通过使用前一步生成的数据作为输入,并将其用于特定数据库的命令行程序来测量插入/写入性能。在可以共享插入程序的范围内,我们已尽力做到这一点(例如,TimescaleDB加载器可以根据需要用于常规PostgreSQL数据库)。每个加载器都共享一些通用标志 -- 例如,批量大小(一起插入的读数数量)、工作线程(并发插入客户端的数量)、连接详细信息(主机和端口)等 -- 但它们也有特定于数据库的调优标志。要查找特定数据库的标志,请使用-help
标志(例如,tsbs_load_timescaledb -help
)。
以下是将数据加载到需要SSL的远程timescaledb实例的示例,使用按照上述说明创建的gzip压缩数据集:
cat /tmp/timescaledb-data.gz | gunzip | tsbs_load_timescaledb \
--postgres="sslmode=require" --host="my.tsdb.host" --port=5432 --pass="password" \
--user="benchmarkuser" --admin-db-name=defaultdb --workers=8 \
--in-table-partition-tag=true --chunk-time=8h --write-profile= \
--field-index-count=1 --do-create-db=true --force-text-format=false \
--do-abort-on-exist=false
为了简化测试,尤其是在本地测试时,我们还提供了 scripts/load/load_<database>.sh
脚本,其中为一些数据库预设了许多合理的默认标志。
因此,要加载数据到TimescaleDB,请确保TimescaleDB正在运行,然后使用:
# 将使用2个客户端,批量大小为10k,从/tmp目录下名为timescaledb-data.gz的文件中插入数据
$ NUM_WORKERS=2 BATCH_SIZE=10000 BULK_DATA_DIR=/tmp \
scripts/load/load_timescaledb.sh
这将创建一个名为 benchmark
的新数据库来存储数据。如果该数据库已存在,它将覆盖该数据库;如果你不希望发生这种情况,请为上述命令提供一个不同的 DATABASE_NAME
。
使用 load_timescaledb.sh
写入远程主机的示例:
# 将使用2个客户端,批量大小为10k,从/tmp目录下名为timescaledb-data.gz的文件中插入数据
$ NUM_WORKERS=2 BATCH_SIZE=10000 BULK_DATA_DIR=/tmp DATABASE_HOST=remotehostname
DATABASE_USER=user DATABASE \
scripts/load/load_timescaledb.sh
默认情况下,每10秒打印一次有关加载性能的统计信息,当完整数据集加载完成时,看起来是这样的:
time,per. metric/s,metric total,overall metric/s,per. row/s,row total,overall row/s
# ...
1518741528,914996.143291,9.652000E+08,1096817.886674,91499.614329,9.652000E+07,109681.788667
1518741548,1345006.018902,9.921000E+08,1102333.152918,134500.601890,9.921000E+07,110233.315292
1518741568,1149999.844750,1.015100E+09,1103369.385320,114999.984475,1.015100E+08,110336.938532
摘要:
使用8个工作线程在936.525765秒内加载了1036800000个指标(平均速率1107070.449780/秒)
使用8个工作线程在936.525765秒内加载了103680000行(平均速率110707.044978/秒)
除最后两行外,所有数据都以CSV格式呈现,标题中包含列名。这些列名对应:
- 时间戳,
- 该时期内每秒的指标数,
- 插入的总指标数,
- 总体每秒指标数,
- 该时期内每秒的行数,
- 总行数,
- 总体每秒行数。
对于在插入时不使用行的数据库(如Cassandra),最后三个值始终为空(用 -
表示)。
最后两行是插入了多少指标(和行,如果适用)、耗时以及平均插入速率的摘要。
基准测试查询执行性能
要在TSBS中测量查询执行性能,你首先需要按照前面的部分加载数据并按照之前的描述生成查询。一旦数据加载完成并生成了查询,只需使用相应的 tsbs_run_queries_
二进制文件来测试相应的数据库:
$ cat /tmp/queries/timescaledb-cpu-max-all-eight-hosts-queries.gz | \
gunzip | tsbs_run_queries_timescaledb --workers=8 \
--postgres="host=localhost user=postgres sslmode=disable"
你可以更改 --workers
标志的值来控制同时运行的并行查询级别。结果输出将类似于:
1000个查询使用8个工作线程完成运行:
TimescaleDB 所有字段的最大CPU,随机8台主机,随机12小时,每1小时:
最小值: 51.97ms, 中位数: 757.55, 平均值: 2527.98ms, 最大值: 28188.20ms, 标准差: 2843.35ms, 总和: 5056.0秒, 计数: 2000
所有查询 :
最小值: 51.97ms, 中位数: 757.55, 平均值: 2527.98ms, 最大值: 28188.20ms, 标准差: 2843.35ms, 总和: 5056.0秒, 计数: 2000
墙钟时间: 633.936415秒
输出给出了查询的描述和多个测量分组(可能因数据库而异)。
为了更方便地测试多个查询,我们提供了 scripts/generate_run_script.py
,它可以创建一个bash脚本,其中包含按顺序运行多种查询类型的命令。应将要生成的查询放在一个文件中,每行一个查询,并将路径提供给脚本。
例如,如果你有一个名为 queries.txt
的文件,内容如下:
last-loc
avg-load
high-load
long-driving-session
你可以生成一个名为 query_test.sh
的运行脚本:
# 为TimescaleDB生成运行脚本,使用 queries.txt 中的查询
# 生成的查询文件位于 /tmp/queries 目录,使用8个工作线程
$ python generate_run_script.py -d timescaledb -o /tmp/queries \
-w 8 -f queries.txt > query_test.sh
生成的脚本文件将如下所示:
#!/bin/bash
# 查询
cat /tmp/queries/timescaledb-last-loc-queries.gz | gunzip | query_benchmarker_timescaledb --workers=8 --limit=1000 --hosts="localhost" --postgres="user=postgres sslmode=disable" | tee query_timescaledb_timescaledb-last-loc-queries.out
cat /tmp/queries/timescaledb-avg-load-queries.gz | gunzip | query_benchmarker_timescaledb --workers=8 --limit=1000 --hosts="localhost" --postgres="user=postgres sslmode=disable" | tee query_timescaledb_timescaledb-avg-load-queries.out
cat /tmp/queries/timescaledb-high-load-queries.gz | gunzip | query_benchmarker_timescaledb --workers=8 --limit=1000 --hosts="localhost" --postgres="user=postgres sslmode=disable" | tee query_timescaledb_timescaledb-high-load-queries.out
解压/tmp/queries/timescaledb-long-driving-session-queries.gz文件并通过管道传输到query_benchmarker_timescaledb,使用8个工作线程,限制为1000,主机为"localhost",PostgreSQL连接参数为"user=postgres sslmode=disable",然后将输出保存到query_timescaledb_timescaledb-long-driving-session-queries.out文件。
查询验证(可选)
此外,每个tsbs_run_queries_
二进制文件都允许打印实际的查询结果,以便您可以比较不同数据库的结果是否相同。使用-print-responses
标志将返回结果。
附录I:查询类型
运维 / 仅CPU
查询类型 | 描述 |
---|---|
single-groupby-1-1-1 | 对1台主机的1个指标进行简单聚合(MAX),每5分钟一次,持续1小时 |
single-groupby-1-1-12 | 对1台主机的1个指标进行简单聚合(MAX),每5分钟一次,持续12小时 |
single-groupby-1-8-1 | 对8台主机的1个指标进行简单聚合(MAX),每5分钟一次,持续1小时 |
single-groupby-5-1-1 | 对1台主机的5个指标进行简单聚合(MAX),每5分钟一次,持续1小时 |
single-groupby-5-1-12 | 对1台主机的5个指标进行简单聚合(MAX),每5分钟一次,持续12小时 |
single-groupby-5-8-1 | 对8台主机的5个指标进行简单聚合(MAX),每5分钟一次,持续1小时 |
cpu-max-all-1 | 对单台主机1小时内所有CPU指标进行每小时聚合 |
cpu-max-all-8 | 对8台主机1小时内所有CPU指标进行每小时聚合 |
double-groupby-1 | 跨时间和主机进行聚合,给出24小时内每台主机每小时1个CPU指标的平均值 |
double-groupby-5 | 跨时间和主机进行聚合,给出24小时内每台主机每小时5个CPU指标的平均值 |
double-groupby-all | 跨时间和主机进行聚合,给出24小时内每台主机每小时所有(10个)CPU指标的平均值 |
high-cpu-all | 所有主机中某个指标高于阈值的所有读数 |
high-cpu-1 | 特定主机中某个指标高于阈值的所有读数 |
lastpoint | 每台主机的最后一次读数 |
groupby-orderby-limit | 随机选择的端点之前的最后5个聚合读数(跨时间) |
物联网
查询类型 | 描述 |
---|---|
last-loc | 获取每辆卡车的实时(即最新)位置 |
low-fuel | 获取所有燃料不足(低于10%)的卡车 |
high-load | 获取当前负载高(超过90%负载容量)的卡车 |
stationary-trucks | 获取所有静止不动的卡车(最近10分钟内平均速度低) |
long-driving-sessions | 获取在过去4小时内没有至少休息20分钟的卡车 |
long-daily-sessions | 获取在过去24小时内驾驶超过10小时的卡车 |
avg-vs-projected-fuel-consumption | 计算每个车队的平均燃料消耗与预计燃料消耗的对比 |
avg-daily-driving-duration | 计算每个司机的平均每日驾驶时长 |
avg-daily-driving-session | 计算每个司机的平均每日驾驶次数 |
avg-load | 计算每个车队每种卡车型号的平均负载 |
daily-activity | 获取每个车队每天卡车处于活跃状态(相对于停运状态)的小时数 |
breakdown-frequency | 按卡车型号计算故障频率 |
贡献
我们欢迎社区贡献,以使TSBS变得更好!
您可以通过提出issue提供任何建议或报告错误,或者通过fork此仓库,做出自己的贡献,并提交拉取请求来帮助我们。
在我们接受任何贡献之前,Timescale贡献者需要签署贡献者许可协议(CLA)。通过签署CLA,我们可以确保社区在使用您的贡献时是自由和有信心的。