分享

LMAX架构

 关平藏书 2017-07-21

LMAX架构

LMAX是一个新的零售金融交易平台。因此,它必须处理具有低延迟的许多交易。该系统构建在JVM平台上,集中在一个业务逻辑处理器上,可以在单个线程上处理每秒600万个订单。业务逻辑处理器使用事件采购完全在内存中运行。业务逻辑处理器被Disrupters包围 - 一个并发组件,它实现了一个不需要锁操作的队列网络。在设计过程中,团队得出结论,使用队列的高性能并发模型的最近方向与现代CPU设计基本相反。

在过去几年中,我们不断听到“免费午餐结束” [1] - 我们不能指望个人CPU速度提高。因此,为了编写快速代码,我们需要明确地使用并发软件的多个处理器。这不是好消息 - 写并发代码是非常困难的。锁和信号量很难理解,难以测试 - 意味着我们花费更多的时间来担心计算机的满足,而不是解决领域问题。各种并发模型,如Actors和Software Transactional Memory,旨在使这更容易 - 但仍然有一个负担,引入了错误和复杂性。

所以我很高兴听到LMAX在去年三月的QCon伦敦的一个演讲。LMAX是一个新的零售金融交易平台。其业务创新之处在于它是一个零售 平台,允许任何人在一系列金融衍生产品中进行交易[2]这样的交易平台需要非常低的延迟 - 因为市场正在迅速发展,交易必须快速处理。零售平台增加了复杂性,因为它必须为许多人这样做。所以结果是更多的用户,有很多交易,所有这些都需要快速处理。[3]

考虑到向多核心思想的转变,这种苛刻的表现自然会提出明确并发的编程模式,而这正是他们的出发点。但在QCon上引起人们关注的是,这不是他们结束的地方。事实上,他们最终是通过为他们的平台做出所有的业务逻辑:所有的交易,从所有的客户,在所有的市场 - 一个单一的线程。一个线程将使用商品硬件处理每秒600万个订单。[4]

处理大量具有低延迟的事务,并没有并发代码的复杂性 - 我该如何抵制呢?幸运的是,LMAX对其他金融公司的另一个区别是他们很乐意谈论他们的技术决策。所以现在,LMAX已经在生产中一段时间​​来探索他们迷人的设计。


总体结构

图1:LMAX的架构在三个小点

在顶层,架构有三个部分

  • 业务逻辑处理器[5]
  • 输入中断器
  • 输出干扰器

顾名思义,业务逻辑处理器处理应用程序中的所有业务逻辑。正如我上面指出的,它是一个单线程java程序,它对方法调用做出反应并产生输出事件。因此,它是一个简单的java程序,不需要任何平台框架来运行除JVM本身,这允许它在测试环境中轻松运行。

尽管业务逻辑处理器可以在一个简单的环境中运行测试,但是更多的参与编排可以让它在生产环境中运行。输入消息需要从网络网关中取出,并进行解密,复制和记录。需要为网络传送输出消息。这些任务由输入和输出中断器处理。与业务逻辑处理器不同,这些是并发组件,因为它们涉及到缓慢而独立的IO操作。它们是专为LMAX设计和制造的,但它们(如整体架构)在其他地方都适用。


业务逻辑处理器

保持在记忆中

业务逻辑处理器顺序地(以方法调用的形式)接收输入消息,在其上运行业务逻辑,并发出输出事件。它完全在内存中运行,没有数据库或其他永久存储。保持内存中的所有数据有两个重要的好处。首先,它是快速的 - 没有数据库提供缓慢的IO访问,也没有任何事务行为执行,因为所有的处理顺序完成。第二个优点是它简化了编程 - 没有对象/关系映射要做。所有代码都可以使用Java的对象模型编写,而不必对映射到数据库做任何妥协。

使用内存结构有一个重要的后果 - 如果一切都崩溃会发生什么?即使是最具弹性的系统也容易受到某人拉力的影响。处理此事的核心是事件采购 - 这意味着业务逻辑处理器的当前状态可以通过处理输入事件来完全推导出来。只要输入事件流保存在耐用存储(这是输入中断器的作业之一)中,就可以通过重播事件来重新创建业务逻辑引擎的当前状态。

了解这一点的一个好方法是想一个版本控制系统。版本控制系统是一系列的提交,随时可以通过应用这些提交来构建工作副本。VCS比业务逻辑处理器更复杂,因为它们必须支持分支,而业务逻辑处理器是一个简单的顺序。

因此,理论上,您可以通过重新处理所有事件来始终重建业务逻辑处理器的状态。但是实际上,如果你需要旋转一下,这将需要太长的时间。因此,与版本控制系统一样,LMAX可以创建业务逻辑处理器状态的快照并从快照还原。他们每天晚上在低活动期间拍摄快照。重新启动业务逻辑处理器的速度非常快,全面重启 - 包括重新启动JVM,加载最新的快照和重播日期的期刊 - 不到一分钟。

如果业务逻辑处理器在下午2点崩溃,快照可以更快启动新的业务逻辑处理器,但不够快。因此,LMAX使多个业务逻辑处理器始终运行[6]每个输入事件由多个处理器处理,但除一个处理器之外,所有输入事件都将忽略其输出 如果实时处理器出现故障,系统将切换到另一台。处理故障转移的这种能力是使用Event Sourcing的另一个好处。

通过事件采购到副本,他们可以在微秒之间切换处理器。除了每天晚上拍摄快照,他们每天晚上都会重新启动业务逻辑处理器。复制允许他们在没有停机的情况下执行此操作,因此他们将继续全天候处理交易。

有关事件采购的更多背景,请参阅几年前我网站上草图模式该文章更侧重于处理时间关系,而不是LMAX使用的好处,但它解释了核心思想。

事件采购是有价值的,因为它允许处理器完全在内存中运行,但它对诊断有另一个显着的优势。如果出现意外行为,团队会将事件序列复制到其开发环境中,并将其重播。这允许他们在大多数环境中比在可能的情况下更容易地检查发​​生了什么。

这种诊断功能扩展到业务诊断。有一些业务任务,例如风险管理,需要大量的计算,这对处理订单是不需要的。一个例子是根据目前的交易头寸,通过风险简介获取前20名客户的列表。该团队通过旋转复制域模型并在那里进行计算来处理这个问题,在那里它不会干扰核心订单处理。这些分析域模型可以具有变体数据模型,在内存中保留不同的数据集,并在不同的机器上运行。

调整性能

到目前为止,我已经解释说,业务逻辑处理器的速度关键在于内存中的顺序。只是这样做(没有什么真正的愚蠢)允许开发人员编写可以处理10K TPS的代码[7]然后他们发现,专注于良好代码的简单元素可以将其提高到100K TPS范围。这只需要很好的代码和小的方法 - 基本上这就允许Hotspot做一个更好的优化和CPU,以便在代码运行时缓存代码更有效率。

上升了一个数量级更多的聪明才智。有几件事情,LMAX团队发现有助于到达那里。一个是编写java集合的自定义实现,这些集合被设计为缓存友好,并且谨慎使用垃圾[8]一个例子是使用原始的java longs作为hashmap键与一个特别写入的数组支持Map implementation(LongToObjectHashMap)。一般来说,他们发现数据结构的选择通常会产生很大的影响,大多数程序员只是抓住上一次使用的任何列表,而不是认为这个上下文是正确的。[9]

达到顶级性能的另一种技术是将注意力放在性能测试中。我长期以来一直注意到人们谈论技术来提高性能,但是真正有所作为的一件事是测试它。即使是很好的程序员也非常擅长构建最终错误的性能参数,所以最好的程序员喜欢使用剖析器和测试用例来进行猜测。[10] LMAX团队还发现,首先编写测试是性能测试的一个非常有效的规则。

编程模型

这种处理方式确实为您编写和组织业务逻辑的方式引入了一些限制。第一个是你必须挑逗任何与外部服务的互动。外部服务调用将会变慢,单线程将停止整个订单处理机。因此,您无法在业务逻辑中拨打外部服务。相反,您需要完成与输出事件的交互,并等待另一个输入事件再次选择它。

我将使用一个简单的非LMAX示例来说明。想像你正在通过信用卡订购果冻豆。一个简单的零售系统将收取您的订单信息,使用信用卡验证服务来检查您的信用卡号码,然后确认您的订单 - 所有在一个单一的操作。处理您的订单的线程将在等待信用卡被检查时阻止,但该块对于用户来说不会太长,并且服务器可以在处理器等待时总是运行另一个线程。

在LMAX架构中,您可以将此操作拆分为两个。第一个操作将捕获订单信息,并通过向信用卡公司输出事件(请求信用卡验证)完成。然后,业务逻辑处理器将对其他客户进行处理事件,直到其输入事件流中收到信用卡验证的事件。在处理该事件时,它将执行该订单的确认任务。

在这种事件驱动的异步风格中工作是有点不寻常的 - 尽管使用异步来提高应用程序的响应能力是一种熟悉的技术。它还有助于业务流程更有弹性,因为您必须更加明确地考虑远程应用程序可能发生的不同情况。

编程模型的第二个特征在于错误处理。传统的会话和数据库事务模型提供了有用的错误处理能力。如果任何事情出错,很容易将交易中发生的一切都丢弃。会话数据是短暂的,并且可以被丢弃,以牺牲一些对用户的刺激为代价,如果在复杂的中间。如果数据库端发生错误,您可以回滚事务。

LMAX的内存结构在输入事件之间是持久的,因此如果出现错误,那么重要的是不要让该内存处于不一致的状态。但是没有自动回滚功能。因此,在进行内存中持久状态的任何突变之前,LMAX团队都非常重视确保输入事件是完全有效的。他们发现测试是在投入生产之前冲出这些问题的关键工具。


输入和输出干扰器

虽然业务逻辑发生在单个线程中,但是在调用业务对象方法之前,需要完成许多任务。用于处理的原始输入以消息的形式脱离线,该消息需要被解组为便于业务逻辑处理器使用的形式。事件采购依赖于保存所有输入事件的耐用杂志,因此每个输入消息都需要记录在耐用商店上。最后,架构依赖于一组业务逻辑处理器,因此我们必须在整个集群中复制输入消息。类似地,在输出端,输出事件需要被封送以通过网络传输。

图2:输入破坏者完成的活动(使用UML活动图表示法)

复制者和记者涉及IO,因此相对较慢。毕竟,业务逻辑处理器的核心思想是避免做任何IO。同样这三个任务相对独立,所有这些任务都需要在业务逻辑处理器处理消息之前完成,但可以按任何顺序完成。因此,与业务逻辑处理器不同,每个交易都会改变后续交易的市场,因此适合并发。

为了处理这种并发性,LMAX团队开发了一个特殊的并发组件,他们称之为 Disruptor [11]

LMAX团队已经 使用开源许可证发布了Disruptor源代码

在一个粗糙的层面上,您可以将Disruptor视为队列的组播图,其中生产者将对象发送给所有消费者,以通过单独的下游队列进行并行消息。当你看到里面你看到这个队列网络真的是一个单一的数据结构 - 一个环形缓冲区。每个生产者和消费者都有一个序列计数器,以指示它当前正在处理的缓冲区中的哪个槽。每个制作者/消费者都写入自己的序列计数器,但可以读取其他的序列计数器。这样,制造商可以读取消费者的计数器,以确保其想要写入的插槽可以在计数器上没有任何锁定。类似地,消费者可以确保只有通过观看计数器,一旦另一个消费者完成它才能处理消息。

图3:输入干扰器协调一个生产者和四个消费者

输出干扰器是相似的,但它们只有两个连续的消耗器用于编组和输出。[12] 输出事件被分为几个主题,因此消息只能发送给对它们感兴趣的接收者。每个主题都有自己的破坏者。

我描述的破坏者以一个生产者和多个消费者的风格使用,但这不是对破坏者设计的限制。破坏者也可以与多个生产者一起工作,在这种情况下,它仍然不需要锁。[13]

破坏者设计的好处是,如果消费者遇到问题并落后,消费者可以更容易地赶上。如果卸载器在槽15上进行处理时出现问题,并且当接收器位于时隙31时返回,则它可以从一个批次中从槽16-30读取数据,以赶上。批量读取来自破坏者的数据使得滞后的消费者更容易赶上,从而减少总体延迟。

我在这里描述了一些事情,每个日志,复制器和unmarshaler - 这确实是LMAX做的。但是设计将允许多个这些组件运行。如果你跑了两个记者,那么一个人会采取偶数的位置,另一个记录员会采取奇怪的插槽。这样就可以实现这些IO操作的进一步并发。

环形缓冲区大:输入缓冲区为2000万个插槽,每个输出缓冲区为4百万个插槽。序列计数器是64位长的整数,即使环形槽包装也会单调增加。[14]缓冲区被设置为一个2的幂的大小,因此编译器可以进行有效的模数运算,以将序列计数器编号映射到槽位号。像系统的其余部分一样,破坏者一夜之间就弹起来了。这种反弹主要是为了擦拭记忆,以便在交易过程中发生昂贵的垃圾收集事件的机会较少。(我也认为定期重新启动是一个很好的习惯,这样你就可以排练这个紧急情况。)

记者的工作是将所有事件以耐用的形式存储,以便如果出现问题,可以重播。LMAX不使用数据库,只是文件系统。它们将事件流入磁盘。从现代来看,机械式磁盘对于随机存取速度非常慢,但流速非常快,因此标签行“磁盘是新磁带”。[15]

之前我提到LMAX在集群中运行其系统的多个副本,以支持快速故障切换。复制器保持这些节点同步。LMAX中的所有通信都使用IP多播,因此客户端不需要知道主节点的IP地址。只有主节点直接监听输入事件并运行一个复制器。复制器将输入事件广播到从节点。如果主节点下降,则会注意到心跳不足,另一个节点变为主节点,开始处理输入事件,并启动其复制器。每个节点都有自己的输入干扰器,因此有自己的日志,并且进行自己的解组。

即使使用IP多播,仍然需要进行复制,因为IP消息可能以不同的节点以不同的顺序到达。主节点为其余处理提供确定性序列。

unmarshaler将事件数据从线路转换为可用于调用业务逻辑处理器上的行为的java对象。因此,与其他消费者不同,它需要修改环形缓冲区中的数据,以便可以存储这个未解密的对象。这里的规则是,消费者被允许写入环形缓冲区,但是每个可写字段只能有一个并行消费者可以写入它。这保留了只有一个作者的原则。[16]

图4:扩展了具有破坏者的LMAX架构

破坏者是可以在LMAX系统之外使用的通用组件。通常,金融公司对于他们的系统非常秘密,甚至关注与业务无关的项目。LMAX不仅对其整体架构开放,而且还开放了破坏者代码,这使我非常开心。这不仅可以让其他组织利用破坏者,还可以对其并发属性进行更多的测试。


排队和他们缺乏机械的同情

LMAX架构吸引了人们的注意,因为与大多数人正在考虑的高性能系统接近,这是一个非常不同的方式。到目前为止,我已经谈到了它的工作原理,但是并没有深入研究这个方法。这个故事本身很有意思,因为这个架构并没有出现。在团队解决之前,花了很长时间来尝试更多的常规选择,并且意识到他们在哪里有缺陷。

目前,大多数业务系统都有一个核心架构,依赖于通过事务数据库协调的多个活动会话。LMAX团队熟悉这种方法,并相信它对于LMAX来说不会奏效。这一评估是建立在Betfair(设立LMAX的母公司)的经验之上。Betfair是一个博彩网站,允许人们下注体育赛事。它处理非常大量的交通量,有很多争议 - 体育赌注往往会爆发特定的事件。为了使这项工作,他们有一个最热的数据库安装之一,不得不做许多不自然的行为,以使其工作。基于这种经验,他们知道维持Betfair是多么困难 并且确信这种架构对于交易网站需要的非常低的延迟是不会奏效的。因此,他们必须找到不同的方法。

他们的初始方法是跟随现在这么多人说 - 要获得高性能,你需要使用显式并发。对于这种情况,这意味着允许并行处理多个线程的订单。然而,和并发的情况一样,困难在于这些线程必须相互通信。处理订单改变市场条件,需要传达这些条件。

他们早期探索的方法是演员模特及其表弟SEDA。Actor模型依赖于独立的活动对象,他们自己的线程通过队列相互通信。许多人发现这种并发模型比尝试基于锁定原语做某事更容易处理。

该团队使用演员模型构建了一个原型交换,并对其进行了性能测试。他们发现,处理器花费更多的时间来管理队列,而不是执行应用程序的真正逻辑。队列访问是一个瓶颈。

当推动这样的表现时,开始重视考虑到现代硬件的构建方式。马丁·汤普森喜欢使用的是“机械同情”。这个术语来自赛车开车,它反映了司机对汽车有一种固有的感觉,所以他们能够感受到如何获得最好的机会。许多程序员,我承认我陷入了这个阵营,对于如何编程与硬件的交互,并没有太多的机械同情。更糟糕的是,许多程序员认为他们有机械的同情,但它建立在硬件如何工作的概念,现在已经过时了。

现代CPU影响延迟的主要因素之一是CPU如何与内存进行交互。这些日子去主内存是一个非常慢的CPU操作。CPU有多个级别的缓存,其中每一个都显着更快。因此,为了提高速度,您希望在这些缓存中获取代码和数据。

在一个层次上,演员模式在这里有所帮助。您可以将一个演员视为自己的对象,将代码和数据进行聚类,这是缓存的自然单元。但是演员需要通过队列进行沟通,而LMAX团队则认为这是干扰缓存的队列。

解释如下:为了将一些数据放在队列中,您需要写入该队列。同样,要将数据从队列中取出,您需要写入队列以执行删除操作。这是写争议 - 不止一个客户端可能需要写入相同的数据结构。为了处理写入争用,队列通常使用锁。但是如果使用了锁,则可能导致内核切换到内核。当这种情况发生时,涉及的处理器可能会丢失其缓存中的数据。

他们得出的结论是要获得最佳的缓存行为,您需要一个只有一个核心写入任何内存位置的设计[17]多个阅读器很好,处理器通常在其高速缓存之间使用特殊的高速链接。但排队队伍的失败是单作家的原则。

这一分析使得LMAX团队得出了两个结论。首先,它导致了破坏者的设计,这个破坏者决心遵循单一作者的约束。其次,它引导了探索单线程业务逻辑方法的想法,提出了如果没有并发管理,单线程可以走多快的问题。

在一个线程上工作的本质是确保一个线程在一个核心上运行,缓存预热,尽可能多的内存访问到缓存而不是主内存。这意味着代码和工作数据集都需要尽可能一致地访问。同时将小代码与代码和数据保持在一起可以将它们作为一个单元在高速缓存之间进行交换,从而简化缓存管理,并再次提高性能。

LMAX架构的一个重要部分是使用性能测试。考虑和放弃以演员为基础的方法来自建筑和性能测试的一个原型。类似地,通过性能测试可以提高改进各种组件性能的大部分步骤。机械同情是非常有价值的 - 它有助于形成关于您可以做出什么改进的假设,并指导您转发步骤而不是后退步骤 - 但最终测试为您提供了令人信服的证据。

然而,这种风格的性能测试不是一个很好理解的话题。经常LMAX团队强调,提出有意义的性能测试通常比开发生产代码更难。再次机械同情对发展正确的测试十分重要。测试低级并发组件是无意义的,除非您考虑到CPU的缓存行为。

一个特别的教训是编写针对零组件的测试的重要性,以确保性能测试足够快,以便真正衡量实际组件正在做什么。编写快速测试代码比编写快速生产代码并不容易,因为测试并不像测试组件那么快,因此太容易得到错误的结果。


你应该使用这种架构吗?

乍一看,这个架构似乎是一个非常小的利基。所有导致它的驱动程序是能够以非常低的延迟运行大量复杂的事务 - 大多数应用程序不需要运行在600万TPS。

但是,让我着迷于这个应用程序的事情是,他们最终得到了一个设计,消除了许多软件项目的大量编程复杂性。围绕事务数据库的并发会话的传统模式不是没有麻烦。与数据库的关系通常是一个不平凡的工作。对象/关系映射工具可以帮助处理数据库的很多痛苦,但它并没有处理这一切。企业应用程序的大多数性能调优都涉及到SQL。

这些天,您可以获得更多的主内存到您的服务器,而不是我们的老家伙可以获得作为磁盘空间。越来越多的应用程序能够将所有工作集合放在主存储器中 - 从而消除了复杂性和缓慢的原因。事件采购提供了一种解决内存系统的耐久性问题的方法,在单个线程中运行所有内容可以解决并发问题。LMAX经验表明,只要您需要不到几百万TPS,您将拥有足够的性能余量。

CQRS日益增长的兴趣有很大的重叠 内存处理器是CQRS系统的命令端的自然选择。(虽然LMAX团队目前不使用CQRS。)

那么什么表示你不应该走这条路?这对于这种不太熟悉的技术来说总是一个棘手的问题,因为这个行业需要更多的时间来探索它的边界。但是,起点是要考虑鼓励建筑的特点。

一个特点是,这是一个连接的域,其中处理一个事务总是有可能改变如何处理以下事务。对于彼此更独立的事务,不需要协调,因此并行运行的独立处理器变得更具吸引力。

LMAX专注于确定事件如何改变世界的后果。许多网站更多地关注现有的信息存储,并将这些信息的各种组合呈现出尽可能多的眼球,例如想到任何媒体网站。这里的架构挑战往往集中在让您的缓存正确。

LMAX的另一个特点是这是一个后端系统,所以考虑如何适用于以交互模式运作的东西是合理的。越来越多的Web应用程序正在帮助我们适应对请求做出反应的服务器系统,这一点与此架构非常契合。这种架构比大多数这样的系统进一步扩展,它绝对使用异步通信,导致我之前概述的编程模型的变化。

这些变化将大部分团队习惯。大多数人倾向于以同步方式思考编程,而不是用于处理异步。然而,异步通信是响应性的重要工具,这一直是真的。有趣的是,如果在JavaScript世界中使用AJAX和node.js更广泛地使用异步通信,将会鼓励更多的人调查此风格。LMAX团队发现,虽然花了一点时间来适应异步风格,但很快就变得自然而且更容易。特别是在这种方法下,错误处理容易得多。

LMAX团队当然认为协调事务数据库的日期是编号。事实上,您可以使用这种架构更轻松地编写软件,并且运行速度更快可以消除传统中央数据库的大部分理由。

对于我来说,我觉得这是一个非常令人兴奋的故事。我的目标大部分是专注于模拟复杂领域的软件。像这样的架构提供了很好的分离关注点,使人们能够专注于域驱动设计,并保持大部分平台的复杂性。领域对象和数据库之间的紧密耦合一直是一个刺激 - 这样的方法提出了一个出路。

脚注

1:免费午餐结束了

这是Herb Sutter 着名文章的标题他描述了“免费午餐”,因为处理器的时钟速度不断增加,每年都会给我们更多的CPU性能。他的观点是,这样的时钟周期的增长不再会发生,相反,性能上升将来自多核。但是要利用多个内核,您需要能够同时工作的软件 - 所以没有编程风格的转变,人们将不再免费获得性能午餐。

2:我对这项创新的价值观念将保持沉默

3:用户群

所有交易系统都需要低延迟,因为一个交易可能会影响后期交易,并且基于快速反应有很大的竞争。大多数交易平台适用于专业人士 - 银行,经纪人等 - 通常有数百名用户。一个零售系统具有更多用户的潜力,Betfair拥有数百万用户,LMAX是针对该规模设计的。(LMAX团队不允许披露其实际数量。)

事实证明,虽然零售系统有很多用户,但大部分活动来自于制造商在易失性期间,仪器每秒可以获得数百次更新,在单个微秒内可以进行数百次交易的异常微阵列。

4:硬件

600万TPS基准测试是使用32GB RAM的3Ghz双核四核Nehalem戴尔服务器。

5: 团队不使用业务逻辑处理器,实际上它们没有该组件的名称,仅将其称为业务逻辑或核心服务。我给了它一个名字,以便在这篇文章中更容易谈论。

6:目前,LMAX在其主要数据中心运行两个业务逻辑处理器,在灾难恢复站点上运行第三个。所有三个进程输入事件。

