zoukankan      html  css  js  c++  java
  • Disruptor-架构思维的转变

    相对于无锁技术,Disruptor对于架构思维的转变,才是其最大亮点。

    Pub Event

    说到RingBuffer做的队列,通常都说的是“一读一写“,或者“多读一写“。而Disruptor天生是为“广播“设计,也就是1个Producer,多个Consumer消费同1条消息。

    有了“广播“,就能很好的支持不同逻辑模块的并行计算,从而提高性能。下面会专门分析一个案例,来讨论这个并行计算。

    Consumer依赖关系维护

    假设有如下一个场景:1个生成者P1,3个消费者C1, C2, C3。其中C3要依赖C1, C2执行完毕。如果基于传统的消息队列来设计,就会是如下的菱形结构:
    这里写图片描述

    之间用4个队列来连接,从P1流经到C3,要经过这4个队列。

    而如果用Disruptor的话,将只需要一个RingBuffer,3个consumer都消费这同1个RingBuffer,如下图所示:

    这里写图片描述

    在这里,有几个关键点:
    (1)C1, C2, C3消费的是同一个RingBuffer,因为进度不一样,它们各自有自己的指针,称之为Sequence。这里假设为S1, S2, S3

    (2)C3是要依赖C1, C2的,也就是它要等C1, C2消费完之后,它才能消费。因此S3取的是Min(S1, S2)。

    (3)假设P1的指针是S0,P1只需要和S3比较就行了,而不需要和S1, S2比较。因为S3是消费最慢的,只要P1没有跟上S3,那么队列就不会被覆盖。

    依赖关系的表达

    具体到Disruptor中,如何表达C3依赖C1, C2呢?代码举例如下,很简单:

    //handler1, 2, 3, 4同时消费一个RingBuffer,2, 3, 4并行,同时依赖1
    disruptor.handleEventsWith(handler1).then(handler2, handler3, handler4);
    
    //handler1,2,3,4同时消费一个RingBuffer,2依赖1,3依赖2,4依赖3
    disruptor.handleEventsWith(handler1).then(handler2).then(handler3).then(handler4);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    Event Resourcing

    在Marin Flower介绍LMAX的价格的时候,http://martinfowler.com/articles/lmax.html

    提出了一种思想:Event Resourcing
    http://martinfowler.com/eaaDev/EventSourcing.html

    下面以LMAX的架构为例,来讲解这种思想:
    这里写图片描述

    如上图所示,Receiver接收请求(这里的Receiver你可以理解为一个网络服务器),BLP处理请求,Publisher把处理结果交给下游。

    在这里,BLP是纯粹在内存中操作,那它挂了之后,状态怎么恢复呢?这里有3个关键点:
    (1)在BLP处理每一个Event之前,该Event先被Journaler日志化
    (2)BLP本身是个状态机。即使挂了,可以重放所有日志,恢复状态。另外,为了提高恢复速度,BLP的状态可以定期做Snapshot。
    (3)为了提高HA,可以准备多个BLP并行,1个挂了,切换到其它的。所以有一个Replicator组件,用于复制日志。

    在这里,Receiver、BLP、Journaler、Replicator通过一个RingBuffer进行交互,如下图所示:

    这里写图片描述

    在这里有1个Producer,4个Consumer,前3个可以并行,最后一个BLP依赖前3个。

    Un-marshaller在这里做一些Event的解析工作。

    这种架构还有一个巨大优点就是:可测性。你可以把日志拷贝到测试环境,“重放“整个过程来测试BLP。

    总结

    通过上面的分析,我们会发现Disruptor并不是我们通常意义上的一个简单的RingBuffer。

    基于它LMAX设计了一个新的架构,这种架构不仅速度够快,而且具有持久性、HA、可测性等诸多优点。

    --------------------- 本文来自 travi 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/chunlongyu/article/details/53313575?utm_source=copy 

  • 相关阅读:
    设计模式--抽象工厂(个人笔记)
    C#中Trim()、TrimStart()、TrimEnd()的用法
    C#中String类的几个方法(IndexOf、LastIndexOf、Substring)
    枚举、字符串、值之间的转换
    C# 获取文件名、目录、后缀、无后缀文件名、扩展名、根目录等
    向服务器发送Post或Get请求(封装好的)
    未能加载文件或程序集“AspNetPager”或它的某一个依赖项。参数错误。 (异常来自 HRESULT:0x80070057 (E_INVALIDARG))
    Hibernate实现向数据库插入一条数据全过程(Study By Example)
    es6 模块化
    css3 属性认识
  • 原文地址:https://www.cnblogs.com/felixzh/p/9711276.html
Copyright © 2011-2022 走看看