金融市场高频数据应当如何管理——DolphinDB与pickle的性能对比测试和分析
金融市场L1/L2的报价和交易数据是量化交易研究非常重要的数据。国内全市场L1/L2的历史数据约为20~50T,每日新增的数据量约为20~50G。传统的关系数据库如MS SQL Server或MySQL均无法支撑这样的数据量级,即便分库分表,查询性能也远远无法达到要求。例如Impala和Greenplum的数据仓库,以及例如HBase的NoSQL数据库,可以解决这个数据量级的存储,但是这类通用的存储引擎缺乏对时序数据的友好支持,在查询和计算方面都存在严重的不足,对量化金融普遍采用的Python的支持也极为有限。
数据库的局限性使得一部分用户转向文件存储。HDF5,Parquet和pickle是常用的二进制文件格式,其中pickle作为Python对象序列化/反序列的协议非常高效。由于Python是量化金融和数据分析的常用工具,因此许多用户使用pickle存储高频数据。但文件存储存在明显的缺陷,譬如大量的数据冗余,不同版本之间的管理困难,不提供权限控制,无法利用多个节点的资源,不同数据间的关联不便,数据管理粒度太粗,检索和查询不便等等。
目前,越来越多的券商和私募开始采用高性能时序数据库DolphinDB来处理高频数据。DolphinDB采用列式存储,并提供多种灵活的分区机制,可充分利用集群中每个节点的资源。DolphinDB的大量内置函数对时序数据的处理和计算非常友好,解决了传统关系数据库或NoSQL数据库处理时序数据方面的局限性。使用DolphinDB处理高频数据,既可以保证查询与计算的超高性能,又可以提供数据管理、权限控制、并行计算、数据关联等数据库的优势。
本文测试DolphinDB和pickle在数据读取方面的性能。与使用pickle文件存储相比,直接使用DolphinDB数据库,数据读取速度可多可提升10倍以上;若为了考虑与现有Python系统的集成,使用DolphinDB提供的Python API读取数据,速度多有2~3倍的提升。有关DolphinDB数据库在数据管理等方面的功能,读者可参考DolphinDB的在线文档或教程。
- 1. 测试场景和测试数据
- 2. 测试环境
- 3. 测试方法
- 3.1 测试DolphinDB
- 3.2 测试DolphinDB的Python API
- 3.3 测试pickle文件
- 4. 测试结果分析
- 4.1 DolphinDB的性能优势来源
- 4.2 字符串对性能的影响
- 4.3 多任务并发下的性能对比
- 5. 库内分析的必要性
- 6. 结论和展望
1. 测试场景和测试数据
本次测试使用了以下两个数据集。
- 数据集1是美国股市一天(2007.08.23) Level 1的报价和交易数据。该数据共10列,其中2列是字符串类型,其余是整型或浮点数类型,存储在dolphindb中的表结构如下表,一天的数据约为2亿3000万行。csv文件大小为9.5G,转换为pickle文件后大小为11.8G。
列名 | 类型 |
---|---|
symbol | SYMBOL |
date | DATE |
time | SECOND |
bid | DOUBLE |
ofr | DOUBLE |
bidsiz | INT |
ofrsiz | INT |
mode | INT |
ex | CHAR |
mmid | SYMBOL |
- 数据集2是中国股市3天(2019.09.10~2019.09.12)的Level 2报价数据。数据集总共78列,其中2列是字符串类型,存储在dolphindb中的表结构如下表,一天的数据约为2170万行。一天的csv文件大小为11.6G,转换为pickle文件后大小为12.1G。
列名 | 类型 | 列名 | 类型 |
---|---|---|---|
UpdateTime | TIME | TotalBidVol | INT |
TradeDate | DATE | WAvgBidPri | DOUBLE |
Market | SYMBOL | TotalAskVol | INT |
SecurityID | SYMBOL | WAvgAskPri | DOUBLE |
PreCloPrice | DOUBLE | IOPV | DOUBLE |
OpenPrice | DOUBLE | AskPrice1~10 | DOUBLE |
HighPrice | DOUBLE | AskVolume1~10 | INT |
LowPrice | DOUBLE | BidPrice1~10 | DOUBLE |
LastPrice | DOUBLE | BidVolume1~10 | INT |
TradNumber | INT | NumOrdersB1~10 | INT |
TradVolume | INT | NumOrdersS1~10 | INT |
Turnover | DOUBLE | LocalTime | TIME |
DolphinDB database的数据副本数设为2。将这两个数据集写入DolphinDB后,磁盘占用空间为10.6G,单份数据仅占用5.3G,压缩比约为8:1。pickle文件没有采用压缩存储。测试发现pickle文件压缩后,加载时间大幅延长。
对比测试查询一天的数据。对DolphinDB Python API与pickle,记录从客户端发出查询到接收到数据并转换成Python pandas的DataFrame对象的耗时。
- 对于DolphinDB Python API,整个过程包括三个步骤:(1)从DolphinDB数据库查询数据耗时,即若不使用Python API而直接使用DolphinDB查询所需耗时;(2)把查询到的数据从DolphinDB数据节点发送到python API客户端需要的时间;(3) 在客户端将数据反序列化成pandas DataFrame需要的时间。
- 对于pickle,耗时为使用pickle模块加载pickle数据文件所需要的时间。
2. 测试环境
测试使用的三台服务器硬件配置如下:
主机:PowerEdge R730xd
CPU:E5-2650 24cores 48线程
内存:512G
硬盘:HDD 1.8T * 12
网络:万兆以太网
OS:CentOS Linux release 7.6.1810
本次测试使用的是DolphinDB多服务器集群模式。共使用3台服务器,每台服务器部署2个数据节点,每个节点分配2个10K RPM的HDD磁盘,内存使用限制为32G,线程数设置为16。数据库的副本数设置为2。测试的客户机安排在其中的一台服务器上。
本次测试的DolphinDB服务器版本是1.30.0,Python API for DolphinDB的版本是1.30.0.4。
3. 测试方法
读写文件之后,操作系统会缓存相应的文件。从缓存读取数据,相当于从内存读取数据,这会影响测试结果。因此每一次测试前,都会清除操作系统的缓存和DolphinDB 的缓存。为了对比,也测试有缓存时的性能,即不存在磁盘IO瓶颈时的性能。
3.1 测试DolphinDB
测试代码如下:
#读取Level 1数据集一天的数据
timer t1 = select * from loadTable("dfs://TAQ", "quotes") where TradeDate = 2007.08.23
#读取Level 2数据集一天的数据
timer t2 = select * from loadTable("dfs://DataYesDB", "tick") where TradeDate = 2019.09.10
相关文章