LMAX高并发系统架构
很早就看到过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高并发系统架构的更多相关文章
- 大数据高并发系统架构实战方案(LVS负载均衡、Nginx、共享存储、海量数据、队列缓存)
课程简介: 随着互联网的发展,高并发.大数据量的网站要求越来越高.而这些高要求都是基础的技术和细节组合而成的.本课程就从实际案例出发给大家原景重现高并发架构常用技术点及详细演练. 通过该课程的学习,普 ...
- PHP高并发高负载系统架构
PHP高并发高负载系统架构 1.为什么要进行高并发和高负载的研究 1.1.产品发展的需要 1.2.公司发展的需要 1.3.当前形式决定的 2.高并发和高负载的约束条件 2.1.硬件 2.2.部署 2. ...
- Java互联网架构-直播互动平台高并发分布式架构应用设计
概述 网页HTML 静态化: 其实大家都知道网页静态化,效率最高,消耗最小的就是纯静态化的 html 页面,所以我们尽可能使我们的网站上的页面采用静态页面来实现,这个最简单的方法其实也是最有效的方法, ...
- 不懂这些高并发分布式架构、分布式系统的数据一致性解决方案,你如何能找到高新互联网工作呢?强势解析eBay BASE模式、去哪儿及蘑菇街分布式架构
互联网行业是大势所趋,从招聘工资水平即可看出,那么如何提升自我技能,满足互联网行业技能要求?需要以目标为导向,进行技能提升,本文主要针对高并发分布式系统设计.架构(数据一致性)做了分析,祝各位早日走上 ...
- 浅谈千万级PV/IP规模高性能高并发网站架构(转自老男孩)
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://oldboy.blog.51cto.com/2561410/736710 如果把来 ...
- 程序员修神之路--用NOSql给高并发系统加速(送书)
随着互联网大潮的到来,越来越多网站,应用系统需要海量数据的支撑,高并发.低延迟.高可用.高扩展等要求在传统的关系型数据库中已经得不到满足,或者说关系型数据库应对这些需求已经显得力不从心了.关系型数据库 ...
- 3年Java开发6个点搞定高并发系统面试疑惑
前言 其实所谓的高并发,如果你要理解这个问题呢,其实就得从高并发的根源出发,为啥会有高并发?为啥高并发就很牛逼? 说的浅显一点,很简单,就是因为刚开始系统都是连接数据库的,但是要知道数据库支撑到每秒并 ...
- Java面试之高并发系统
在开发高并发系统时有三把利器用来保护系统:缓存.降级和限流.
- (转)浅谈千万级PV/IP规模高性能高并发网站架构
浅谈千万级PV/IP规模高性能高并发网站架构 原文:http://blog.51cto.com/oldboy/736710 文章架构简图: 高并发访问的核心原则其实就一句话“把所有的用户访问请求都 ...
随机推荐
- JMeter如何使用用户定义的变量
jmeter中经常使用用户自定义变量,以下是如何在实战中使用自定义变量. 先用Badboy录制登陆脚本,具体的Badboy录制脚本方法自行百度.录制完毕后修改脚本,删除一些没有用的脚本.这里我只保留了 ...
- [JSOI 2011]分特产
Description JYY 带队参加了若干场ACM/ICPC 比赛,带回了许多土特产,要分给实验室的同学们. JYY 想知道,把这些特产分给N 个同学,一共有多少种不同的分法?当然,JYY 不希望 ...
- [BJOI2006]狼抓兔子
题目描述 现在小朋友们最喜欢的"喜羊羊与灰太狼",话说灰太狼抓羊不到,但抓兔子还是比较在行的,而且现在的兔子还比较笨,它们只有两个窝,现在你做为狼王,面对下面这样一个网格的地形: ...
- [SHOI2008]堵塞的交通
Description 有一天,由于某种穿越现象作用,你来到了传说中的小人国.小人国的布局非常奇特,整个国家的交通系统可 以被看成是一个2行C列的矩形网格,网格上的每个点代表一个城市,相邻的城市之间有 ...
- 灰狼呼唤着同胞(brethren)
先求出确定边的联通块,有cnt块,显然方案数为2^(cnt-1) 联通块用dfs很好求 但此题还有并查集解法,且与一道叫团伙的题很像 边为0为敌人,1为朋友,敌人的敌人是朋友,朋友的朋友是朋友,正好对 ...
- [JSOI2007]祖码Zuma
题目描述 这是一个流行在Jsoi的游戏,名称为祖玛. 精致细腻的背景,外加神秘的印加音乐衬托,彷佛置身在古老的国度里面,进行一个神秘的游戏——这就是著名的祖玛游戏.祖玛游戏的主角是一只石青蛙,石青蛙会 ...
- hdu 5521 最短路
Meeting Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)Total ...
- 【BZOJ1012】【JSOI2008】最大数maxnumber
Description 现在请求你维护一个数列,要求提供以下两种操作:1. 查询操作.语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值.限制:L不超过当前数列的长度.2. 插 ...
- c++中成员函数的参数名与成员变量名重合的问题
有一天写类的时候突然想到了这个问题,下面就来介绍如何解决这个问题. 定义一个类: class test{ public: void setnum(); void getnum(); private: ...
- box-sizing position
box-sizing 属性 用于更改用于计算元素宽度和高度的默认的 CSS 盒子模型.可以使用此属性来模拟不正确支持CSS盒子模型规范的浏览器的行为. /* 关键字 值 */ box-sizing: ...