guava的eventBus和disruptor比較

EventBus:

基於觀察者模式實現的,本文基於同步模式來操作;這裏只介紹下幾個常用操作的代碼實現:

register:註冊觀察者實現:主要就是以把觀察者觀察的類key,同類觀察者的set集合爲value構成一個ConcurrenHashMap

代碼如下:

  private final ConcurrentMap<Class<?>, CopyOnWriteArraySet<Subscriber>> subscribers =
      Maps.newConcurrentMap();

這裏有兩步加鎖:map分段鎖,copyOnWriteArraySet讀寫鎖;

EventBus.post(Object):發送事件實現:根據事件的class找subscribers中的觀察者,通過反射執行所有觀察者的@Subscribe註解註釋的方法;

代碼如下:

public void post(Object event) {
    Iterator<Subscriber> eventSubscribers = subscribers.getSubscribers(event);
    if (eventSubscribers.hasNext()) {
      dispatcher.dispatch(event, eventSubscribers);
    } else if (!(event instanceof DeadEvent)) {
      // the event had no subscribers and was not itself a DeadEvent
      post(new DeadEvent(this, event));
    }
  }

本地測試結果:生產者生成100000條事件非常快(沒找到有拒絕策略,異步模式有線程池拒絕),如果動態增加大量生產者效率會下降主要是因爲兩個鎖,另外因爲消費者需要輪詢執行,如果消費者延遲高,會導致內存和cpu飆升,本地16g內存測試結果:

應用場景:ddd領域模型中jvm事件總線可以使用eventBus,建議使用異步的模式

Disruptor:

基礎介紹就不說了自己去看官方文檔,這裏只寫做事件總線怎麼做:

生產者:

            // 1.ringBuffer 事件隊列 下一個槽
            long sequence = ringBuffer.next();
            //2.取出空的事件隊列
            LongEvent longEvent = ringBuffer.get(sequence);
            data = byteBuffer.getLong(0);
            //3.獲取事件隊列傳遞的數據
            longEvent.setValue(data);
            ringBuffer.publish(sequence);

消費者(單線程):把消費者作爲事件轉發器,根據事件類型轉發到不同的自定義事件處理器(類似於Redis的事件處理機制)

每個事件處理器都在各自的業務線程池中執行(Hystrix的線程池隔離機制),避免某個延遲操作影響其他操作(線程池數不宜過多避免達到監控平臺的數量限制)

他是怎麼實現的線程安全的呢?

1.生產者cas替換ringbuffer的節點實現無鎖設計(如果競爭特別激烈會不會有某個線程一直不成功呢?肯定有但是還沒有那麼大併發量)

2.消費者通過維護自己的selection和ringbuffer的全局版本進行對比

這裏爲什麼把兩種方式比較呢?

其實大部分公司eventBus肯定夠用,但是他的所有的事件都是一個線程池,並沒有隔離,而且還有鎖,總的來說就是一個pull的模式。

disruptor是一個拉的模式,ringbuffer和消費者各自維護一個序號,用於記錄消費者消費的消費位置;另外disruptor支持多種消費模式:串行,並行(a1,a2之間並行,但是a1,b1需要串行),鏈式並行,菱形並行模式;

對於支付類的大型公司還是disruptor的無鎖效率更高,並且使用事件分派機制可以使各個業務操作在線程池層面隔離

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章