我们如何做基于Tarantool的Alfa-Bank投资业务的核心


电影《我们的秘密宇宙:细胞的隐秘生活》中的镜头照片

投资业务是银行界最困难的领域之一,因为不仅有贷款,贷款和存款,而且还有证券,货币,商品,衍生品和结构产品形式的各种困难。

最近,我们发现人们的金融知识水平有所提高。越来越多的人参与证券市场的交易。个人投资账户不久前就出现了。它们使您可以在证券市场上进行交易,同时可以减免税款或不缴税。所有来找我们的客户都希望管理他们的产品组合并查看实时报告。此外,大多数情况下,此产品组合是多产品的,也就是说,人们是各种业务线的客户。

此外,俄罗斯和国外监管机构的要求也在不断提高。

为了满足当前的需求并为将来的升级奠定基础,我们开发了基于Tarantool的投资业务的核心。

一些统计。Alfa-Bank的投资业务为个人和法人实体提供经纪服务,以提供在各种证券市场中交易的机会,为证券存储提供托管服务,为拥有私人和大型资本的个人提供信托管理服务,为个人提供证券发行服务。其他公司。Alfa-Bank的投资业务是每秒超过3000报价,这些报价是从各种交易平台下载的。在工作日内,代表银行或其客户在市场上完成了30万笔交易。在外部和内部平台上,每秒执行多达5000个订单。同时,所有内部和外部客户都希望实时查看其位置。

背景


自2000年代初以来,我们的投资业务领域已经独立发展:交易所交易,经纪服务,货币交易,证券和各种衍生品的场外交易。结果,我们陷入了功能井的陷阱。这是什么?每个业务部门都有其自己的系统,这些系统可以复制彼此的功能。每个系统都有自己的数据模型,尽管它们基于相同的概念进行操作:交易,工具,交易对手,报价等。由于每个系统都是独立开发的,因此出现了各种各样的技术。

此外,系统的代码库已经过时,因为某些产品起源于1990年代中期。在某些领域,它减慢了开发过程,并带来了生产率问题。

新解决方案要求


企业意识到技术发展对于进一步发展至关重要。我们被分配了以下任务:

  1. 在单个快速存储和单个数据模型中收集所有业务数据。
  2. 我们不得丢失或修改此信息。
  3. 有必要对数据进行版本控制,因为监管机构可能随时要求提供前几年的统计数据。
  4. 我们不仅应该带来一些新的,时髦的DBMS,而且应该创建一个解决业务问题的平台。

此外,我们的建筑师还设置了条件:

  1. 新的解决方案应该是企业级的,也就是说,它应该已经在一些大公司中进行了测试。
  2. 解决方案的操作模式必须是关键任务。这意味着我们必须同时出现在多个数据中心中,并冷静地体验一个数据中心的断开连接。
  3. . , , - . , .
  4. , .

我们采用标准方式:制定要求并与采购部门联系。从那里,我们得到了通常准备好进行此操作的公司列表。他们向所有人介绍了该任务,其中六个接受了对解决方案的评估。

我们在银行不相信任何人的话,我们喜欢自己测试所有内容。因此,我们竞争的先决条件是通过压力测试。我们为负载制定了测试任务,六分之三的公司已经自付费用,同意基于内存技术实施该解决方案的原型以对其进行测试。

我不会告诉我们如何测试所有内容以及花费了多长时间,我只总结一下:Mail.ru Group开发团队基于Tarantool的解决方案的原型展示了负载测试中的最佳性能。我们签订了合同并开始开发。来自Mail.ru Group的四个人,来自Alfa-Bank的三名开发人员,三名系统分析师,解决方案架构师,产品所有者和Scrum管理员。

接下来,我将讨论我们的系统如何发展,如何发展,我们做了什么以及为什么。

发展历程


首先,我们想知道如何从当前系统中获取数据。我们认为HTTP非常适合我们,因为当前的所有系统都可以相互通信,并通过HTTP发送XML或JSON。

我们使用内置的Tarantool HTTP服务器,因为我们不需要终止SSL会话,并且它的性能足以满足我们的要求。

正如我已经说过的,我们所有系统都生活在不同的数据模型中,在输入时,我们需要将对象带到我们将在家里描述的模型中。需要一种语言来转换数据。我们选择了命令式Lua。我们在沙盒中运行所有用于数据转换的代码-这是一个安全的地方,运行代码不会超出此范围。为此,只需执行必要代码的加载字符串,创建一个环境,该环境的函数不能阻塞任何内容或删除某些内容。


转换后,必须检查数据是否符合我们正在创建的模型。我们讨论了一个模型应该是什么,用什么语言来描述它。我们停止了Apache Avro,因为该语言非常简单,并且得到了Tarantool的支持。该模型和用户代码的新版本可以一天几次运行,即使在负载下,甚至没有负载下,一天中的任何时间都可以运行,并且可以快速适应变化。


验证后,必须保存数据。我们使用vshard(具有分片的地理间隔副本)进行此操作。


而且,对于大多数向我们发送数据的系统来说,细节都是如此,无论是否接收到它们都无关紧要。因此,从一开始我们就实施了维修线。这是什么?如果由于某种原因该对象未通过数据转换或验证,则我们仍将确认收货,但同时将对象保存在维修队列中。它与业务数据位于主存储库中是一致的。我们立即为其编写了一个管理界面,各种指标和警报。因此,我们不会丢失数据。即使源中的某些内容发生了变化,如果数据模型发生了变化,我们也会立即发现它并进行调整。


现在,您需要学习如何检索存储的数据。我们仔细分析了我们的系统,发现在Java和Oracle的经典堆栈中,总是存在某种ORM,它将数据从关系视图转换为对象视图。那么,为什么不立即以图形的形式将对象提供给系统呢?因此,我们很高兴地选择了满足我们所有需求的GraphQL。它允许您以图表的形式接收数据,仅提取当前所需的数据。您甚至可以以足够的灵活性对API进行版本控制。


几乎立即,我们意识到提取的数据对我们来说还不够。我们制作了可以附加到模型中的对象的函数-实际上是计算字段。也就是说,我们在该字段上附加了某个功能,例如,该功能考虑了报价的平均价格。请求数据的外部使用者甚至都不知道该字段是已计算的。


实施认证系统。


然后他们注意到在我们的解决方案中明确扮演了几个角色。角色是一种功能聚合器。通常,角色具有不同的设备使用情况:

  • T-Connect:处理传入连接,受处理器限制,占用很少的内存,不存储状态。
  • IB-Core:转换它通过Tarantool协议接收的数据,即与平板电脑一起使用。也不会存储状态,并且可以缩放。
  • 存储:仅保存数据,不使用任何逻辑。最简单的接口以该角色实现。借助vshard可扩展。


也就是说,在角色的帮助下,我们彼此脱离了集群的各个部分,这些部分可以彼此独立地进行扩展。

因此,我们使用管理员界面创建了事务数据流的异步记录和修复队列。从业务的角度来看,记录是异步的:如果我们保证可以向自己记录数据,那么无论在哪里,我们都将对此进行确认。如果未确认,则出了点问题,需要发送数据。这是异步记录。

测试中


从项目一开始就决定,我们将尝试灌输测试驱动的开发。我们使用tarantool / tap框架在Lua中编写单元测试,而使用pytest框架在Python中编写集成测试。同时,开发人员和分析人员都参与编写集成测试。

我们如何应用测试驱动的开发?

如果我们想要一些新功能,我们首先尝试为其编写测试。发现错误后,我们必须首先编写测试,然后再对其进行修复。首先,这样的工作很难,员工会误解甚至破坏:“让我们现在快速修复它,做一些新的事情,然后再进行测试。”只有这种“后期”几乎不会发生。

因此,您必须首先强迫自己编写测试,然后要求他人进行测试。相信我,即使在短期内,测试驱动的开发也是有益的。您会感到生活变得更加轻松。根据我们的感觉,现在有99%的代码已被测试覆盖。看起来很多,但我们没有问题:每次提交都会运行测试。

但是,最重要的是我们喜欢压力测试,我们认为它是最重要的,并定期进行。

我会告诉您一个简短的故事,其中介绍了我们是如何对第一个版本的负载测试进行第一阶段的。我们将系统放在开发人员的笔记本电脑上,打开负载并每秒接收4000笔交易。一台笔记本电脑的好结果。我们建立了一个包含四台服务器的虚拟负载架,比生产环境要弱。部署到最低限度。我们启动它,得到的结果比一台笔记本电脑上的线程要差。冲击含量。

我们很伤心。我们查看服务器负载,结果发现它们处于空闲状态。


我们打电话给开发人员,他们向我们解释说,那些来自Java世界的人Tarantool是单线程的。在负载下,只有一个处理器内核可以有效地使用它。然后,我们在每台服务器上部署了最大数量的Tarantool实例,打开了负载,每秒已接收1.450万笔交易。


我会再解释一次。由于将角色划分为使用不同资源的角色,因此负责处理连接和数据转换的角色仅加载处理器,并且与负载成正比。



此外,该内存仅用于处理传入的连接和临时对象。


相反,在存储服务器上,处理器的负载增长,但比处理连接的服务器要慢得多。


内存消耗与数据加载量成正比。


