天天看點

Kafka下的生産消費者模式與訂閱公布模式

  在RabbitMQ下的生産消費者模式與訂閱公布模式一文中,筆者以“資料接入”和“事件分發”兩種場景為例。介紹了怎樣使用RabbitMQ來設計、實作生産消費者模式與訂閱公布模式。生産消費者模式,指的是由生産者将資料源源不斷推送到消息中心,由不同的消費者從消息中心取出資料做自己的處理。在同一類别下。全部消費者拿到的都是相同的資料;訂閱公布模式,本質上也是一種生産消費者模式,不同的是,由訂閱者首先向消息中心指定自己對哪些資料感興趣,公布者推送的資料經過消息中心後,每一個訂閱者拿到的僅僅是自己感興趣的一組資料。這兩種模式是使用消息中間件時最經常使用的,用于功能解耦和分布式系統間的消息通信。

  本文将繼續以“資料接入”和“事件分發”這兩個場景為例。來探讨Kafka作為消息系統的應用方法(High Level)。

搞清楚Kafka的基本概念和應用方法是進行系統方案設計的前提,編寫代碼僅僅是詳細落地實施,而解決bug和性能調優是系統跑起來之後的事情了。

須要指出的是。本文重點是探讨應用方法,詳細應用時須要依據自身需求來做調整,沒有不論什麼技術方案是萬能的。

  為了友善閱讀。筆者首先反複一下這兩種場景:

  • 資料接入

      如果有一個使用者行為採集系統,負責從App端採集使用者點選行為資料。

    一般會将資料上報和資料處理分離開,即App端通過REST API上報資料,後端拿到資料後放入隊列中就立馬傳回,而資料處理則另外使用Worker從隊列中取出資料來做。例如以下圖所看到的。

    Kafka下的生産消費者模式與訂閱公布模式
      這樣做的優點有:第一。功能分離。上報的API接口不關心資料處理功能,僅僅負責接入資料。第二。資料緩沖。資料上報的速率是不可控的,取決于使用者使用頻率。採用該模式能夠一定程度地緩沖資料;第三,易于擴充,在資料量大時。通過添加資料處理Worker來擴充,提高處理速率。這便是典型的生産消費者模式。資料上報為生産者,資料處理為消費者。
  • 事件分發

      如果有一個電商系統。那麼。使用者“收藏”、“下單”、“付款”等行為都是非常重要的事件。通常後端服務在完畢相應的功能處理外。還須要在這些事件點上做非常多其它處理動作。比方發送短信通知、記錄使用者積分等等。我們能夠将這些額外的處理動作放到每一個子產品中,但這并非優雅的實作。不利于功能解耦和代碼維護。

      我們須要的是一個事件分發系統,在各個功能子產品中将相應的事件公布出來。由對其感興趣的處理者進行處理。這裡涉及兩個角色:A對B感興趣,A是處理者,B是事件。由事件處理器完畢二者的綁定,并向消息中心訂閱事件。服務子產品是後端的業務邏輯服務,在不同的事件點公布事件,事件經過消息中心分發給事件處理器相應的處理者。

    整個流程例如以下圖所看到的。

    這邊是典型的訂閱公布模式。

    Kafka下的生産消費者模式與訂閱公布模式
Kafka基本概念

  Kafka是一個分布式流資料系統,使用Zookeeper進行叢集的管理。與其它消息系統相似。整個系統由生産者、Broker Server和消費者三部分組成,生産者和消費者由開發者編寫。通過API連接配接到Broker Server進行資料操作。我們重點關注三個概念:

  • Topic。是Kafka下消息的類别,相似于RabbitMQ中的Exchange的概念。這是邏輯上的概念,用來區分、隔離不同的消息資料。屏蔽了底層複雜的存儲方式。對于大多數人來說。在開發的時候僅僅須要關注資料寫入到了哪個topic、從哪個topic取出資料。
  • Partition,是Kafka下資料存儲的基本單元,這個是實體上的概念。同一個topic的資料。會被分散的存儲到多個partition中,這些partition能夠在同一台機器上,也能夠是在多台機器上。比方下圖所看到的的topic就有4個partition。分散在兩台機器上。這樣的方式在大多數分布式存儲中都能夠見到,比方MongoDB、Elasticsearch的分片技術,其優勢在于:有利于水準擴充,避免單台機器在磁盤空間和性能上的限制,同一時候能夠通過複制來添加資料備援性,提高容災能力。為了做到均勻分布。通常partition的數量一般是Broker Server數量的整數倍。
  • Consumer Group,相同是邏輯上的概念。是Kafka實作單點傳播和廣播兩種消息模型的手段。

    同一個topic的資料。會廣播給不同的group;同一個group中的worker。僅僅有一個worker能拿到這個資料。換句話說。對于同一個topic,每一個group都能夠拿到相同的全部資料,可是資料進入group後僅僅能被當中的一個worker消費。

    group内的worker能夠使用多線程或多程序來實作,也能夠将程序分散在多台機器上,worker的數量通常不超過partition的數量,且二者最好保持整數倍關系。由于Kafka在設計時假定了一個partition僅僅能被一個worker消費(同一group内)。

    Kafka下的生産消費者模式與訂閱公布模式
生産消費者模式

  搞清楚了Kafka的基本概念後,我們來看怎樣設計生産消費者模式來實作上述的“資料接入”場景。在下圖中,由Producer負責接收前端上報的資料,投遞到相應的topic中(這裡忽略了Broker Server的細節),在Consumer端,全部對該資料感興趣的業務都能夠建立自己的group來消費資料,至于group内部開多少個worke來消費全然取決于資料量和業務的實時性要求了。

Kafka下的生産消費者模式與訂閱公布模式
訂閱公布模式

  再來看“事件分發”的場景,假如我們有“收藏”、“下單”、“付款”三個事件。業務一對“收藏”和“下單”事件感興趣。而業務二對“下單”和“付款”事件感興趣。那麼我們怎樣進行事件訂閱?不同于RabbitMQ中有資料路由機制(routing key),能夠将感興趣的事件綁定到自己的Queue上,Kafka僅僅提供了單點傳播和廣播的消息模型,無法直接進行消費對象的綁定。是以理論上Kafka是不适合做此種場景下的訂閱公布模式的。如果一定要做,有這麼幾個方案:

  • 方案一:繼續使用上述生産消費者的模式,在不同的group中過濾出自己感興趣的事件資料。然後進行處理。這樣的方式簡單有效。缺點就是每一個group都會收到非常多自己不感興趣的垃圾資料。
  • 方案二:把每一個事件的資料推送到不同的topic中。即以事件名稱來作為topic分類,在Consumer端,建立自己的group來消費自己感興趣的一組topic。這樣的方式适用于事件個數能夠明白評估而且數量較少,如果事件種類非常多。會導緻topic的數量過多,建立過多的topic和partition則會影響到Kafka的性能。由于Kafka的每一個Topic、每一個分區都會相應一個實體檔案,當Topic數量添加時,消息分散的落盤政策會導緻磁盤IO競争激烈成為瓶頸。
    Kafka下的生産消費者模式與訂閱公布模式
  • 方案三:採用流處理方式對資料進行分類。即添加一個中間資料流處理。将資料依照訂閱規則進行歸類,然後寫入不同的topic中,在Consumer端。每一個group能夠拿到僅僅是自己感興趣的資料。這樣的方式适用于資料量較大、可是Consumer端的消費group有限的情況。否則也會出現上述的topic碎片化的問題。
    Kafka下的生産消費者模式與訂閱公布模式
  • 方案四:自己做partition的配置設定,可是不easy控制。應盡量避免。

繼續閱讀