傳統Active MQ與大數據下的分佈式Kafka

本人在Zuora工作的時候,幾乎所有的異步業務邏輯都使用ActiveMQ,對AMQ也算頗爲熟悉。現如今每天和Kafka打交道,對kafka也算駕馭的不錯。現在基於這兩者做個小比較。


首先,Active MQ與Kafka的相同點只有一個,就是都是消息中間件。其他沒有任何相同點。

  1. 關於consume
Active mq是完全遵循JMS標準的。amq無論在standalone還是分佈式的情況下,都會使用mysql作爲存儲,多一個consumer線程去消費多個queue, 消費完的message會在mysql中被清理掉。作爲AMQ的consume clinet的多個consumer線程去消費queue,AMQ Broker會接收到這些consume線程,阻塞在這裏,有message來了就會進行消費,沒有消息就會阻塞在這裏。具體消費的邏輯也就是處理這些consumer線程都是AMQ Broker那面處理。其實就是queue的message存在mysql,多個線程監聽這個queue,

Kafka有consumer group的概念。一個consumer group下有多個consumer,每個consumer都是一個線程,consumer group是一個線程組。每個線程組consumer group之間互相獨立。同一個partition中的一個message只能被一個consumer group下的一個consumer線程消費,因爲消費完了這個consumer group下的這個consumer對應的這個partition的offset就+1了,這個consumer group下的其他consumer還是這個consumer都不能在消費了。 但是另外一個consumer group是完全獨立的,可以設置一個from的offset位置,重新消費這個partition。
kafka是message都存在partition下的segment文件裏面,有offsite偏移量去記錄那條消費了,哪條沒消費。某個consumer group下consumer線程消費完就會,這個consumer group 下的這個consumer對應這個partition的offset+1,kafka並不會刪除這條已經被消費的message。其他的consumer group也可以再次消費這個message。在high level api中offset會自動或手動的提交到zookeeper上(如果是自動提交就有可能處理失敗或還沒處理完就提交offset+1了,容易出現下次再啓動consumer group的時候這條message就被漏了),也可以使用low level api,那麼就是consumer程序中自己維護offset+1的邏輯。
kafka中的message會定期刪除。

  1. 關於存儲結構

ActiveMQ的消息持久化機制有JDBC,AMQ,KahaDB和LevelDB

Kafka是文件存儲,每個topic有多個partition,每個partition有多個replica副本(每個partition和replica都是均勻分配在不同的kafka broker上的)。每個partition由多個segment文件組成。這些文件是順序存儲的。因此讀取和寫入都是順序的,因此,速度很快,省去了磁盤尋址的時間。

很多系統、組件爲了提升效率一般恨不得把所有數據都扔到內存裏,然後定期flush到磁盤上;而Kafka決定直接使用頁面緩存;但是隨機寫入的效率很慢,爲了維護彼此的關係順序還需要額外的操作和存儲,而線性的順序寫入可以避免磁盤尋址時間,實際上,線性寫入(linear write)的速度大約是300MB/秒,但隨即寫入卻只有50k/秒,其中的差別接近10000倍。這樣,Kafka以頁面緩存爲中間的設計在保證效率的同時還提供了消息的持久化,每個consumer自己維護當前讀取數據的offset(也可委託給zookeeper),以此可同時支持在線和離線的消費。

  1. 關於使用場景與吞吐量

ActiveMQ用於企業消息中間件,使得業務邏輯和前端處理邏輯解耦。AMQ的吞吐量不大,zuora的AMQ就是用作jms來使用。AMQ吞吐量不夠,並且持久化message數據通過jdbc存在mysql,寫入和讀取message性能太低。

Kafka的吞吐量非常大
TalkingData的kafka吞吐量非常大,並且會堆積message數據, kafka更多的作爲存儲來用,可以淤積數據。

  1.  關於消息傳遞模型

傳統的消息隊列最少提供兩種消息模型,一種P2P,一種PUB/SUB

Kafka並沒有這麼做,它提供了一個消費者組的概念,一個消息可以被多個消費者組消費,但是隻能被一個消費者組裏的一個消費者消費,這樣當只有一個消費者組時就等同與P2P模型,當存在多個消費者組時就是PUB/SUB模型

  1. push/pull 模型

對於消費者而言有兩種方式從消息中間件獲取消息:
①Push方式:由消息中間件主動地將消息推送給消費者,採用Push方式,可以儘可能快地將消息發送給消費者;②Pull方式:由消費者主動向消息中間件拉取消息,會增加消息的延遲,即消息到達消費者的時間有點長

但是,Push方式會有一個壞處:如果消費者的處理消息的能力很弱(一條消息需要很長的時間處理),而消息中間件不斷地向消費者Push消息,消費者的緩衝區可能會溢出。

ActiveMQ使用PUSH模型, 對於PUSH,broker很難控制數據發送給不同消費者的速度。AMQ Broker將message推送給對應的BET consumer。ActiveMQ用prefetch limit 規定了一次可以向消費者Push(推送)多少條消息。當推送消息的數量到達了perfetch limit規定的數值時,消費者還沒有向消息中間件返回ACK,消息中間件將不再繼續向消費者推送消息。
ActiveMQ  prefetch limit 設置成0意味着什麼?意味着此時,消費者去輪詢消息中間件獲取消息。不再是Push方式了,而是Pull方式了。即消費者主動去消息中間件拉取消息。

那麼,ActiveMQ中如何採用Push方式或者Pull方式呢?

從是否阻塞來看,消費者有兩種方式獲取消息。同步方式和異步方式。

同步方式使用的是ActiveMQMessageConsumer的receive()方法。而異步方式則是採用消費者實現MessageListener接口,監聽消息。

使用同步方式receive()方法獲取消息時,prefetch limit即可以設置爲0,也可以設置爲大於0

prefetch limit爲零 意味着:“receive()方法將會首先發送一個PULL指令並阻塞,直到broker端返回消息爲止,這也意味着消息只能逐個獲取(類似於Request<->Response)”

prefetch limit 大於零 意味着:“broker端將會批量push給client 一定數量的消息(<= prefetch),client端會把這些消息(unconsumedMessage)放入到本地的隊列中,只要此隊列有消息,那麼receive方法將會立即返回,當一定量的消息ACK之後,broker端會繼續批量push消息給client端。”
當使用MessageListener異步獲取消息時,prefetch limit必須大於零了。因爲,prefetch limit 等於零 意味着消息中間件不會主動給消費者Push消息,而此時消費者又用MessageListener被動獲取消息(不會主動去輪詢消息)。這二者是矛盾的。

Kafka使用PULL模型,PULL可以由消費者自己控制,但是PULL模型可能造成消費者在沒有消息的情況下盲等,這種情況下可以通過long polling機制緩解,而對於幾乎每時每刻都有消息傳遞的流式系統,這種影響可以忽略。
Kafka 的 consumer 是以pull的形式獲取消息數據的。 pruducer push消息到kafka cluster ,consumer從集羣中pull消息。





















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