当前位置: 首页 > 科技观察

我们如何为算法交易系统选择数据库?_0

时间:2023-03-20 01:37:15 科技观察

任何软件系统都必须包含的一个关键组件是用于存储、检索和分析数据的数据库。在这篇文章中,我们将和大家一起探讨适合算法交易平台的数据库有哪些特点?有哪些数据库选项?从广义上讲,数据库提供了记录和管理数据(OLTP)和分析数据(OLAP)的能力。大多数数据库将擅长其中一项功能,同时在某些指标上表现出色而在其他指标上表现不佳。例如,擅长一致性和持久事务的关系数据库在性能方面可能表现不佳,因为它需要锁定其数据结构并刷新所有磁盘写入。相反,优先考虑性能的数据库可能需要使用宽松的一致性模型。基于特定功能和特性的优先级,不同类型的数据库适用于不同的场景。1.算法交易系统的数据存储如果我们要追求完美,即持久一致地存储大量数据并实时快速分析,是否可以做到?虽然计算机科学理论警告我们不要贪得无厌,但还是有一些工程理念值得关注。主要设计目标包括:将大量事件快速摄取到持久存储中(每天工作时间,约250K-1M事件/秒;我们预计每个事件约100-200字节,具有10-30个字段)实时分析,包括聚合能够处理大量的模式和趋势历史数据基于以上设计目标,可以构建多个解决方案,但基本上都需要对数据存储进行分层,以提供多种附加功能。解决方案之一是:将事务系统中的所有事件存储到一个快速数据存储中,例如仅附加文件日志(可能在高可用性系统中的多个节点上复制或重新创建)。该文件提供持久存储,但没有真正的查询功能。将日志文件的内容按顺序提取到内存数据库/缓存中。这个步骤可以很快,甚至是实时的,因为在这一层没有一致性检查、复制或持久性要求。该层应提供实时聚合和分析。定期(每小时或一天结束时等)将内存数据库的内容保存到磁盘。这里使用了一个可以对存储在磁盘上的大量数据进行操作的数据库。本质上,对这些存储数据的操作被认为是离线或批处理模式,并且预计不会有瞬时响应时间。(可选)仅将日志文件的相关部分提取到关系数据库中以进行每日/每月报告。例如,只有订单和执行被加载到关系数据库中,而市场报价被跳过。此外,还可以简化此解决方案,例如,通过组合步骤2、3和4,使用提供多个模式来存储和分析数据的单一工具。下面我们来讨论数据库在切分需求下的工作。2、我们对数据库的要求我们对数据库的要求可以分为两部分:非技术要求和技术要求。非技术要求清单:成本:作为一家注重成本的初创公司,我们一直在寻找免费或相对便宜的产品。鉴于当今有许多FOSS方案,我们认为这不是一个疯狂的要求。这也意味着不包括标准的付费数据库,例如Oracle和MSSQLServer。良好的文档和社区支持:如果我们不为许可和支持付费,我们需要良好的文档和另一种回答问题的途径。可能的途径可能是邮件列表、活跃的在线社区,或者可能只是StackOverflow。操作工具:我们更喜欢相对成熟的产品,内置工具用于设置、管理和监控部署(包括可能的多节点集群)。技术要求:快速抓取:我们需要数据库能够以每秒250K的插入速度抓取,越高越好。如果我们需要进行批量插入,那是可以接受的;如果我们需要使用多个线程或连接也可以。快速聚合:我们打算在我们的系统中使用事件溯源模式。按照这种架构模式的规定,我们将系统中的所有状态更改记录为离散的不可变事件。为了从这些事件中重新创建系统的最新状态,我们需要支持内存中的快速聚合,包括窗口函数、更新插入和可能的其他横截面聚合。时序操作:支持时间桶、移动窗口聚合、as-ofjoin等操作。表达查询语言:SQL很好,但表达力不足以进行高级分析。理想情况下,数据库将支持使用具有矢量化操作的函数式语言进行数据访问和处理。创建用户定义函数或服务器端脚本的能力也很有用。内存表:用于快速分析工作数据集。磁盘上的表:我们希望该类别中的大多数数据库使用面向列的存储。数据库应该支持优化的磁盘数据布局,这可以显着提高性能。数据按日期划分并分段存储以进行数据管理对于每个分区,数据按Symbol(交易代码)跨多个节点进行分片以实现并行和冗余在每个分区和分片中,数据记录按(Symbol+Exchange,Symbol+exchange)被聚簇以方便从磁盘顺序读取最后,在每个聚簇键的记录中,数据按时间戳排序以加快时间序列操作此外,数据在磁盘上被压缩以减少从磁盘读取的数据总量分层数据存储:数据库还可以支持分层存储策略,将较旧的数据移动到较慢的存储,从而降低存储成本。以下是我们评估的数据大小估计:每日数据增长:50–100GB(未压缩)~1B记录历史数据(最终):100TB(未压缩)~1T记录3.如何测试?我们所有的测试都在单个或两个AWS专用实例(m5n-2xlarge)上执行。这些实例运行具有8个vCPU、32GBRAM和100–200GBSSD卷的AmazonLinux2AMI。我们知道对于一些参与的数据库来说,这些实例不是很大,特别是在内存指标方面。但我们在这个选择上也有我们的考量。首先,我们认为这些资源足以进行我们想要的测试,其次,我们想了解当资源不足时,这些工具将如何降级或失效。我们尽最大努力配置每个工具以在我们的时间限制内实现最佳性能,但我们可能并不总是使用推荐的配置、硬件或节点数量。我们还尝试遵循文档并以最佳方式设置数据布局(例如分片方案)。我们执行的实际测试包括:加载一天的NYSETAQ数据(文件20180730)。这会将3500万笔交易加载到一张表中,将7.19亿条报价加载到另一张表中。我们不会将此数据库用于报价数据分析,但它肯定会成为一个很好的示例数据集。对于每笔交易,找到交易所在交易所的当前报价。对于单个繁忙的代码(例如SPY),我们希望查询不到一分钟,而对于所有代码,我们希望查询在30分钟内完成。这是对查询语言表达复杂连接的能力以及数据库在合理时间内执行连接的能力的测试。对于每个股票代码,计算交易日每分钟的交易数量、平均规模和成交量加权平均交易价格。我们希望在整个事务表上花费的时间不超过10秒。为交易日的每一分钟计算每个交易品种的OHLC柱。计算交易日内每个交易品种的时间加权平均点差。这是一个有趣的测试,原因有二:1)确定一个报价的持续时间需要使用像LEAD或next这样的窗口函数,以及2)每个报价都必须被处理,所以这是对原始扫描速度的测试。4.备选方案澄清一下,我们在kdb+方面有很多经验,因此我们对响应时间的大部分期望都来自该经验。就原始单核速度而言,我们还没有找到比kdb+更快的工具。但由于价格、陡峭的学习曲线和缺乏运营工作,我们没有将kdb+列入候选名单。平面文件尽管数据库是最常见的数据存储,但直接使用平面文件是真正的关键竞争优势,因为它在存储数据方面提供了最大的灵活性。今天,有各种工具可以高效地操作存储在本地磁盘或S3存储桶上的平面文件,例如:Python(带有Jupyter的Pandas)、ApacheSpark、AmazonRedshiftSpectrum,甚至还有clickhouse-local。我们在AWS上使用ApacheSpark尝试了一个EMR(ElasticMapReduce)集群,虽然设置起来相对容易,但我们花了一段时间才弄清楚如何从文件和JDBC源加载数据,以及如何使用Spark数据集使用PySpark数据框。我们的结论是,这可以用于具有适当缩放功能的批处理分析,但不能用作主数据库。但是我们对Hadoop和Spark的了解有限,所以也会影响结论的判断。然而,我们仍然认为它是一个设计良好的系统,以正确的方式组织文件和目录,具有相应的工具和计划的工作,并且对于能够分配适当资源的高级用户来说可能是一个挑战。切实可行的选项。但对我们来说,我们认为它可能过于脆弱和杂乱无章,我们需要一些其他奇特的功能。MySQL我们只将MySQL作为起点,主要是为了确认传统的RDBMS并不是我们真正的正确答案。MySQL不是时间序列数据库,也不是面向列的,不支持我们正在寻找的高级分析特性或性能指标。它的优点是它是免费的并且拥有庞大的社区。它的支持者会声称,只要你知道怎么做,它就可以做任何事情。在我们的测试中,MySQL(InnoDB引擎)跟不上连接池中250K/秒的快速批量插入,并且随着表增长到几百万条记录,插入率下降。磁盘上的数据量显得很大,查询百万条记录的响应时间以秒为单位。即使可以添加索引,也无法在可接受的时间内完成包含数百万条记录的连接表。在校对本文草稿时,一位前同事向我们推荐了MariaDB列存储,由于时间关系,我们无法对其进行全面评估。PostgreSQL和TimescaleDBPostgreSQL在我们的负载测试中优于MySQL,尤其是在插入率和响应时间随着表大小增加而降低的水平方面,但不足以满足实际需求。TimescaleDB似乎很有竞争力——它是一个PostgreSQL扩展,使用大量常规PostgreSQL表来创建一个称为超表的虚拟表。超表上的所有查询和操作都向下传递到适当的块表。这里的主要目的是提高插入率并在处理大量数据时提供可预测的查询时间。TimescaleDB还提供了一些时间序列相关的函数来辅助分析。宣传效果很好,但实际跑起来并不好。初始插入率还不错(250K/秒),但我们无法提取3500万笔交易——不知何故它正在消耗内存。我们还注意到文本文件加载器无法利用服务器上的所有可用内核。在获取数据时,我们发现服务器上的IOWait时间比其他数据库长得多,可能是由于磁盘压缩不足。磁盘空间使用率也很高-奇怪的是,存储的数据比完全未压缩的文本数据占用更多空间(可能是因为预分配?)。我们知道最近的版本支持原生压缩,但我们不能自动将其用于新提取的数据。ClickHouseClickHouse基本上是一个新播放器,几乎具有我们梦寐以求的所有功能:它是FOSS、超快、水平可扩展、容错、硬件支持良好,并具有高级磁盘数据管理(包括分层存储);这个过程非常透明,Github上有一个活跃的社区,每2-3周发布一次更新,包括新功能、改进和修复;文档很好,很容易从维护者那里得到问题的解答。ClickHouse主要是一个OLAP引擎,没有真正的事务支持可言——例如,它不支持插入数据的更新和删除,除非通过笨拙的异步ALTERTABLE命令。它也不支持窗口函数(除了neighbor和runningAccumulate等特殊情况),这有点令人惊讶,因为它主要用于时间序列。我们在没有启用任何复制的情况下在单个节点上测试了ClickHouse。ClickHouse能够以超过1M/秒的速度加载3500万笔交易和7.19亿笔报价。它使用一种特殊的磁盘数据结构(MergeTree)以最快的速度将数据写入临时文件,然后在后台合并以达到高速。它永远不会耗尽内存(只有一个例外),并使用压缩源文件节省近一半的磁盘空间,效率极高。不幸的是,我们无法克服一些关键障碍:发出查询的唯一方法是使用类似SQL的查询语言,但有一些严格的限制:每个请求只能发出一个select语句,并且不支持用户定义的函数(UDFs)或存储过程(StoredProcedure)。他们的理念可以概括为“听我说”。一些合法的用户请求,例如支持日期时间数据类型的亚秒级精度,维护者没有得到令人满意的答复。公平地说,有些回应是有正当理由的,但看到这些交流仍然有点令人不安。总而言之,我们还是认为ClickHouse有很大的潜力,会密切关注它的发展,甚至可能会在系统的非关键部分部署ClickHouse。DolphinDBDolphinDB是一个奇怪的专业产品,在本次评估之前我们没有过多关注它。这是一个用于时间序列分析的快速分布式数据库,是kdb+的可行替代方案。kdb+的背景勾起了我们的兴趣,虽然是付费产品,但也足够我们试用了。我们对它的总体印象是积极的。它比ClickHouse更快,甚至可能比kdb+更快。它原生支持多节点集群、功能丰富的函数式编程语言以及优化的内存和磁盘数据结构。它在短短6秒内将我们的3500万笔交易加载到一张表中!它仅用了358毫秒就在所有SPY交易和它们的主要报价之间执行了截止连接,并在25秒内对所有代码执行了相同的连接,而在kdb+上的单个查询大约需要5分钟。此外,存储数据占用的磁盘空间不到压缩源文件的一半。它还具有一些高级功能(我们没有测试),包括:支持流和发布/订阅、实时聚合/窗口化引擎、实时异常检测引擎、高级统计分析功能和机器学习功能被克服:成本:虽然看起来比kdb+便宜,但对我们来说还是太贵了;需要学习非标准语言(虽然比kdb+容易多了),但是文档很完整也很优秀;对于关键业务组件,我们真的可以考虑为(对我们而言)未经证实且其局限性尚无法判断的闭源产品付费吗?由于它有几次崩溃和莫名其妙的内存不足情况而犹豫不决,因此会扣分。尽管如此,看起来我们可能已经找到了比kdb+更快、功能更丰富的东西,它的得分很高。我们会密切关注这个产品,如果对具有这些功能的产品有强烈的需求,比如报价数据研究环境,我们肯定会考虑它。现在要说的MemSQL就是我们最终的选择——MemSQL。MemSQL是付费产品,但它也为最多4个节点、128GB内存和无限磁盘数据的初始集群提供免费商业许可证。在考虑付费产品之前,我们认为这足以满足我们的初始需求。MemSQL将自己定义为一种称为HTAP(混合事务/分析处理)的新型数据库。MemSQL的主要卖点是:它提供了快速的分析功能,同时具有丰富的事务支持和与SQL的完全兼容。它甚至与MySQL兼容,因此您可以使用所有MySQL工具和驱动程序。与大型工具生态系统集成很好,但也存在一些障碍,因为很难用纯SQL表达一些高级分析。我们接受这个特殊的缺点,因为它完全支持UDF和存储过程中的过程语言[注意:过程方法至少比通常的向量化操作慢一个数量级]。MemSQL支持内存中的行存储表以及磁盘上的列存储表,具有分片、排序和压缩(他们最近还发布了一种混合单存储格式。我们只使用Columnstore进行了测试,特别是考虑到我们的测试实例仅32GB内存。MemSQL是部署、管理、监控、集群设置,甚至数据加载和查询方面最容易使用的工具之一。我们能够以超过500,000条记录/秒的速度加载交易和报价。我们注意到我们观察到服务器上的加载过程能够使用多个内核并行提取。加载的数据占用的空间与压缩源文件的空间大致相同。我们还观察到外部工具能够从MemSQL读取数据中提取,这特别令人印象深刻。整体性能对于大多数单表查询以及多表连接查询都很好。它在as-of连接上表现不佳,但它根本不是为该用例设计的......我们花了很多钱钛的我试图最好地表示SQL中的as-of-join,但我们最终迫使引擎执行(相对)快速的MergeJoin。可以预期,供应商将在未来的Dedicated支持中添加对作为自定义操作的as-of-join的支持。总而言之,MemSQL是我们在调查中找到的最平衡的解决方案。它成熟、易用、免费(暂时)、快速、高效,并且可以与我们想要的所有标准工具互操作。5.结果统计对于以上测试,我们都做了详细的统计和对比:如果想更详细的查看我们的测试结果,可以在这里查看:https://github.com/prerak-proof/dbtests6。还有很多其他工具可以评估,尤其是各种NoSQL数据库。我们的总体感觉是,虽然这些选项也可以处理我们的数据大小,但它们可能无法满足我们的性能预期。至少目前,我们认为MemSQL是最好的选择。适合我们的产品,包括我们的需求和限制。