`

LMAX 的架构(二)

 
阅读更多

 

接上文:LMAX 的架构(一)

即使有IP广播,复制还是需要的,因为IP消息是以不同顺序到达不同节点,主节点提供为其他处理提供一个确定顺序。

 

格式转换unmarshaler是将事件从其消息格式转换到Java对象,这样才能在业务逻辑处理器中使用,不同于其他消费者,它需要修改ring buffer中的数据以便能够存入这个被转换好的Java对象,这里有一个规则:并发地每次只有一个消费者能够运行写入,这实际上也符合单一写入者原则。

    disruptor组件可以用在LMAX系统以外,通常金融财务公司对他们的系统都保持隐秘,但是LMAX能够开源,我很高兴,这将允许其他组织使用disruptor,它也将允许其他人对其进行并发性能测试。
 
(banq注:disruptor看来是一种特殊的消息组件类似JMS东西)。

 

队列和机制偏爱的缺乏

 

LMAX架构引起了人们的关注,因为它是一个非常不同的方式接近的高性能系统。到目前为止,我已经谈到了它是如何工作的,但没有太多深入探讨了为什么它是这样。这个故事本身是有趣的,意识到他们是有缺陷的。

 

许多商业系统都有自己的核心架构师,通过事务性数据库实现多个会话事务(banq注:如EJB或Spring JTA等等),LMAX团队也熟悉这些知识,但是确信这些不合适他们的系统。这个经验是建立在LMAX母公司Betfair上 - 这是一家体育博彩公司,它处理很多人的体育投赌事件,这是一个相当大的并发访问,传统数据库机制几乎无法应付,这些让他们相信必须寻找另外一个途径来突破,他们现在接近目标了。

 

他们最初的想法为获得高性能是使用现在流行的并发。这意味着允许多线程并行处理多个订单。然而,在这种情况下是很难实现的,因为这些线程必须互相沟通。处理订单变化的市场条件等都需要相互沟通。

 

早期他们探索了Actor模型和近亲SEDA. Actor模型依赖于独立,活跃的对象有其自己的线程,彼此之间是通过queue同学,很多人认为这种并发模型比基于原始锁的方式易于处理。

 

这团队就建立了一个actor模型原型,进行性能测试,他们发现的是处理器会花费更多时间在管理队列,而不是去做真正应用逻辑,队列访问成了真正瓶颈(banq注:Scala的Actor模型很有名,不知这是否算Scala致命问题,怪不得很少人谈Scala的Actor模型了).

 

当追求性能达到这种程度,现代硬件构造原理成为很重要的必须了解的知识了,马丁汤普森喜欢用的一句话是“机制偏爱”,这词来自赛车驾驶,它反映的是赛车手对汽车有一种与生俱来的感觉,使他们能够感受到如何发挥它到最好状态。许多程序员包括我承认我也陷入这样一个阵营:不会认为编程如何与硬件等底层机制交互是值得研究的。

 

现代的CPU延迟是影响性能的主导因素之一,在CPU如何与内存交互,CPU具有多层次的缓存(一级二级),每级速度都明显加快。因此,如果要提高速度,将您的代码和数据加载到这些缓存中。

 

在某个层次, actor模型能够帮助你,你能认为actor可以作为集群节点,是缓存的自然单元。但是actors需要相互联系, 这是通过队列的- 而LMAX团队发现队列会干扰缓存(banq注:JVM伪分享的问题)。

 

为什么队列干扰了缓存呢?解释是这样的: 为了将数据放入队列,你需要写入队列,类似地,为了从队列取出数据,你需要移除队列也是一种写,客户端也许不只一次写入同样数据结构,处理写通常需要锁,但是如果锁使用了,会引起切换到底层系统的场景, 当这个发生后,处理器会丢失它的缓存中的数据。

 

他们得出的结论能够获得最好的缓存性能, 你需要设计一个CPU核写任何内存,多个读是好的,处理器会非常快,而队列失败在one-writer原则。
(JVM伪共享)

 

这样的分析导致LMAX团队得出一系列结论,导致他们设计出disruptor, 能够遵循single-writer约束. 其次它导向留澳单个线程处理业务逻辑的新的目标, 问题是:一个线程如果从并发管理结构中脱离出来(没有锁机制),它到底能跑多快?

 

单个线程的本质是:确保你每个CPU核运行一个线程,缓存配合,尽可能的高速缓存访问甚于主内存。这就意味着代码和数据需要尽可能的一致,. 保持小的代码对象和数据在一起,以便允许他们能够调入到一个高速缓存单位中或者轮换,简化高速缓存管理就是提高性能。

 

LMAX架构的路径的一个重要组成部分是使用了性能测试。基于actor模型的放弃也是来自于测试原型的性能。同时也为改善的各个组成部分的性能步骤,启用了性能测试。机械同情是非常宝贵的的 - 它有助于形成假设什么可以改进,并指导你前进 -最终测试提供了有说服力的证据。

两段关于性能测试重要性,未译

Performance testing in this style, however, is not a well-understood topic. Regularly the LMAX team stresses that coming up with meaningful performance tests is often harder than developing the production code. Again mechanical sympathy is important to developing the right tests. Testing a low level concurrency component is meaningless unless you take into account the caching behavior of the CPU.

One particular lesson is the importance of writing tests against null components to ensure the performance test is fast enough to really measure what real components are doing. Writing fast test code is no easier than writing fast production code and it's too easy to get false results because the test isn't as fast as the component it's trying to measure.

 

你应当使用者架构吗
这个架构是适合非常小小众,必须有很低的延迟获得复杂大量的交易,大多数应用并不需要6百万TPS。

但是我对这个架构着迷的原因是它的设计,它移除了很多其他大多数编程系统的复杂性,传统围绕事务性的关系数据库会话并发模型是不是免费的麻烦?(banq注:因为都掌握都知道也就是免费的) 通常与数据库打交道都有不寻常的付出和努力,对象/关系数据库映射ORM工具Object/relational mapping tools能够帮助减轻不少这种痛苦,但是它不能解决全部问题,大多数企业性能微调还是要纠结于SQL.

现在你能得到服务器更多的主内存,比我们过去这些老家伙得到的磁盘还要多,越来越多应用能够将他们的工作全部置于内存中,这样消除了复杂性和性能低问题. 事件源驱动Event Sourcing提供了一种内存in-memory系统的解决方案, 在单个线程运行业务解决了并发. LMAX 经验建议只要你需要少于几百万TPS,你就有足够的性能提升余地。

这里也是相似于CQRS. 一种事件驱动, in-memory风格自然的命令系统(尽管LMAX当前没有使用CQRS.)

 

那么表示你是不是不应该走上这条道路呢?始终存在这样鲜为人知的棘手的技术问题,这个行业需要更多的时间去探索它的边界(注:老子思想的缴啊)。基本出发点是鼓励有自己特点的架构。

一个重要特点是处理一个交易总是潜在地影响其后面的处理方式,因为交易总是相互独立的, 因为很少相互协调,那么使用分离单独处理器分别处理并发运行也许更加有吸引力。

LMAX指出了“事件”概念是如何改变世界(banq注:hold住事件,而不是hold住数据,你就上了一个新层次,摆脱低级趣味的数据库癖好)。 许多网站使用原有的信息存储系统,然后渲染各种能够吸引眼球的效果. 他们的架构挑战就是如何正确使用缓存。

LMAX另外一个特点是这是一个后台系统,有理由考虑如何在一个交互模型中应用它,比如日益增长的Web应用,当异步通讯在WEB应用越来越多时,这将改变我们的编程模型。

这个改变会影响很多团队,大多数人倾向于认为同步编程,不习惯于异步处理。异步通讯是必不可少的响应工具,在javascript世界已经广泛使用,如 AJAX 和 node.js, 这些鼓励人们研究这些风格. LMAX团队发现虽然要花费一定时间来适应异步编程模型,但是一旦习惯就成为自然,特别是错误处理上容易得多。

LMAX团队当然感觉到花力气协调事务性关系数据库的日子已经屈指可数(banq老泪纵横啊,05年喊出了数据库时代的终结,08年我就喊出数据库已死,被国内很多大牛讥笑为疯子) 。你可以使用一种更加容易方式编写程序而且比传统集中式中央数据库运行得更快,为什么视而不见呢?

从我的观点看,我发现了一个令人激动的故事,我的大多数目标集中在软件的复杂领域模型解决上,作为一个架构师很喜欢这样的分离关注:让人们关注领域驱动设计DDD Domain-Driven Design,同时很好分离了平台复杂性,领域对象和数据库的紧耦合总是如一根针刺激我,现在好像找到出路了。

 

全文完。
banq最后注,我来总结老马文章的主要观点:
1.肯定了In-Memory内存缓存模式 + 异步事件 架构,LMAX实践也验证了这个架构。这个架构降低复杂性。

2.LMAX的核心是新型并发框架Disruptor,其核心是根据现代CPU硬件缓存特点发明不同于通用LinkedList或Queue的新型数据结构RingBuffer。

3.号称并发未来的Actor模型被LMAX团队验证是有瓶颈的。

4.提出新的并发模型,每个CPU一个线程,多个CPU多个线程并发模式,摒弃了锁模式。

5.ORM等Hibernate没有完全解决OO的目标,关系数据库的事务也不是最后救命的稻草。LMAX用自己的事件记录的方式实现事务,这也不同于所谓内存事务STM。见另外一篇:NOSQL存储的基于事件的事务实现。

6.09年推出Jdonframework 6.1版本就是事件驱动(Event Sourcing)+异步编程模型+In-memory架构,老马实际肯定了Jdon一直坚持的前沿架构观点。(当然Jdonframework和LMAX还有些差别,只有领域模型异步的输出事件,没有输入事件,下一步可以引入Disruptors)。

7.老马认为架构师要分离关注,一是通过DDD降低业务的复杂性;二是通过技术探索创新,降低技术平台的复杂性,让程序员更多精力投入业务问题解决上。

  • 大小: 172.1 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics