很早就看到过MF的这篇The LMAX Architecture,可是之前一来英文水平不够,二来确实看不懂… 今天有幸再次看到,一口气读完终于有所领悟。

1 Overall Architecture

LMAX是一个新的金融交易平台。系统完全构建于JVM之上,却能在一个单线程上每秒处理6m的订单(其实是指核心业务逻辑处理类是单线程的)。系统主要由高并发组件Disruptors和业务服务Business Logic Processor两部分组成。

我们经常听到“免费午餐已经没有了”,现代CPU的主频速度已经很难提升,为了写出更快的代码我们只能寄希望于编写多处理器上的并发软件。但这对程序员来说可不是一个好消息,因为并发编程非常困难,难于开发更难于测试。锁和信号量(semaphore)让我们投入过多精力关注计算机硬件而非我们的领域问题本身。多种编程模型如Actor和STM(software transactional memory)都意在简化并发编程,然而它们还是会引入Bug和不必要的复杂度。

在这种情况下,LMAX的单线程、低延迟、低复杂度使其显得格外引人注目。下面就是LMAX平台的顶层架构。就像刚才介绍的,系统主要就是由两个Disruptor和核心的Business Logic Processor组成。

2 Business Logic Processor

Business Logic Processor业务逻辑处理器(以下简称Processor)几乎没用任何框架,单线程地直接运行在JVM上,顺序地处理一个个输入消息。其最大特点就是完全在内存中计算(operate entirely in-memory),而没有任何的数据或其他持久化介质。这带来两个重要的好处:

1.      因为避免了慢IO访问和等待,所以它非常快

2.      因为再也不需要ORM映射了,所有数据都在Java对象中,所以它简化了编程

当然内存计算架构也带来了连锁反应,有一系列的问题要处理,比如故障恢复、Failover等。那么LMAX是如何应对的呢?其核心是Event Sourcing编程模型

Ø  首先,Processor的状态完全由输入事件源推演而来,所以Processor的状态恢复完全可以通过replay事件或日志来还原。

Ø  同时,定期(比如每天夜里并发量低时)都会做快照(snapshot)。这样通过重启JVM,加载快照,replay日志就可以快速还原。

Ø  最后,Processor会有多个结点组成集群来处理一个输入消息,当然只有一个Processor的输出会被保留。这样,当某个Processor发生故障时,可以及时failover切换。

此外,Event Sourcing模型的另一个好处就是方便了开发人员进行调试和诊断。当发生问题时,直接将事件或日志序列拷贝到本地环境进行replay就能重现问题了,因为Processor都是无状态的。

从实现上来说,Event Sourcing去除ORM层,加入Event Store(可以定制也可以使用关系数据库),通过DDD的Aggregate聚合根来管理Domain对象。



使用Event Sourcing模型最明显的变化首先就是一切慢外部服务都要从Processor中抽离出去,可以形成多个Input-Output-Input Distributor链。这种事件驱动风格其实不罕见,例如开发Nginx模块时,Nginx完全基于事件驱动,所以开发的模块时各个回调函数都要保证能快速返回。第二点就是错误处理。传统数据库出错时可以直接回滚,而LMAX平台没有自动回滚的设施,所以在持久化输入消息前要进行充分验证(持久化是在Disruptor中完成的,下面会讲到)。

3 Input and Output Disruptor

尽管Processor是单线程执行的,但整个系统不可能只有一个线程来处理请求。在LMAX中,Disruptor负责多线程处理请求以及计算前的一系列脏活累活。具体来说它主要负责以下几件事儿:

Ø  Receive message接消息:

Ø  Journal日志:将输入消息保存到磁盘上。只使用普通文件系统,没用任何数据库。

Ø  Replicate复制:将输入消息复制到集群中各个结点,让每个Processor都能处理。

Ø  Un-marshall解码:将原始输入消息解码为Processor能够处理的格式。

Receive message相当于另外三个任务的生产者,而后三个任务都是要在Processor处理前要完成的,但是三者间没有顺序要求。在这里,Disruptor采用了Ring Buffer数据结构。

