KDB+ 数据库:从金融到一级方程式赛车

KDB+,公司产品 KX 是一个在小范围内广为人知、速度极快的柱状数据库,旨在存储时间序列和基于时间序列的分析计算。 最初,它在金融行业非常流行 - 所有排名前 10 的投资银行和许多知名的对冲基金、交易所和其他组织都使用它。 最近,KX 决定扩大其客户群,现在在存在大量数据(按时间或其他方式组织)的其他领域提供解决方案 - 电信、生物信息学、制造等。 他们还成为一级方程式阿斯顿·马丁红牛车队的合作伙伴,帮助收集和处理来自汽车传感器的数据并分析风洞测试。 在这篇文章中,我想告诉你 KDB+ 的哪些功能使其性能超强,为什么公司愿意在它上面花很多钱,最后,为什么它不是一个真正的数据库。
 
KDB+ 数据库:从金融到一级方程式赛车
 
在本文中,我将尝试大致告诉您 KDB+ 是什么、它有哪些功能和限制,以及它对于想要处理大量数据的公司有什么好处。 我不会详细介绍 KDB+ 的实现细节或其 Q 编程语言的细节。这两个主题都非常广泛,值得单独撰写文章。 有关这些主题的大量信息可以在 code.kx.com 上找到,包括一本关于 Q - Q For Mortals 的书(请参阅下面的链接)。

一些条款

  • 内存数据库。 将数据存储在 RAM 中以便更快访问的数据库。 这种数据库的优点是显而易见的,但缺点是可能会丢失数据,并且需要在服务器上拥有大量内存。
  • 列式数据库。 数据按列存储而不是按记录存储的数据库。 这种数据库的主要优点是,一列中的数据一起存储在磁盘和内存中,这显着加快了对其的访问速度。 无需加载查询中未使用的列。 主要缺点是修改和删除记录比较困难。
  • 时间序列。 带有日期或时间列的数据。 通常,时间排序对于此类数据很重要,以便您可以轻松确定当前记录之前或之后的记录,或者应用其结果取决于记录顺序的函数。 经典数据库是建立在完全不同的原则之上的 - 将记录的集合表示为一个集合,其中记录的顺序原则上没有定义。
  • 向量。 在 KDB+ 的上下文中,这是相同原子类型的元素列表,例如数字。 换句话说,元素数组。 与列表不同,数组可以紧凑地存储并使用向量处理器指令进行处理。

 

历史信息

KX 于 1993 年由 Arthur Whitney 创立,他之前在摩根士丹利银行从事 A+ 语言的工作,A+ 语言是 APL 的继承者,APL 是一种非常原创且一度在金融界很流行的语言。 当然,在 KX 中,Arthur 继续秉承同样的精神,在激进极简主义思想的指导下创建了向量函数语言 K。 K 程序看起来像是一堆标点符号和特殊字符,符号和函数的含义取决于上下文,每个操作都比传统编程语言具有更多的含义。 因此,K 程序占用的空间极小——几行代码就可以替代 Java 等冗长语言中的几页文本——并且是该算法的超集中实现。
 
K 中的函数根据给定语法实现了 LL1 解析器生成器的大部分内容:

