近日,咱们曾发布测试报告 DolphinDB与InfluxDB对比测试报告,此报告测试于2018年底。当时的结果显示,DolphinDB Database 的查询性能领先InfluxDB一到三个数据量级,数据导入性能领先一个数量级,数据导出性能相差不大。时隔一年多,DolphinDB与InfluxDB都作了很多功能和性能上的优化,二者的性能究竟有何变化?咱们从新对DolphinDB和InfluxDB进行对比测试,测试涵盖数据导入导出、数据查询和磁盘空间占用三个方面。测试的数据集也涵盖了日益流行的物联网数据集,以及规模更大的金融大数据集。git
1、系统概述
DolphinDBgithub
DolphinDB 是以 C++ 编写的一款分析型的高性能分布式时序数据库,使用高吞吐低延迟的列式内存引擎,集成了功能强大的编程语言和高容量高速度的流数据分析系统,可在数据库中进行复杂的编程和运算,显著减小数据迁移所耗费的时间。sql
DolphinDB 经过内存引擎、数据本地化、细粒度数据分区和并行计算实现高速的分布式计算,内置流水线、 Map Reduce 和迭代计算等多种计算框架,使用内嵌的分布式文件系统自动管理分区数据及其副本,为分布式计算提供负载均衡和容错能力。数据库
DolphinDB 支持类标准 SQL 的语法,提供相似于 Python 的脚本语言对数据进行操做,也提供其它经常使用编程语言的 API,在金融领域中的历史数据分析建模与实时流数据处理,以及物联网领域中的海量传感器数据处理与实时分析等场景中表现出色。编程
InfluxDBwindows
InfluxDB 是目前最为流行的高性能开源时间序列数据库,由 Go 语言写成。它的核心是一款定制的存储引擎 TSM Tree,对时间序列数据作了优化,优先考虑插入和查询数据的性能。缓存
InfluxDB 使用类 SQL 的查询语言 InfluxQL,并提供开箱即用的时间序列数学和统计函数;同时对外提供基于 HTTP 的接口来支持数据的插入与查询性能优化
InfluxDB 容许用户定义数据保存策略 (Retention Policies) 来实现对存储超过指定时间的数据进行删除或者降采样,被普遍应用于存储系统的监控数据,IoT 行业的实时数据等场景。负载均衡
2、测试环境
因为 InfluxDB 集群版本闭源,在测试中 DolphinDB 与 InfluxDB 均使用单机模式。框架
主机:DELL OptiPlex 7060
CPU :Intel Core i7-8700(6 核 12 线程 3.20 GHz)
内存:32 GB (8GB × 4, 2666 MHz)
硬盘:2T HDD (222 MB/s 读取;210 MB/s 写入)
OS:Ubuntu 16.04 LTS
测试使用的 DolphinDB 版本为 Linux v0.89 (2019.01.31),最大内存设置为 28GB
。
测试使用的 InfluxDB 版本为 1.7.5,根据 InfluxDB 官方配置文件中的说明,结合测试机器的实际硬件对配置作了优化,主要将 wal-fsync-delay
调节为适合机械硬盘的 100ms
,将 cache-max-memory-size
设置为 28GB
,以及将 series-id-set-cache-size
设置为 400
。
具体修改的配置详见附录中 influxdb.conf
文件。
3、数据集
本报告测试了小数据量级(4.2GB)和大数据量级(270GB)下DolphinDB和InfluxDB的表现状况,如下是两个数据的表结构和分区方法:
4.2GB设备传感器记录小数据集(csv格式,3千万条)
咱们使用物联网设备的传感器信息做为小数据集来测试,数据集包含3000个设备在2016年11月15日到2016年11月19日10000个时间间隔上的传感器时间,设备ID,电池,内存,CPU等时序统计信息。数据集共30,000,000条数据,包含包含一张设备信息表device_info和一张设备传感器信息记录表readings。
数据来源:https://docs.timescale.com/v1.1/tutorials/other-sample-datasets
下载地址:https://timescaledata.blob.core.windows.net/datasets/devices_big.tar.gz
如下是readings表在DolphinDB和InfluxDB中的结构:
咱们在 DolphinDB database 中的分区方案是将 time
做为分区的第一个维度,按天分为 4 个区,分区边界为 [2016.11.15 00:00:00, 2016.11.16 00:00:00, 2016.11.17 00:00:00, 2016.11.18 00:00:00, 2016.11.19 00:00:00]
;再将 device_id
做为分区的第二个维度,天天一共分 10 个区,最后每一个分区所包含的原始数据大小约为 100 MB
。
InfluxDB 中使用 Shard Group 来存储不一样时间段的数据,不一样 Shard Group 对应的时间段不会重合。一个 Shard Group 中包含了大量的 Shard, Shard 才是 InfluxDB 中真正存储数据以及提供读写服务的结构。InfluxDB 采用了 Hash 分区的方法将落到同一个 Shard Group 中的数据再次进行了一次分区,即根据 hash(Series) 将时序数据映射到不一样的 Shard,所以咱们使用如下语句手动指定每一个 Shard Group 的 Duration,在时间维度上按天分区。
create retention policy one_day on test duration inf replication 1 shard duration 1d default
270GB股票交易大数据集(csv格式,23个csv,65亿条)
咱们将纽约证券交易所(NYSE)提供的 2007.08.01 - 2007.08.31 一个月的股市 Level 1 报价数据做为大数据集进行测试,数据集包含 8000 多支股票在一个月内的交易时间
,股票代码
,买入价
,卖出价
,买入量
,卖出量
等报价信息。
数据集中共有 65 亿(65,6169,3704)条报价记录,一个 CSV 中保存一个交易日的记录,该月共 23 个交易日,未压缩的 CSV 文件共计 270 GB。
数据来源:NYSE Exchange Proprietary Market Data
如下是TAQ表在DolphinDB和InfluxDB中的结构:
在 DolphinDB database 中咱们按date(日期)
,symbol(股票代码)
进行分区,天天再根据 symbol 分为 100 个分区,每一个分区大概 120 MB 左右。
在InfluxDB中使用与小数据集相同的策略。
4、数据导入导出测试
1. 导入数据
DolphinDB使用如下脚本导入:
timer { for (fp in fps) { loadTextEx(db, `taq, `date`symbol, fp, ,schema) print now() + ": 已导入 " + fp } }
4.2 GB 设备传感器记录小数据集共3 千万条数据导入用时 20 秒
, 平均速率 150 万条/秒
。
270 GB 股票交易大数据集共 65 亿条数据(TAQ20070801 - TAQ20070831
23 个文件),导入用时 38 分钟
。
InfluxDB 自己不支持直接导入 CSV,只能经过 HTTP API 或者influx -import
的方式导入,出于导入性能考虑,咱们选择将 CSV 中的每一行先转换为 Line Protocol 格式,如:
readings,device_id=demo000000,battery_status=discharging,bssid=A0:B1:C5:D2:E0:F3,ssid=stealth-net battery_level=96,battery_temperature=91.7,cpu_avg_1min=5.26,cpu_avg_5min=6.172,cpu_avg_15min=6.51066666666667,mem_free=650609585,mem_used=349390415,rssi=-42 1479211200
并添加以下文件头:
# DDL CREATE DATABASE test CREATE RETENTION POLICY one_day ON test DURATION INF REPLICATION 1 SHARD DURATION 1d DEFAULT # DML # CONTEXT-DATABASE:test # CONTEXT-RETENTION-POLICY:one_day
保存到磁盘中,再经过如下命令导入:
influx -import -path=/data/devices/readings.txt -precision=s -database=test
通过转换后,4.2 GB 设备传感器记录小数据集共3 千万
条数据导入用时25 分钟 10 秒
, 平均速率2 万条/秒
。
将 TAQ 数据插入到 InfluxDB 的过程当中,若是屡次插入时间相同 (1185923302),tag 相同的记录 (这里是 symbol, mode, ex),好比下面两条,即便 value 不一样 (bid, ofr, bidsiz, ofrsiz),后面的那一条记录也会覆盖前面的记录,最终数据库中只保留了最后一条记录。
taq,symbol=A,mode=12,ex=T bid=37,ofr=54.84,bidsiz=1,ofrsiz=1 1185923302 taq,symbol=A,mode=12,ex=T bid=37,ofr=38.12,bidsiz=1,ofrsiz=1 1185923302
要解决这个问题文档(InfluxDB frequently asked questions | InfluxData Documentation)里给出了两种方法,一种是新增一个 tag 来对相同时间的数据设置不一样的 tag value 手动区分,另外一种是强行微调时间戳使其不一样。
设置不一样的 tag value 手动区分这种方法只适用于数据彻底按照时间顺序插入的状况。在使用其余的编程语言插入数据的过程当中判断该条记录的时间戳是否与上一条记录彻底相同,并在插入数据库时手动指定不一样的 tag value 做区分,效率低下且操做繁琐;若数据并不是彻底按照时间顺序插入,则没法判断当前的时间点是否已经有数据记录的存在,是否会覆盖先前的数据。
咱们在本次测试中使用强行微调时间戳的方法,因为原有 TAQ 交易记录的时间精度为秒,所以咱们能够在将 CSV 的数据转换至 Line Protocol 格式的过程当中,在原来精确到秒的时间戳的基础上,随机加上一个毫秒值,产生一个新的精度为毫秒的伪时间戳,以防止数据冲突。
通过转换后,270 GB 股票交易大数据集所包含的65 亿
条数据导入用时65 小时
,平均导入速率2.7 万条/秒
。
导入性能对好比下表所示:
结果显示,DolphinDB 的导入速率远大于 InfluxDB 的导入速率。在导入过程当中还能够观察到,随着时间的推移,InfluxDB 的导入速率不断降低,而 DolphinDB 保持稳定。并且 InfluxDB 在导入数据时须要先编写代码将 CSV 格式文件转换为 InfluxDB 的 Line Protocol 格式,复杂繁琐,还会产生多余的中间文件占用大量空间。
2. 导出数据
在 DolphinDB 中使用saveText((select * from readings), '/data/devices/readings_dump.csv')
进行数据导出,用时仅需 28 秒。
在 InfluxDB 中若使用influx -database 'test' -format csv -execute "select * from readings > /data/devices/export_15.csv
进行数据导出内存占用会超过 30 GB,最终引起fatal error: runtime: out of memory
,最后采用分时间段导出 CSV 的方法。代码以下所示:
for i in 1{5..8}; do time influx -database 'test' -format csv -execute "select * from readings where '2016-11-$i 00:00:00' <= time and time < '2016-11-$((i+1)) 00:00:00'" > /data/devices/export_$i.csv done
总耗时5 min 31 s。
除性能差距悬殊以外,InfluxDB 的 CSV 数据导出操做复杂,容易发生内存溢出问题,并且导出的 CSV 文件首行无字段名称,用户体验远不如 DolphinDB。
导出性能对好比下表所示:
5、磁盘空间占用对比
导入数据后,DolphinDB和InfluxDB占用空间以下表所示:
小数据集中 DolphinDB 的空间利用率与 InfluxDB 相近,两款数据库都对数据进行了压缩存储,压缩率大体处于同一个数量级,在 20% - 30% 之间;大数据集中 InfluxDB 对数据的压缩效果很差,占用空间为 DolphinDB 的两倍。
6、数据库查询性能测试
咱们一共对比了如下八种类别的查询:
- 点查询指定某一字段取值进行查询
- 范围查询针对单个或多个字段根据时间区间查询数据
- 精度查询针对不一样的标签维度列进行数据聚合,实现高维或者低维的字段范围查询功能
- 聚合查询是指时序数据库有提供针对字段进行计数、平均值、求和、最大值、最小值、滑动平均值、标准差、归一等聚合类 API 支持
- 对比查询按照两个维度将表中某字段的内容从新整理为一张表格(第一个维度做为列,第二个维度做为行)
- 抽样查询指的是数据库提供数据采样的 API,能够为每一次查询手动指定采样方式进行数据的稀疏处理,防止查询时间范围太大数据量过载的问题
- 关联查询对不一样的字段,在进行相同精度、相同的时间范围进行过滤查询的基础上,筛选出有关联关系的字段并进行分组
- 经典查询是实际业务中经常使用的查询
查询测试的时间包含磁盘 I/O 的时间,为保证测试公平,每次启动程序测试前均经过 Linux 系统命令sync; echo 1,2,3 | tee /proc/sys/vm/drop_caches
分别清除系统的页面缓存、目录项缓存和硬盘缓存,启动程序后依次执行全部查询语句执行一次。
4.2GB设备传感器记录小数据集查询测试结果以下表所示:
查询脚本见附录。
结果显示,DolphinDB的查询性能远超于InfluxDB。在功能上,InfluxDB不如DolphinDB强大,好比:
- InfluxDB不支持对比查询和表链接,没法完成许多常规SQL数据库支持的查询。
- InfluxDB 不支持对除 time 之外的 tag, field 进行排序,即不能
select * from taq order by <some-field>
,详见[feature request] ORDER BY tag values · Issue #3954 · influxdata/influxdb。 - InfluxDB中函数的参数只能是某一个 field ,而不能是 field 的表达式(
field1 + field2
等)所以只能用 subquery 先计算出表达式的值再套用函数,很是繁琐,并且须要在子查询和父查询的 where 子句中重复指定时间范围,不然会从最旧的数据记录的时间开始一直扫描到当前时间。 InfluxDB 和 DolphinDB 第14个查询语句的对好比下:
//14. 经典查询:计算某时间段内高负载高电量设备的内存大小 //DolphinDB select max(date(time)) as date, max(mem_free + mem_used) as mem_all from readings where time <= 2016.11.18 21:00:00, battery_level >= 90, cpu_avg_1min > 90 group by hour(time), device_id //InfluxDB select max(mem_total) from ( select mem_free + mem_used as mem_total from readings where time <= '2016-11-18 21:00:00' and battery_level >= 90 and cpu_avg_1min > 90 ) where time <= '2016-11-18 21:00:00' group by time(1h), device_id
270GB股票交易大数据查询测试结果以下表所示:
查询脚本见附录。
结果显示,某些查询,二者的性能差异不大,但某些查询,DolphinDB比InfluxDB快将近100到200倍。
在测试中,咱们发现:
- InfluxDB在第2个查询中,对于where条件中选择的多个非连续的时间分区返回的结果为空,而不是各个时间分区的结果的总和。InfluxDB中第2个查询的代码以下所示:
//2. 范围查询:查询某时间段内的某些股票的全部记录 select symbol, time, bid, ofr from taq where (symbol = 'IBM' or symbol = 'MSFT' or symbol = 'GOOG' or symbol = 'YHOO') and ('2007-08-03 01:30:00' <= time and time < '2007-08-03 01:30:59') //该语句返回的结果不为空 select symbol, time, bid, ofr from taq where (symbol = 'IBM' or symbol = 'MSFT' or symbol = 'GOOG' or symbol = 'YHOO') and (('2007-08-03 01:30:00' <= time and time < '2007-08-03 01:30:59') or ('2007-08-04 01:30:00' <= time and time < '2007-08-04 01:30:59')) //扩展了时间范围后,该语句返回的结果反而为空
- 在InfluxDB中没法完成第8个查询。DolphinDB的第8个查询的代码以下所示:
//8. 经典查询:计算某天每一个股票每分钟最大卖出与最小买入价之差 select symbol, max(ofr) - min(bid) as gap from taq where '2007-08-03' <= time and time < '2007-08-04' and bid > 0 and ofr > bid group by symbol, time(1m)
InfluxDB会抛出异常,ERR: mixing multiple selector functions with tags or fields is not supported
,即不能在select语句中同时使用max和min函数,而DolphinDB能够正常执行。
- InfluxDB 对时间进行 group by 以后返回的结果包含了全部的时间段,即便当前时间段内无有效数据也返回(以下所示),对于稀疏数据增长了处理复杂度且下降性能,而DolphinDB只返回包含有效数据的时间段。
2007-07-31T23:02:00Z 22.17 54.84 2007-07-31T23:03:00Z 2007-07-31T23:04:00Z 2007-07-31T23:05:00Z 2007-07-31T23:06:00Z 2007-07-31T23:07:00Z 2007-07-31T23:08:00Z 37 38.12 2007-07-31T23:09:00Z 2007-07-31T23:10:00Z 37.03 38.12
7、其余方面的比较
DolphinDB 除了在基准测试中体现出优越的性能以外,还具备以下优点:
- 语言上,InfluxDB 经过 InfluxQL 来操做数据库,这是一种类 SQL 语言;而 DolphinDB 内置了完整的脚本语言,不只支持 SQL 语言,并且支持命令式、向量化、函数化、元编程、RPC 等多种编程范式,能够轻松实现更多的功能。
- 数据导入方面,InfluxDB 对于特定文件格式数据例如 CSV 文件的批量导入没有很好的官方支持,用户只能经过开源第三方工具或本身实现文件的读取,规整为 InfluxDB 指定的输入格式,再经过 API 进行批量导入。单次只能导入 5000 行,不只操做复杂,效率也极其低下;而DolphinDB提供了ploadText、loadText、loadTextEx函数,能够直接在脚本中导入CSV文件,对用户更加友好,而且效率更高。
- 功能上,InfluxDB不支持表链接,部分常规查询没法完成;而DolphinDB不只支持经常使用的表链接功能,还对asof join和window join等非同时链接作了不少性能优化。
- InfluxDB对时间序列的分组(group by)的最大分组是星期(week);而DolphinDB支持对全部内置时间类型进行分组,最大单位为月(month)。InfluxDB在查询中函数的参数只能是某一个字段,不能是字段的表达式,而DolphinDB无此限制。
- DolphinDB提供了600多个内置函数,可知足金融领域的历史数据建模与实时流数据处理以及物联网领域中的实时监控与实时分析处理等不一样场景的需求,而且大部分聚合函数、处理时序数据须要的领先、滞后、累计窗口、滑动窗口函数都作了性能优化。
- DolphinDB 的集群版本支持事务,并且在一个分区的多个副本写入时,保证强一致性。
在本次的全部测试项目中,DolphinDB 表现更出色,主要测试结论以下:
- 数据导入方面,小数据集状况下 DolphinDB 的导入性能是 InfluxDB 的 75 倍 ,大数据集的状况下导入性能大约是其 100 倍 ,且 InfluxDB 原生不支持 CSV 导入,须要手动转换为 Line Protocol 格式。
- 数据导出方面,DolphinDB 的性能是 InfluxDB 的 11 倍 左右,且 InfluxDB 在导出大批量数据为 CSV 格式时容易产生内存溢出问题。
- 磁盘空间占用方面,DolphinDB 占用的空间老是小于等于 InfluxDB 占用的空间。
- 查询功能方面,InfluxDB 不支持对比查询,不支持表链接,不支持对除 time 之外的 tag, field 进行排序,且函数的参数只能是某一个 field ,而不能是 field 的表达式,功能上有极大的限制,有多个测试样例没法在 InfluxDB 中实现;而 DolphinDB 对数据的处理则更加的灵活、方便。
- 查询性能方面,DolphinDB 在 2 个 测试样例中性能超过 InfluxDB 1000多倍 ;在 6 个 测试样例中性能超过 InfluxDB 50多倍 ;在 2 个 测试样例中性能为 InfluxDB 10多倍 ; 其他全部测试样例性能也所有优于 InfluxDB。
附录
数据预览(取前20行)
- readings
- readings(Line Protocol)
- readings表转换为Line Protocol脚本
- TAQ
- TAQ(Line Protocol)
- TAQ表转换为Line Protocol脚本
DolphinDB
InfluxDB