下面解释一下其工作原理:每个任务都有自己的counter来记录当前处理到哪个Slot了。但每个任务都可以看到其他任务的counter,一是防止操作冲突,二是要保持速度(Receiver > Journaler/Replicator/Un-marshaller > Processor)。为了提高并发,还可以增加消费者,例如使用两个Journaler分别处理单双数的消息。

同样地,Output Disruptor也使用同样的数据结构来处理输出消息。

4 Mechanical Sympathy

“机械同感”(mechanical sympathy)来自于赛车比赛,它反映了车手对赛车有一种内在的感觉,所以他们能够赛车达到最佳状态。然而多数程序员缺少这种对编程与硬件交互的感同身受的情感。要么是没有,要么就是以为自己有,实际上却是基于很久以前硬件工作方式而建立的概念。

现代CPU影响延迟的一个重要因素就是CPU与内存的交互。虽然内存在我们看来很快,但是在CPU看来它实在太慢了。所以CPU内部又有了多层次的缓存,如L1,L2甚至L3,而这正是我们要想方设法利用的 – 尽可能让我们的代码或数据被它们缓存住。LMAX团队在放弃传统金融的事务数据库架构后选择了Actor模型,然而Actor模型尽管简化了并发编程,但实际上当多个客户端并发操作底层队列时,就会涉及到锁。结果,锁会引起上下文切换到内核态,从而使正在处理的CPU很可能丢失缓存中的数据。我们知道并发读是不需要锁的,于是解决问题的关键就在于如何保证单一写(one-writer principle)。

引用一段小测试:Disruptor论文中讲述了我们所做的一个实验。这个测试程序调用了一个函数,该函数会对一个64位的计数器循环自增5亿次。当单线程无锁时,程序耗时300ms。如果增加一个锁(仍是单线程、没有竞争、仅仅增加锁),程序需要耗时10000ms,慢了两个数量级。更令人吃惊的是,如果增加一个线程(简单从逻辑上想,应该比单线程加锁快一倍),耗时224000ms。使用两个线程对计数器自增5亿次比使用无锁单线程慢1000倍。

于是Disruptor首先遵循了single-writer原则(过后再具体分析Disruptor的内部实现),其次它使用单线程运行Processor来处理业务。好处自然就是保证一个CPU内核上只有一个线程在跑,这样能够warm up缓存,尽可能地使内存访问能命中缓存,而非真正访问内存。基于mechanical sympathy的分析和对系统原型的性能测试发挥了巨大作用,指导并验证了最终模型的设计。

5 When to Use?

第一印象可能是这种架构只适用于很少的场景。毕竟大多数应用程序都不是需要在低延迟下处理复杂事务的金融系统,对于这些应用6m的TPS不是必要的。然而,在内存越来越多的情况下,许多应用都放弃了与关系数据库和ORM工具的缠斗,将它们的working set放入内存处理,在这种情况下,LMAX采用的Event Sourcing模型是值得借鉴的

然而在Event Sourcing模型与CQRS(另一种基于事件的内存处理框架)之间有明显的功能重叠。关于二者的区别和使用场景还有待研究。


LMAX高并发系统架构的更多相关文章

  1. 大数据高并发系统架构实战方案(LVS负载均衡、Nginx、共享存储、海量数据、队列缓存)

    课程简介: 随着互联网的发展,高并发.大数据量的网站要求越来越高.而这些高要求都是基础的技术和细节组合而成的.本课程就从实际案例出发给大家原景重现高并发架构常用技术点及详细演练. 通过该课程的学习,普 ...

  2. PHP高并发高负载系统架构

    PHP高并发高负载系统架构 1.为什么要进行高并发和高负载的研究 1.1.产品发展的需要 1.2.公司发展的需要 1.3.当前形式决定的 2.高并发和高负载的约束条件 2.1.硬件 2.2.部署 2. ...

  3. Java互联网架构-直播互动平台高并发分布式架构应用设计

    概述 网页HTML 静态化: 其实大家都知道网页静态化,效率最高,消耗最小的就是纯静态化的 html 页面,所以我们尽可能使我们的网站上的页面采用静态页面来实现,这个最简单的方法其实也是最有效的方法, ...

  4. 不懂这些高并发分布式架构、分布式系统的数据一致性解决方案,你如何能找到高新互联网工作呢?强势解析eBay BASE模式、去哪儿及蘑菇街分布式架构

    互联网行业是大势所趋,从招聘工资水平即可看出,那么如何提升自我技能,满足互联网行业技能要求?需要以目标为导向,进行技能提升,本文主要针对高并发分布式系统设计.架构(数据一致性)做了分析,祝各位早日走上 ...

  5. 浅谈千万级PV/IP规模高性能高并发网站架构(转自老男孩)

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://oldboy.blog.51cto.com/2561410/736710 如果把来 ...

  6. 程序员修神之路--用NOSql给高并发系统加速(送书)

    随着互联网大潮的到来,越来越多网站,应用系统需要海量数据的支撑,高并发.低延迟.高可用.高扩展等要求在传统的关系型数据库中已经得不到满足,或者说关系型数据库应对这些需求已经显得力不从心了.关系型数据库 ...

  7. 3年Java开发6个点搞定高并发系统面试疑惑

    前言 其实所谓的高并发,如果你要理解这个问题呢,其实就得从高并发的根源出发,为啥会有高并发?为啥高并发就很牛逼? 说的浅显一点,很简单,就是因为刚开始系统都是连接数据库的,但是要知道数据库支撑到每秒并 ...

  8. Java面试之高并发系统

    在开发高并发系统时有三把利器用来保护系统:缓存.降级和限流.

  9. (转)浅谈千万级PV/IP规模高性能高并发网站架构

    浅谈千万级PV/IP规模高性能高并发网站架构 原文:http://blog.51cto.com/oldboy/736710 文章架构简图:   高并发访问的核心原则其实就一句话“把所有的用户访问请求都 ...

随机推荐

  1. codeforces 868A Bark to Unlock

    As technologies develop, manufacturers are making the process of unlocking a phone as user-friendly ...

  2. CSAPP-链接

    主要任务: 1.符号解析 在声明变量和函数之后,所有的符号声明都被保存到符号表. 而符号解析阶段会给每个符号一个定义. 2.重定位: 把每个符号的定义与一个内存位置关联起来,然后修改所有对这些符号的引 ...

  3. hdu 5514 Frogs(容斥)

    Frogs Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submi ...

  4. poj3237 树链部分 边权模板

    Tree Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 7384   Accepted: 2001 Description ...

  5. 10分钟 5步 发布以太坊 ERC20 代币

    1.安装 METAMASK Brings Ethereum to your browser 一个可以浏览器上进行操作的以太坊钱包,推荐 Chrome. Chrome 插件安装地址: https://c ...

  6. Spring中的InitializingBean接口的使用

    InitializingBean接口为bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候都会执行该方法. 测试,如下: imp ...

  7. BigData-‘基于代价优化’究竟是怎么一回事?

    本文由  网易云发布. 本文具体讨论了Join基础算法的一种优化方案  – Runtime Filter,在本文最后还引申地聊了聊谓词 下推技术.同时,在本文文章开头,笔者引出了两个问题,SQL执行引 ...

  8. 152. Maximum Product Subarray(中等, 神奇的 swap)

    Find the contiguous subarray within an array (containing at least one number) which has the largest ...

  9. 如何joomla修改版权信息

    1.在language\zh_CN目录下有一个zh-CN.mod_footer.ini文件,修改里面的内容: 2.具体模板的html\mod_footer目录下的default.php文件内(具体文件 ...

  10. 浅谈JS变量声明和函数声明提升

    先来两个问题 很多时候,在直觉上,我们都会认为JS代码在执行时都是自上而下一行一行执行的,但是实际上,有一种情况会导致这个假设是错误的. a = 2; var a; console.log(a); 按 ...