1. pp:{q:{(x;p3(),y)};r:$[-11=@x;$x;11=@x;q[`N;$*x];10=abs@@x;q[`N;x]  
2.   ($)~*x;(`P;p3 x 1);(1=#x)&11=@*x;pp[{(1#x;$[2=#x;;,:]1_x)}@*x]  
3.      (?)~*x;(`Q;pp[x 1]);(*)~*x;(`M;pp[x 1]);(+)~*x;(`MP;pp[x 1]);(!)~*x;(`Y;p3 x 1)  
4.      (2=#x)&(@x 1)in 100 101 107 7 -7h;($[(@x 1)in 100 101 107h;`Ff;`Fi];p3 x 1;pp[*x])  
5.      (|)~*x;`S,(pp'1_x);2=#x;`C,{@[@[x;-1+#x;{x,")"}];0;"(",]}({$[".s.C"~4#x;6_-2_x;x]}'pp'x);'`pp];  
6.   $[@r;r;($[1<#r;".s.";""],$*r),$[1<#r;"[",(";"/:1_r),"]";""]]}  

 亚瑟在2003年出现的KDB+中体现了这种以最少的身体动作实现极致效率的理念(我想现在已经很清楚名字中的字母K来自哪里了),无非是第四版K的诠释者在 K K 之上添加了一个更加用户友好的版本,称为 Q。Q 还添加了对 SQL 特定方言 - QSQL 的支持,以及解释器 - 支持表作为系统数据类型、用于处理表的工具在内存和磁盘等中
 
因此,从用户的角度来看,KDB+ 只是一个 Q 语言解释器,支持 C# 中的表和类似 SQL 的 LINQ 样式表达式。 这是KDB+与其他数据库最重要的区别,也是其主要竞争优势,但往往被忽视。 这不是数据库+禁用的辅助语言,而是成熟的强大编程语言+内置对数据库功能的支持。 这种区别对于列出 KDB+ 的所有优势将发挥决定性作用。 例如…
 

大小

按照现代标准,KDB+ 的尺寸简直就是微观的。 它实际上是一个亚兆字节的可执行文件和一个带有一些系统功能的小文本文件。 实际上 - 不到一兆字节,并且对于该计划,公司每年为服务器上的一个处理器支付数万美元。

  • 这种大小使 KDB+ 在任何硬件上都感觉很棒 - 从 Pi 微型计算机到具有 TB 内存的服务器。 这不会以任何方式影响功能;此外,Q 会立即启动,这使得它可以用作脚本语言等。
  • 在这个大小下,Q 解释器完全适合处理器高速缓存,从而加快了程序执行速度。
  • 对于这个大小的可执行文件,Q 进程占用的内存空间可以忽略不计;您可以运行数百个它们。 此外,如果需要,Q 可以在单个进程中使用数十或数百 GB 的内存进行操作。

普遍

Q 非常适合广泛的应用。 Process Q 可以充当历史数据库并提供对 TB 级信息的快速访问。 例如,我们有几十个历史数据库,其中一些数据库一天未压缩的数据占用了100多GB。 然而,在合理的限制下,对数据库的一次查询将在几十到几百毫秒内完成。 一般来说,我们对用户请求有一个通用的超时时间 - 30 秒 - 但它很少起作用。
 
Q 也可以很容易地成为一个内存数据库。 新数据添加到内存表中的速度如此之快,以至于用户请求成为限制因素。 表中的数据存储在列中,这意味着对列的任何操作都将充分使用处理器缓存。 除此之外,KX还尝试通过处理器的向量指令来实现算术等所有基本运算,从而最大限度地提高其速度。 Q 还可以执行数据库不典型的任务 - 例如,处理流数据并“实时”计算(根据任务的不同,延迟从几十毫秒到几秒)针对不同时间的金融工具的各种聚合函数间隔或建立完美交易对市场影响的模型,并在完成后几乎立即进行分析。 在此类任务中,大多数时候主要的时间延迟不是Q,而是需要同步不同来源的数据。 由于数据和处理它们的函数在一个进程中,因此实现了高速,并且处理被简化为执行多个 QSQL 表达式和连接,这些表达式和连接不是解释的,而是通过二进制代码执行的。
 
最后,你可以在Q中编写任何服务流程。 例如,网关进程自动将用户请求分发到必要的数据库和服务器。 程序员可以完全自由地实现任何用于平衡、优先级、容错、访问权限、配额以及基本上任何他想要的其他算法。 这里的主要问题是您必须自己实现这一切。
 
作为示例,我将列出我们拥有哪些类型的流程。 所有这些都被积极使用并协同工作,将数十个不同的数据库合并为一个,处理来自多个来源的数据并为数百个用户和应用程序提供服务。

  • 数据源的连接器(feedhandler)。 这些进程通常使用加载到 Q 中的外部库。Q 中的 C 接口非常简单,允许您轻松地为任何 C/C++ 库创建代理函数。 Q 的速度足够快,可以同时处理来自所有欧洲证券交易所的大量 FIX 消息。
  • 数据分发者 (tickerplant), 作为连接器和消费者之间的中间环节。 同时,它们将传入数据写入特殊的二进制日志,为消费者提供针对连接丢失或重新启动的稳健性。
  • 内存数据库(rdb)。 这些数据库通过将原始数据存储在内存中,提供对原始数据的最快访问。 通常,他们白天在表中积累数据,并在晚上重置它们。
  • 持久数据库 (pdb)。 这些数据库确保今天的数据存储在历史数据库中。 一般来说,与 RDB 不同,它们不会将数据存储在内存中,而是在白天使用磁盘上的特殊缓存,并在午夜将数据复制到历史数据库中。
  • 历史数据库(HDB)。 这些数据库提供对前几天、前几个月和前几年数据的访问。 它们的大小(以天为单位)仅受硬盘驱动器大小的限制。 数据可以位于任何地方,特别是位于不同的磁盘上以加快访问速度。 可以使用多种可供选择的算法来压缩数据。 数据库的结构有据可查且简单,数据按列存储在常规文件中,因此可以对其进行处理,包括通过操作系统进行处理。
  • 具有聚合信息的数据库。 它们存储各种聚合,通常按仪器名称和时间间隔分组。 内存数据库根据每条传入消息更新其状态,历史数据库存储预先计算的数据以加快对历史数据的访问。
  • 最后,该 网关进程为应用程序和用户提供服务。 Q 允许您实现传入消息的完全异步处理、跨数据库分发消息、检查访问权限等。 请注意,消息不受限制,并且大多数情况下不是 SQL 表达式,就像其他数据库中的情况一样。 大多数情况下,SQL 表达式隐藏在特殊函数中,并根据用户请求的参数构建 - 时间转换、过滤、数据标准化(例如,如果支付股息,则股票价格均衡)等。

一种数据类型的典型架构:

KDB+ 数据库:从金融到一级方程式赛车

速度

虽然Q是一种解释语言,但它也是一种矢量语言。 这意味着许多内置函数,特别是算术函数,采用任何形式的参数 - 数字、向量、矩阵、列表 - 并且程序员应该将程序实现为数组操作。 在这样的语言中,如果将两个包含一百万个元素的向量相加,该语言是否被解释就不再重要;相加将由超级优化的二进制函数执行。 由于 Q 程序中的大部分时间都花在使用这些基本向量化函数的表操作上,因此输出的运行速度非常不错,使我们即使在一个进程中也能处理大量数据。 这类似于Python中的数学库——虽然Python本身是一种非常慢的语言,但它有许多像numpy这样优秀的库,可以让你以编译语言的速度处理数值数据(顺便说一句,numpy在思想上接近Q) )。
 
此外,KX 还采取了非常谨慎的方法来设计表格并优化表格的工作。 首先,支持多种类型的索引,这些索引由内置函数支持,不仅可以应用于表列,还可以应用于任何向量——分组、排序、唯一性属性以及历史数据库的特殊分组。 索引应用简单,并且在向列/向量添加元素时会自动调整。 索引可以同样成功地应用于内存和磁盘上的表列。 执行 QSQL 查询时,如果可能,会自动使用索引。 其次,历史数据的处理是通过显示操作系统文件(内存映射)的机制来完成的。 大型表永远不会加载到内存中;相反,必要的列会直接映射到内存中,并且仅实际加载所需的部分(索引在这里也有帮助)。 数据是否在内存中对程序员来说没有区别;使用 mmap 的机制完全隐藏在 Q 的深处。
 
KDB+ 不是关系数据库;表可以包含任意数据,而表中行的顺序在添加新元素时不会改变,并且在编写查询时可以而且应该使用。 处理时间序列(来自交换、遥测、事件日志的数据)时迫切需要此功能,因为如果数据按时间排序,则用户不需要使用任何 SQL 技巧来查找第一行或最后一行或 N表中的行,确定第 N 行后面的哪一行,等等。 表连接得到进一步简化,例如,在包含 16000 亿个元素的表中查找 500 个 VOD.L(沃达丰)交易的最后报价在磁盘上大约需要一秒,在内存中大约需要几十毫秒。
 
时间连接的示例 - 报价表映射到内存,因此不需要在 where 中指定 VOD.L,隐式使用 sym 列上的索引以及数据按时间排序的事实。 Q 中的几乎所有连接都是常规函数,而不是选择表达式的一部分:

1. aj[`sym`time;select from trade where date=2019.03.26, sym=`VOD.L;select from quote where date=2019.03.26]  

最后,值得注意的是,从 Arthur Whitney 本人开始,KX 的工程师真正痴迷于效率,并竭尽全力充分利用 Q 的标准功能并优化最常见的使用模式。
 

KDB+ 在企业中广受欢迎,主要是因为其卓越的多功能性 - 它既可以用作内存数据库,也可以用作存储 TB 级历史数据的数据库,也可以用作数据分析平台。 由于数据处理直接在数据库中进行,因此可以实现高速工作并节省资源。 一种与数据库功能集成的成熟编程语言允许您在一个平台上实现整个必要流程堆栈 - 从接收数据到处理用户请求。
 

欲了解更多信息,

限制

KDB+/Q的一个显着缺点是进入门槛较高。 该语言的语法很奇怪,一些函数严重重载(例如,value 有大约 11 个用例)。 最重要的是,它需要一种完全不同的方法来编写程序。 在矢量语言中,您必须始终考虑数组转换,通过映射/归约函数的几种变体(在 Q 中称为副词)实现所有循环,并且永远不要试图通过用原子操作替换矢量操作来省钱。 例如,要查找数组中某个元素第 N 次出现的索引,您应该编写:

1. (where element=vector)[N]  

尽管按照 C/Java 标准,这似乎效率非常低(= 创建一个布尔向量,其中返回其中元素的真实索引)。 但这种表示法使表达式的含义更加清晰,并且您可以使用快速向量运算而不是缓慢的原子运算。 矢量语言与其他语言之间的概念差异相当于命令式编程方法和函数式编程方法之间的差异,您需要为此做好准备。
 
一些用户也对 QSQL 不满意。 关键是它看起来只是像真正的 SQL。 实际上,它只是一个类似 SQL 表达式的解释器,不支持查询优化。 用户必须自己在 Q 中编写最佳查询,而许多人还没有准备好。 另一方面,当然,您始终可以自己编写最佳查询,而不是依赖黑盒优化器。
 
另外,一本关于 Q - Q For Mortals 的书可以在以下网址免费获得: 公司网站,那里还收集了很多其他有用的材料。
 
另一个很大的缺点是许可证的成本。 每个 CPU 每年花费数万美元。 只有大公司才能承担这样的费用。 最近,KX 使其许可政策更加灵活,并提供了仅按使用时间付费或在 Google 和 Amazon 云中租用 KDB+ 的机会。 KX 还提供下载 用于非商业目的的免费版本 (根据要求提供 32 位版本或 64 位版本)。
 

竞争对手

有相当多的专业数据库是基于类似的原理构建的——柱状、内存中、专注于大量数据。 问题是这些是专门的数据库。 一个突出的例子是 Clickhouse。 该数据库与 KDB+ 在磁盘上存储数据和构建索引的原理非常相似;它执行某些查询的速度比 KDB+ 快,尽管不是很明显。 但即使作为数据库,Clickhouse 也比 KDB+ 更专业 - Web 分析与任意时间序列(这种差异非常重要 - 因此,例如,在 Clickhouse 中不可能使用记录排序)。 但最重要的是,Clickhouse 不具备 KDB+ 的多功能性,KDB+ 是一种允许直接在数据库中处理数据的语言,而不是首先将其加载到单独的应用程序中、构建任意 SQL 表达式、在查询中应用任意函数、创建流程与历史数据库功能的执行无关。 因此,很难将 KDB+ 与其他数据库进行比较;它们在某些用例中可能更好,或者在经典数据库任务方面更好,但我不知道还有另一个同样有效且通用的工具来处理临时数据。
 

Python集成

为了让不熟悉该技术的人更容易使用 KDB+,KX 创建了库以在单个进程中与 Python 紧密集成。 您可以从 Q 调用任何 Python 函数,反之亦然 - 从 Python 调用任何 Q 函数(特别是 QSQL 表达式)。 如有必要(并不总是为了效率),库会将数据从一种语言的格式转换为另一种语言的格式。 因此,Q 和 Python 紧密共生,以至于它们之间的界限变得模糊。 因此,程序员一方面可以完全访问许多有用的 Python 库,另一方面,他获得了处理集成到 Python 中的大数据的快速基础,这对于涉及机器学习的人员尤其有用或建模。
 
在 Python 中使用 Q:

1. >>> q()  
2.q)trade:([]date:();sym:();qty:())  
3. q)  
4. >>> q.insert('trade', (date(2006,10,6), 'IBM', 200))  
5. k(',0')  
6. >>> q.insert('trade', (date(2006,10,6), 'MSFT', 100))  
7. k(',1')  

引用

公司网址—— https://kx.com/
开发者网站 - https://code.kx.com/v2/
为凡人预订 Q(英文)- https://code.kx.com/q4m3/
kx 员工关于 KDB+/Q 应用的文章 - https://code.kx.com/v2/wp/

来源: habr.com

为具有 DDoS 保护、VPS VDS 服务器的站点购买可靠的主机 🔥 购买具备 DDoS 防护的可靠网站托管服务,包括 VPS 和 VDS 服务器 | ProHoster