7:交易中有什么

当人们谈论交易时间时,其中一个问题是交易中究竟是什么。在某些情况下,只需在数据库中插入新记录即可。LMAX的交易相当复杂,比典型的零售销售更为复杂。

交易中的订单涉及:

  • 检查目标市场是否可以接受订单
  • 检查订单对该市场有效
  • 为订单类型选择正确的匹配策略
  • 对订单进行排序,以便每个订单以最佳价格进行匹配,并与正确的流动性相匹配
  • 创造和宣传由于搭配而产生的交易
  • 根据新的行业更新价格

8:在这个延迟时间范围内,您必须注意垃圾收集器。对于几乎所有系统来说,现在的GC压实对性能没有任何明显的影响。但是,当您尝试以最小的抖动每秒处理数百万次事务时,GC暂停会成为问题。要记住的是,短暂的物体可以很快收集。所以永远是永远的对​​象,因为他们将永远活着。有问题的对象是那些会被提升为老一代的对象,但最终会死亡。因为这样破坏了老一代地区,所以会触发压缩。

9: 我很少想到要使用哪个集合实现。当您不在性能关键代码中时,这是完全合理的。不同的背景表明不同的行为。

10:有趣的旁注。虽然LMAX团队拥有大部分当前对功能编程的兴趣,但他们认为OO方法为这种问题提供了更好的方法。他们注意到,当他们编写更快的代码时,他们将从功能风格转向OO风格。部分原因是因为复制了功能性风格需要维护不变性的数据。但这也是因为对象提供了一个更复杂的域的更好的模型,并具有更丰富的数据结构选择。

11: “破坏者”的名字来自于几个来源。一个是LMAX团队认为这个组件是破坏当前并发思想的事实。另一个是对Java引入移相器这一事实的回应,所以包含扰乱者也很自然。

12:也可以记录输出事件。如果需要重新下载服务,这样做的优点是不需要重新计算它们。但实际上这并不值得。业务逻辑是确定性的,非常快速的,因此存储结果没有任何收益。

13:尽管在这种情况下确实需要使用CAS指令。有关详细信息,请参阅破坏者技术文档

14:这的确意味着,如果他们处理每秒十亿次的交易,那么这个计数器就会在292年的时间内被打包,造成一些地狱破裂。他们决定修改这个并不是一个重中之重。

15: SSD在随机访问方面更好,但像磁盘一样的IO系统会降低速度。

16:写字段时的另一个复杂因素是必须确保将写入的任何字段分成不同的缓存行。

17:确保单个作家到记忆位置

遵循单一作者原则的一个复杂因素是处理器不能一次抓住一个位置。而是一次性将多个连续的位置(称为高速缓存行)扫描到缓存中。访问高速缓存行块中的内存显然更有效,但也意味着您必须确保您不具有由不同内核编写的高速缓存行内的位置。因此,例如,Disruptor的序列计数器被填充,以确保它们出现在单独的高速缓存行中。


致谢

金融机构的技术工作通常是秘密的,通常没有什么理由。这是一个问题,因为它妨碍了专业从经验中学习的能力。所以我特别感谢LMAX在讨论他们的经验方面的开放性,无论是本文还是其他材料。

Disruptor的主要创始人是Martin Thompson,Mike Barker和Dave Farley

Martin Thompson和Dave Farley给了我详细介绍LMAX架构,作为本文的基础。他们也迅速回应电子邮件问题,以改善我的早期草案。

并发编程是一个棘手的领域,需要大量的关注才能胜任,而且我还没有做出这样的努力。因此,我完全依赖别人了解并发性,并感谢他们的耐心咨询。


进一步阅读

如果您喜欢LMAX团队成员的LMAX架构的视频描述,最好的选择是 Martin Thompson和Michael Barker在2010年旧金山颁发QCon演示文稿

Disruptor源代码可用作开放源代码。还有一个很好的技术论文(pdf),进一步深入以及博客和文章的集合

LMAX团队的各种成员都有自己的博客:Martin Thompson, Michael BarkerTrisha Gee

重大修订

2011年7月12日:第一次出版

2011年6月22日:开始起草

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多