金融市场高频数据应当如何管理——DolphinDB与pickle的性能对比测试和分析
本文提供文章标题与基础信息,并围绕DolphinDB与pickle在高频金融数据读取上的对比测试展开。
Source: https://dolphindb.cn/blogs/286
What this page covers
- 高频金融L1/L2数据规模与传统方案局限。
- DolphinDB设计要点与测试目标。
- 测试场景、数据集定义与对比口径。
- 测试环境与软件版本信息。
- 清缓存原因与测试方法(含代码步骤)。
- 基础结果表:DolphinDB、Python API与pickle耗时对比。
- 瓶颈分析、字符串影响、并发对比、库内分析与结论展望。
技能认证特训营第二期报名促销
页面顶部提供培训营报名入口,并提示限时优惠。
- 页面包含“技能认证特训营第二期”的报名入口信息。
- 页面包含与报名相关的促销/优惠提示。
文章标题与基础信息
展示文章标题,并标注作者/来源与发布日期。
- 文章来源标识为 DolphinDB。
- 文章发布日期为 2021-05-18。
背景:高频金融数据规模与传统数据库/文件存储的局限
说明L1/L2高频数据规模,并讨论关系数据库、通用数据仓库/NoSQL与文件存储在该场景下的不足。
- 国内全市场L1/L2历史数据规模约20~50T。
- 国内全市场L1/L2每日新增数据约20~50G/日。
- 文中认为MS SQL Server或MySQL难以支撑该数据量级的查询要求。
- 文中认为部分数据仓库/NoSQL可解决存储,但对时序查询计算与Python支持存在不足。
- 文中列举HDF5、Parquet、pickle等常用二进制文件格式。
DolphinDB概述与本文测试目标
介绍DolphinDB面向高频数据的设计要点,并给出与pickle读取性能对比的结论与参考文档链接。
- 文中描述DolphinDB采用列式存储。
- 文中描述DolphinDB提供多种分区机制以利用集群节点资源。
- 文中给出与pickle对比的读取性能提升结论(不同读取方式提升幅度不同)。
- 文中提供DolphinDB在线文档链接。
- 文中提供DolphinDB教程(Gitee)链接。
文章目录(外部链接)
提供指向文章各章节(如场景、环境、方法、结果与结论等)的链接目录。
- 目录链接覆盖测试场景相关内容。
- 目录链接覆盖测试环境与测试方法相关内容。
- 目录链接覆盖结果分析与结论相关内容。
测试场景和测试数据
定义两个数据集的结构与规模,并描述写入DolphinDB后的副本/占用/压缩情况,以及对比测试口径与计时拆分。
- 数据集1为美国股市一天(2007.08.23)的Level 1报价和交易数据。
- 数据集1约2亿3000万行。
- 数据集1 CSV大小为9.5G,转为pickle后为11.8G。
- 数据集2为中国股市3天(2019.09.10~2019.09.12)的Level 2报价数据。
- 数据集2单日约2170万行,单日CSV为11.6G,转为pickle后为12.1G。
测试环境
列出硬件、网络、操作系统以及DolphinDB集群部署方式与版本信息。
- 服务器型号为 PowerEdge R730xd,CPU为E5-2650(24 cores/48线程),内存512G。
- 存储为HDD 1.8T * 12,网络为万兆以太网,系统为CentOS Linux 7.6.1810。
- 部署为多服务器集群:3台服务器;每台部署2个数据节点。
- 测试使用的DolphinDB服务器版本为1.30.0,Python API版本为1.30.0.4。
测试方法
说明清缓存必要性,并给出DolphinDB查询、DolphinDB Python API与pickle读取的步骤与代码示例。
- 文中说明操作系统文件缓存会影响读性能测试,需要在测试前清缓存并对比缓存场景。
- 文中给出清理操作系统缓存命令:sudo sh -c "echo 1 > /proc/sys/vm/drop_caches"。
- 文中给出清理DolphinDB缓存命令:pnodeRun(clearAllCache)。
- 文中给出DolphinDB查询示例(按TradeDate过滤一天数据)。
- 文中给出DolphinDB Python API连接示例(含IP、端口与账号参数)。
测试结果分析:基础结果表
展示两数据集在无缓存/有缓存条件下,DolphinDB数据库查询、DolphinDB Python API与pickle读取的耗时对比结果表。
- 数据集1:DolphinDB数据库查询耗时为6秒(无缓存/有缓存均为6秒)。
- 数据集1:DolphinDB Python API耗时为38秒(无缓存)与35秒(有缓存)。
- 数据集1:pickle耗时为72秒(无缓存)与34秒(有缓存)。
- 数据集2:DolphinDB Python API耗时为22秒(无缓存/有缓存均为22秒)。
- 数据集2:pickle耗时为70秒(无缓存)与20秒(有缓存)。
DolphinDB的性能优势来源
从磁盘IO、网络传输、压缩与分布式存储、以及客户端协议等角度解释瓶颈与优化方向。
- 文中结论称:直接从DolphinDB数据库查询速度最快,超过pickle查询10倍以上。
- 文中指出pickle读取瓶颈主要在磁盘IO;有缓存时耗时主要为反序列化。
- 文中指出在该配置下,DolphinDB数据库查询部分瓶颈在网络而非磁盘IO。
- 文中描述DolphinDB与Python API客户端采用改良的pickle协议。
- 文中提出进一步优化方向包括升级网络或继续改良序列化/反序列化协议。
字符串对性能的影响
分析字符串字段对耗时的影响,并给出剔除字符串字段后的对比结果与SYMBOL机制说明。
- 数据集1无缓存时,DolphinDB Python API总耗时38秒,其中约80%耗费在pickle反序列化。
- 数据集1剔除两个字符串字段后,DolphinDB Python API耗时从38秒缩短到19秒。
- 数据集2剔除两个字符串字段后,DolphinDB Python API耗时从22秒缩减到20秒。
- 文中描述SYMBOL用于优化高重复度的字符串类型数据(如股票ID、交易所名称)。
- 文中描述SYMBOL通过字典存储不重复字符串,并在内部存储索引。
多任务并发下的性能对比
对比多进程并发读取下的耗时表现,并解释瓶颈与改进方向。
- 并发测试采用数据集2,并开启多个Python进程从pickle或DolphinDB加载数据。
- 3个并发pickle读取连接耗时约220秒左右(分别为220/222/219秒)。
- 3个连接访问不同服务器数据节点时,DolphinDB API耗时为28/35/31秒。
- 文中解释pickle并发读取耗时近线性增加,瓶颈为磁盘IO。
- 文中提出改进方向包括升级网络或引入传输压缩。
库内分析的必要性
建议尽量在数据库内完成清洗与分析,以减少传输与客户端开销,并描述DolphinDB脚本语言与分析能力覆盖范围。
- 文中称DolphinDB提供完整的多范式脚本语言,并包含千余个内置函数。
- 文中列举库内可支持时间序列、滑动窗口、关联、Pivoting与机器学习等常用功能。
- 文中示例对比:客户端pandas分析总耗时约50秒左右(表述为示例)。
- 文中估计:若各节点完成统计并仅合并少量结果,总耗时约2秒左右。
结论和展望
总结分布式、压缩、列式存储与协议改进带来的工程结论,并讨论网络瓶颈与数据类型设计建议。
- 文中结论称:数据库在管理便利/安全/可靠的同时,性能上超越裸文件是可行的。
- 文中指出Python API链路中,数据库查询耗时占比小,耗时主要在网络传输与序列化/反序列化。
- 文中建议通过库内分析降低传输数据量,以缓解“最后一公里”瓶颈。
- 文中提及可采用类似Apache Arrow的通用内存数据格式以降低序列化/反序列化开销。
- 文中建议在数据系统设计中尽可能避免字符串类型,重复度高时可用类似SYMBOL类型替代。
Facts Index
| Entity | Attribute | Value | Confidence |
|---|---|---|---|
| 技能认证特训营第二期 | 报名链接 | https://www.qingsuyun.com/h5/e/217471/5/ | high |
| 文章 | 发布日期 | 2021-05-18 | high |
| DolphinDB | 署名/来源标识 | DolphinDB | high |
| 国内全市场L1/L2历史数据 | 数据量规模 | 约20~50T | medium |
| 国内全市场L1/L2每日新增数据 | 数据量规模 | 约20~50G/日 | medium |
| MS SQL Server或MySQL | 对该数据量级的支撑能力 | 无法支撑这样的数据量级(即便分库分表,查询性能也远远无法达到要求) | low |
| Impala和Greenplum数据仓库、HBase等NoSQL | 在存储方面对该数据量级的作用 | 可以解决该量级的存储,但对时序数据支持不友好,查询和计算存在严重不足,对Python支持有限 | low |
| 常用二进制文件格式 | 示例 | HDF5、Parquet、pickle | high |
| pickle | 性质 | 作为Python对象序列化/反序列的协议非常高效 | low |
| 文件存储用于高频数据 | 缺陷 | 大量数据冗余、版本管理困难、不提供权限控制、无法利用多个节点资源、数据关联不便、管理粒度粗、检索与查询不便等 | medium |
| DolphinDB | 采用的存储方式 | 列式存储 | high |
| DolphinDB | 分区机制 | 提供多种灵活的分区机制,可利用集群中每个节点资源 | medium |
| DolphinDB | 能力/优势(按文中列举) | 支持超高性能查询与计算,并提供数据管理、权限控制、并行计算、数据关联等数据库优势 | low |
| DolphinDB vs pickle(数据读取性能) | 提升幅度(直接使用DolphinDB数据库读取) | 最多可提升10倍以上 | medium |
| DolphinDB vs pickle(数据读取性能) | 提升幅度(使用DolphinDB Python API读取) | 最多有2~3倍提升 | medium |
| DolphinDB在线文档 | 链接 | https://link.zhihu.com/?target=https%3A//www.dolphindb.cn/cn/help/index.html | high |
| DolphinDB教程(Gitee) | 链接 | https://link.zhihu.com/?target=https%3A//gitee.com/dolphindb/Tutorials_CN/blob/README.md | high |
| 数据集1 | 日期范围/日期 | 美国股市一天(2007.08.23)Level 1报价和交易数据 | high |
| 数据集1 | 列数与字符串列数 | 共10列,其中2列是字符串类型 | high |
| 数据集1 | 行数(一天) | 约2亿3000万行 | medium |
| 数据集1 | CSV文件大小 | 9.5G | high |
| 数据集1 | 转换为pickle后大小 | 11.8G | high |
| 数据集1在DolphinDB中的表结构 | 列定义 | symbol SYMBOL; date DATE; time SECOND; bid DOUBLE; ofr DOUBLE; bidsiz INT; ofrsiz INT; mode INT; ex CHAR; mmid SYMBOL | high |
| 数据集2 | 日期范围 | 中国股市3天(2019.09.10~2019.09.12)Level 2报价数据 | high |
| 数据集2 | 列数与字符串列数 | 总共78列,其中2列是字符串类型 | high |
| 数据集2 | 行数(一天) | 约2170万行 | medium |
| 数据集2 | 一天CSV文件大小 | 11.6G | high |
| 数据集2 | 转换为pickle后大小(一天) | 12.1G | high |
| 数据集2在DolphinDB中的表结构(字段示例) | 列定义(表中列出) | UpdateTime TIME; TradeDate DATE; Market SYMBOL; SecurityID SYMBOL; PreCloPrice DOUBLE; OpenPrice DOUBLE; HighPrice DOUBLE; LowPrice DOUBLE; LastPrice DOUBLE; TradNumber INT; TradVolume INT; Turnover DOUBLE; LocalTime TIME; TotalBidVol INT; WAvgBidPri DOUBLE; TotalAskVol INT; WAvgAskPri DOUBLE; IOPV DOUBLE; AskPrice1~10 DOUBLE; AskVolume1~10 INT; BidPrice1~10 DOUBLE; BidVolume1~10 INT; NumOrdersB1~10 INT; NumOrdersS1~10 INT | high |
| DolphinDB database | 数据副本数 | 2 | high |
| 两数据集写入DolphinDB后的磁盘占用 | 占用空间 | 10.6G(单份数据5.3G) | high |
| 两数据集写入DolphinDB后的压缩比 | 压缩比 | 约8:1 | medium |
| pickle文件(本文测试) | 是否采用压缩存储 | 未采用压缩存储;测试发现pickle压缩后加载时间大幅延长 | medium |
| 对比测试口径 | 查询范围 | 对比测试查询一天的数据 | high |
| DolphinDB Python API vs pickle 对比 | 计时范围 | 从客户端发出查询到接收到数据并转换成Python pandas DataFrame对象的耗时 | high |
| DolphinDB Python API查询过程 | 步骤拆分 | (1)数据库查询耗时;(2)数据节点发送到API客户端时间;(3)客户端反序列化为pandas DataFrame时间 | high |
| pickle读取耗时定义 | 计时内容 | 使用pickle模块加载pickle数据文件所需时间 | high |
| 服务器硬件(测试环境) | 主机型号 | PowerEdge R730xd | high |
| 服务器硬件(测试环境) | CPU | E5-2650 24cores 48线程 | high |
| 服务器硬件(测试环境) | 内存 | 512G | high |
| 服务器硬件(测试环境) | 硬盘 | HDD 1.8T * 12 | high |
| 测试环境网络 | 网络类型 | 万兆以太网 | high |
| 测试环境操作系统 | OS版本 | CentOS Linux release 7.6.1810 | high |
| DolphinDB部署模式(测试) | 集群形态 | 多服务器集群模式;3台服务器;每台服务器部署2个数据节点 | high |
| 数据节点资源配置(测试) | 磁盘/内存/线程 | 每个节点分配2个10K RPM HDD磁盘;内存使用限制32G;线程数设置16 | high |
| DolphinDB数据库(测试) | 副本数 | 2 | high |
| 测试客户机 | 位置 | 安排在其中一台服务器上 | high |
| DolphinDB服务器版本(测试) | 版本号 | 1.30.0 | high |
| Python API for DolphinDB版本(测试) | 版本号 | 1.30.0.4 | high |
| 测试方法(清缓存) | 原因 | 操作系统会缓存读写后的文件,从缓存读取会影响测试结果;每次测试前清除操作系统缓存和DolphinDB缓存,并对比有缓存性能 | high |
| 清理操作系统缓存命令 | 命令 | sudo sh -c "echo 1 > /proc/sys/vm/drop_caches"(可能需root用户) | high |
| 清理DolphinDB数据库缓存命令 | 命令 | pnodeRun(clearAllCache) | high |
| DolphinDB查询示例(测试代码) | Level 1查询 | select * from loadTable("dfs://TAQ", "quotes") where TradeDate = 2007.08.23 | high |
| DolphinDB查询示例(测试代码) | Level 2查询 | select * from loadTable("dfs://DataYesDB", "tick") where TradeDate = 2019.09.10 | high |
| DolphinDB Python API连接示例(测试代码) | 连接参数 | s.connect("192.168.1.13",22172, "admin", "123456") | high |
| pickle测试流程(测试代码) | 生成pkl文件方法 | quotes.to_pickle("taq.pkl"); tick.to_pickle("level2.pkl") | high |
| pickle测试流程(测试代码) | 读取方法 | pickle.load(open('taq.pkl','rb')); pickle.load(open('level2.pkl','rb')) | high |
| 读取美国股市Level 1数据集(结果表) | DolphinDB 数据库查询耗时 | 无缓存6秒;有缓存6秒 | high |
| 读取美国股市Level 1数据集(结果表) | DolphinDB Python API耗时 | 无缓存38秒;有缓存35秒 | high |
| 读取美国股市Level 1数据集(结果表) | pickle耗时 | 无缓存72秒;有缓存34秒 | high |
| 读取中国股市Level 2数据集(结果表) | DolphinDB 数据库查询耗时 | 无缓存5秒;有缓存5秒 | high |
| 读取中国股市Level 2数据集(结果表) | DolphinDB Python API耗时 | 无缓存22秒;有缓存22秒 | high |
| 读取中国股市Level 2数据集(结果表) | pickle耗时 | 无缓存70秒;有缓存20秒 | high |
| DolphinDB数据库直连查询 vs pickle | 性能对比结论 | 直接从DolphinDB数据库查询速度最快,超过pickle查询10倍以上 | medium |
| pickle文件读取极限性能(本文配置) | 吞吐范围 | 每秒150MB~200MB | medium |
| 读取12G pickle文件 | 耗时 | 约70秒 | medium |
| pickle读取瓶颈 | 瓶颈来源 | 磁盘IO;有操作系统缓存时性能提升,耗时主要为反序列化 | medium |
| 提升pickle读取性能的方法(文中建议) | 方向 | 提升存储介质吞吐量,例如改用SSD或磁盘阵列 | medium |
| DolphinDB数据库与Python API客户端 | 采用的协议 | 采用改良的pickle协议 | medium |
| DolphinDB数据库查询部分耗时(两数据集) | 耗时范围 | 约5~6秒(无论是否有缓存) | high |
| 一天的数据量在DolphinDB数据库中 | 数据量 | 约8G | medium |
| 数据在集群中分布(一天数据) | 节点数与单节点数据量 | 分三个节点存储;每个节点约2.7G | medium |
| 从一个节点查询需要传输的数据量(文中设定) | 传输数据量 | 约5.4G(本地节点不需要网络传输) | medium |
| 万兆以太网传输约5.4G数据 | 对应时间 | 约5~6秒 | medium |
| DolphinDB数据库查询瓶颈(本文配置) | 瓶颈来源 | 网络而非磁盘IO | medium |
| 压缩后一天的数据量 | 大小 | 约1.4G | medium |
| 压缩数据分布与磁盘加载时间估算 | 估算条件与结果 | 分布于12个磁盘;每盘100mb/s吞吐量;加载一天数据磁盘时间约1.2秒 | medium |
| DolphinDB Python API的反序列化协议 | 相对原版pickle的改进收益 | 比原版pickle协议节约5~6秒时间 | medium |
| 进一步提升DolphinDB Python API查询性能(文中建议) | 方向 | 升级网络(10G到100G,第一步查询耗时可能从5~6秒缩减到2秒)或继续改良pickle协议 | low |
| 数据集1(无缓存)DolphinDB Python API耗时构成 | 反序列化占比 | 总耗时38秒,数据库端耗时仅5~6秒,约80%时间耗费在pickle反序列化上 | medium |
| 数据集1(无缓存,剔除两个字符串字段) | 耗时变化(DolphinDB Python API) | 从38秒缩短到19秒(减少一半) | high |
| 数据集1两个字符串字段 | 耗时影响描述 | 以20%的数据量占了50%的耗时(在该分析语境下) | medium |
| 数据集2(剔除两个字符串字段) | 耗时变化(DolphinDB Python API) | 从22秒缩减到20秒 | high |
| 美国股市Level 1(去除字符串字段)读取结果 | DolphinDB耗时 | 无缓存19秒;有缓存18秒 | high |
| 美国股市Level 1(去除字符串字段)读取结果 | pickle耗时 | 无缓存56秒;有缓存16秒 | high |
| 中国股市Level 2(去除字符串字段)读取结果 | DolphinDB耗时 | 无缓存20秒;有缓存20秒 | high |
| 中国股市Level 2(去除字符串字段)读取结果 | pickle耗时 | 无缓存66秒;有缓存18秒 | high |
| 剔除字符串字段对pickle查询的影响(本文观察) | 效果描述 | 有缓存情况下耗时缩短一半;无缓存情况下提升有限,原因是瓶颈在磁盘IO | medium |
| DolphinDB数据类型 SYMBOL | 用途 | 用于优化高重复度的字符串类型数据(如股票ID、交易所名称) | medium |
| SYMBOL类型的实现机制(文中描述) | 存储方式 | 为Vector或Table配备字典存储不重复字符串,内部存储字符串在字典中的索引 | high |
| DolphinDB改用STRING类型(相对SYMBOL) | 性能影响 | 性能会降低 | medium |
| pickle反序列化对SYMBOL优势的利用 | 问题描述 | 未充分利用SYMBOL带来的优势,存在大量Python对象多次copy,是进一步优化方向之一 | medium |
| 并发测试设置 | 数据集与方法 | 采用数据集2;因全局锁限制,开启多个Python进程从pickle文件或DolphinDB数据库加载数据;pickle并发读取同一节点同一磁盘不同文件 | high |
| 并发查询耗时(3个连接,数据集2) | DolphinDB API连接本地服务器数据节点 | 连接1 48秒;连接2 43秒;连接3 45秒 | high |
| 并发查询耗时(3个连接,数据集2) | DolphinDB API连接不同服务器数据节点 | 连接1 28秒;连接2 35秒;连接3 31秒 | high |
| 并发查询耗时(3个连接,数据集2) | pickle | 连接1 220秒;连接2 222秒;连接3 219秒 | high |
| pickle并发读取耗时变化(本文解释) | 原因与现象 | 耗时从70秒线性增加到约220秒;瓶颈为磁盘IO,任务从1到3耗时约变3倍 | medium |
| DolphinDB并发查询耗时增加(本文解释) | 连接到不同服务器数据节点 | 耗时增加约50%(约10秒),主要原因是客户端节点网络达到瓶颈 | medium |
| DolphinDB并发查询耗时增加(本文解释) | 连接到同一服务器数据节点 | 耗时增加约100%(约22秒),主要原因是客户端节点和接入数据节点网络同时达到瓶颈 | medium |
| 提升DolphinDB并发多任务查询性能(文中建议) | 方向 | 升级网络(万兆升级到10万兆以太网)或引入传输压缩以提升网络传输效率 | low |
| DolphinDB数据库端查询耗时占比(文中总结) | 占比 | 约占整个查询耗时的20%左右(单任务与并发场景的总结表述) | medium |
| 数据集1示例(库内分析 vs 客户端分析) | Python API取数后pandas分析总耗时 | 约50秒左右 | low |
| 数据集1示例(库内分析) | 若各节点完成统计并仅合并少量结果的总耗时 | 约2秒左右(文中估计) | low |
| DolphinDB | 脚本语言与内置函数规模 | 内置完整的多范式脚本语言,包括千余个内置函数 | medium |
| DolphinDB库内分析能力(文中列举) | 支持的操作类型 | 时间序列、面板数据、矩阵的聚合、滑动窗口分析、关联、Pivoting、机器学习等量化金融常用功能可在库内完成 | medium |
| 数据库性能结论(文中结论) | 总体结论 | 数据库在提供管理便利/安全/可靠优势的同时,性能上超越操作系统裸文件业已可行;得益于分布式、压缩、列式存储与应用层协议改进,磁盘IO可能不再是最先遇到的瓶颈 | low |
| 高频金融数据解决方案(文中结论) | 对DolphinDB的定位 | 高频数据的时序特性使得时序数据库DolphinDB成为最新且有前景的解决方案;相对pickle等文件方案,带来管理便利与性能突破及时间序列/面板处理便利 | low |
| Python API查询链路瓶颈(文中结论) | 瓶颈位置 | 数据库查询耗时占很小部分,大部分时间耗费在客户端网络传输与数据序列化/反序列化(“最后一公里”) | low |
| 突破“最后一公里”瓶颈的思路(文中建议) | 方向 | 采用库内分析以降低传输数据量;启用类似Apache Arrow的通用内存数据格式以降低序列化/反序列化开销 | low |
| 网络瓶颈(文中展望) | 判断与建议 | 随着分布式技术推进,10G网络可能更早成为瓶颈;部署高性能数据库集群时可开始考虑100G以太网 | low |
| 数据压缩的重要性(文中结论) | 作用 | 数据压缩可提升磁盘IO与网络IO效率,在大数据存储与传输中重要 | medium |
| 字符串类型 | 对系统性能的影响(文中结论) | 对数据系统性能有非常大的负面影响;对象存储导致内存不连续与分配压力;CPU效率低;长度不一致导致磁盘随机读取困难 | medium |
| 数据系统设计(文中建议) | 字符串类型使用建议 | 尽可能避免使用字符串类型;若重复度高,建议使用类似DolphinDB的SYMBOL类型替代 | medium |