服务


为了专门开发新产品作为应用程序平台,我们制作了一个组件,用于在其上部署服务和库。

服务不仅仅是在某些字段上运行的一小段代码。它们可能是属于集群的相当大而复杂的设计,检查参考数据,扭曲业务逻辑并给出答案。我们还将服务方案导出到GraphQL,并且消费者获得通用数据访问点,并且在整个模型中进行自省。很舒服

由于服务包含更多功能,因此我们决定应该提供一些库,以便在其中提取常用的代码。在检查完这对我们没有任何影响之后,我们将它们添加到了安全的环境中。现在,我们可以以库的形式为其他环境设置函数。

我们希望我们拥有一个不仅用于存储而且用于计算的平台。并且由于我们已经有很多副本和分片,因此我们实现了分布式计算的外观,并将其称为map reduce,因为事实证明它就像原始的map reduce。

旧系统


尽管我们的所有旧系统都支持该协议,但并非所有旧系统都可以通过HTTP调用我们并使用GraphQL。因此,我们制定了一种将数据复制到这些系统的机制。


如果对我们有所更改,特殊的触发器将在“存储”角色中工作,并且具有更改的消息将落入处理队列。使用单独的复制器角色将其发送到外部系统。该角色不存储状态。

新改进


您还记得,从业务角度来看,我们进行了异步记录。但是后来他们意识到这还不够,因为有一类系统需要立即获得有关操作状态的答案。因此,我们扩展了GraphQL并添加了突变。它们有机地适用于现有的数据处理范式。对于另一类系统,我们只有一个方面的读写能力。


我们还意识到仅靠服务不足以提供足够的服务,因为每天,每周,每月都要建立大量报告。这可能会花费很长时间,并且报告甚至可能阻止Tarantool事件循环。因此,我们扮演了单独的角色:调度程序和运行程序。跑步者不存储状态。它们启动了艰巨的任务,而这些任务是我们无法实时实现的。并且调度程序角色监视启动这些任务的调度,这在配置中进行了描述。任务本身与业务数据存储在同一位置。当合适的时间到来时,调度程序会接任务,将任务交给某个跑步者,他会考虑并保存结果。


并非所有任务都需要按计划运行。有些报告需要按需阅读。达到此要求后,便会在沙箱中形成一个任务,并将其发送给运行程序以执行。一段时间后,用户异步接收到所有内容均已计算完毕的答案,报告已准备就绪。


最初,我们坚持保存所有数据,版本控制而不删除它们的范例。但是在生活中,您仍然需要不时删除某些内容,主要是一些原始或中间信息。基于过期,我们建立了一种清除过时数据存储的机制。


我们也知道,迟早会出现一种情况,那就是没有足够的空间来将数据存储在内存中,但是仍然必须存储数据。为此,我们将很快进行磁盘存储。


结论


我们从将数据加载到单个模型的任务开始,花了三个月的时间进行开发。我们有六个数据提供者系统。在Lua中,将整个转换代码转换为一个模型的代码大约为3万行。而且大部分工作尚未到来。有时,邻近团队缺乏动力,这使情况的处理变得非常复杂。如果您遇到类似的问题,那么您认为实现该问题的时间是正常的,请乘以三甚至四。

还请记住,即使使用新的DBMS,也无法借助新的DBMS解决业务流程中的现有问题。我的意思是说?在项目开始时,我们给客户留下了深刻的印象,现在我们将推出一个新的快速数据库并投入使用!流程会更快,一切都会好起来的。实际上,技术无法解决业务流程中存在的问题,因为业务流程是人。您需要与人合作,而不是技术。

在初始阶段通过测试进行开发可能会很痛苦且耗时。但是,即使在短期内,当您无需执行任何操作来进行回归测试时,它的积极效果也很明显。

在开发的所有阶段进行负载测试非常重要。您越早注意到体系结构中的某种缺陷,就越容易修复它,这将在将来节省大量时间。

Lua没有错。任何人都可以学习在上面写东西:Java开发人员,JavaScript开发人员,Python开发人员,前端或后端。我们甚至有分析师对此进行撰写。

当我们谈论我们没有SQL的事实时,这使人们感到恐惧。 “如何在没有SQL的情况下获取数据?”那可能吗? ”当然。在OLTP类系统上,不需要SQL。有一种语言形式的替代方法,可以立即返回面向文档的视图。例如,GraphQL。还有一种分布式计算形式的替代方案。

如果您知道需要扩展,请立即在Tarantool上设计解决方案,以便它可以在数十个Tarantool实例上并行工作。如果您不这样做,那将是困难而痛苦的,因为Tarantool只能有效地使用一个处理器内核。

All Articles