常見消息中間件之ActiveMQ

前言

  消息隊列是指利用高效可靠的消息傳遞機制進行與平台無關的數據交流,並基於數據通訊來進行分散式系統的集成。目前消息隊列已經逐漸成為企業IT系統內部通訊的核心手段,它具有低耦合、可靠投遞、廣播、流量控制、最終一致性等一系列功能,成為非同步RPC的主要手段之一。當前使用較多的消息隊列有RabbitMQ、RocketMQ、ActiveMQ、Kafka、ZeroMQ、MetaMQ等,而部分資料庫如Redis、MySQL以及phxsql也可實現消息隊列的功能。

  大多時候,我們使用消息隊列來做三件事情:解耦、削峰、非同步。這是消息隊列最突出的優點,其他優點比如可以持久化數據,保證消息之間的順序等等在業務中對我們的幫助也很大。

  萬事有利就有弊,消息隊列有這些優點,自然也有它的缺點,比如:

  1)系統研發成本增加。引入消息隊列後,你就必須要對大多數消息隊列有個深入的理解,否則如何做技術選型呢?而消息隊列本身也比較複雜,在短時間內無法完全理解。所以是否使用消息隊列需要根據具體場景判斷,而不是為了使用技術而用技術。

  2)系統複雜性增加。 一個系統如果直接將業務串列處理,那麼只需要在一個系統中把程式碼寫寫寫就好了。但如果引入消息隊列,則要多考慮很多方面的問題,比如一致性問題、如何保證消息不被重複消費,如何保證保證消息可靠傳輸。因此,需要考慮的東西更多,系統複雜性增大。

  3)系統可用性降低。 本來其他系統只要運行好好的,那你的系統就是正常的。現在你要加個消息隊列進去,那消息隊列掛了,你的系統勢必受到影響。因此,系統可用性降低。

  所以我們在考慮使用消息隊列的時候,一定要對目前的主流框架有所了解,充分應用其優點,避免或弱化其缺點。

  當今市面上主流的開源MOM(Message Oriented Middleware,消息中間件)基本上都是Apache旗下的項目,有老牌的ActiveMQ、RabbitMQ,炙手可熱的Kafka,阿里巴巴自主開發RocketMQ等。我們主要談談這幾個MQ的性能、優缺點和相應的業務場景。這些MQ都是支援集群架構模式的。

  另外說一下,其實Redis也是有MQ功能的,它完全可以當做一個輕量級的隊列服務來使用。與RabbitMQ相比,入隊時,當數據比較小時 Redis 的性能要高於 RabbitMQ,而如果數據大小超過了 10K,Redis 性能就大幅度降低,很難滿足系統的使用需求;出隊時,無論數據大小,Redis 都表現出非常好的性能,而 RabbitMQ 的出隊性能則遠低於 Redis。在我們印象中,Redis 是一個 key-value 快取中間件,而不是一個消息隊列中間件,基於以上兩種原因,我們在考慮消息中間件的時候一般都不考慮 Redis。所以我們在下面的內容就不涉及Redis的相關內容了,感興趣的小夥伴可以去研究一下。

1 JMS規範

  首先我們聊聊JMS(Java Message Service)規範,也就是Java消息服務,它定義了Java中訪問消息中間件的介面規範。所以我們應該明白,JMS只是介面,並沒有給予實現,實現JMS介面的消息中間件稱為「JMS Provider」。上面說到的ActiveMQ、RabbitMQ、Kafka、RocketMQ都基本遵循或參考了JMS規範,都有自己的特點和優勢。

1.1 專業術語

  JMS(Java Message Service):實現JMS介面的消息中間件;

  Provider(MessageProvider):消息的生產者;

  Consumer(MessageConsumer):消息的消費者;

  PTP(Point to Point):點對點消費模型;

  Pub/Sub(Publish/Subscribe):發布/訂閱的消息模型;

  Queue:隊列目標,也就是我們說的消息隊列,一般會真正的進行物理存儲;

  Topic:主題目標;

  ConnectionFactory:連接工廠,用於創建連接到消息中間件的連接;

  Connection:JMS客戶端到JMSProvider之間的通訊鏈路;

  Destination:目的地,指消息發布和接收的地點,包括隊列和主題;

  Session:會話,表示一個單執行緒的上下文,用於發送和接收消息

1.2 JMS消息格式

  StreamMessage 原始值的數據流

  MapMessage 一套名稱/值對

  TextMessage 一個字元串對象

  BytesMessage 一個未解釋的數據流

  ObjectMessage 一個序列化的對象

2 ActiveMQ

  ActiveMQ是一個完全支援JMS1.1和J2EE1.4規範的JMS Provider實現,儘管JMS規範出台已經很久了,但是JMS在早些年的J2EE應用中有著特殊的地位。可以說ActiveMQ是一個「古老」的消息中間件了,在那個時候它在業界應用的最廣泛,也是曾經叱吒風雲過的。但是從當今的業務需求來看,ActiveMQ想要有更強大的性能和海量數據處理能力,還需要不斷升級版本,提升性能和架構設計的重構。

  ActiveMQ有豐富的API、多種集群構建模式,這些足夠滿足我們80%以上的業務需求,事實也確實如此,做為業界老牌的消息中間件,它在中小型企業應用廣泛。當然了,面對大規模、高並發應用服務做中間件選項,如淘寶、京東等大型電商網站,ActiveMQ就捉襟見肘了。

2.1 消息投遞模式

  我們先說JMS規範里最經典的兩種消息投遞模式:「點對點」和「發布訂閱」。

  1)點對點:生產者向隊列投遞一條消息,只有一個消費者能夠監聽得到這條消息(PTP),如下圖:

 

 

   2)發布訂閱:生產者向隊列投遞一條消息,所有監聽該隊列的消費者都能夠監聽到這條消息(P/S),如下圖:

 

 

 2.2 指標

  我們從服務性能、存儲堆積能力、可擴展性三個方面考慮。

  1)ActiveMQ的性能一般,在早期傳統行業盛行的時代比較流行,但是面對如今的高並發、大數據的業務場景,就力不從心了。

  2)數據存儲默認採用kahadb存儲(索引文件形式存儲),也可以使用高性能的google leveldb(記憶體資料庫存儲),或者使用關係型資料庫如Oracle、MySQL等存儲。

  3)ActiveMQ可以與Zookeeper進行構建主備集群模型,並且多套的主備模型直接可以採用Network的方式構建分散式集群。

2.3 ActiveMQ集群

  ActiveMQ最經典的兩種集群架構模式:Master-Slave、Network。

  1)Master-Slave:

 

 

   從名字就可以看出來就是主從方式,也就是主備方式,雙機熱備機制。Master-Slave就是消息被複制到slave broker,即使master broker遇到故障失去工作能力,你也可以切換到slave broker繼續工作且不丟失消息。Master-Slave數目前ActiveMQ推薦的高可靠性和容錯的解決方案。

  Master-Slave集群的關鍵點:

  a、上圖綠色節點是主節點,灰色是備份節點,這兩個節點都是運行狀態。

  b、zookeeper的作用就是當綠色主節點宕機時,進行及時切換到備份節點上去,使其進行主從角色互換,用於實現高可用性的方案。

  c、Master-Slave集群模型的缺點也很明顯,就是不能做到分散式的topic、queue,當消息量巨大時,我們的MQ集群壓力過大,沒辦法滿足分散式的需求。

  2)Network

 

   可以理解為網路通訊方式。這種方式真正解決了分散式消息存儲和故障轉移、broker切換的問題。它支援分散式的topic、queue。一個broker會相同對待所有的訂閱:不管他們是來自本地客戶連接,還是遠程broker,它都會遞送有關的資訊拷貝到每個訂閱。遠程broker得到這個資訊拷貝後,會依次把它遞送到其內部的本地連接上。

  Network集群的關鍵點:

  a、這種方案需要兩套及以上的Master-Slave集群模型才可以搞定,部署很麻煩。

  b、Network解決了分散式消息隊列的問題,但是資源浪費嚴重。所以Master-Slave模型是傳統型互聯網公司的首選。

 

  ActiveMQ畢竟是Apache的頂級項目之一,它開箱即用,類似於 RabbitMQ,少量程式碼就可以高效地實現高級應用場景。目前正在進行新版本重構與落地,我們期待它能夠完成這次新生吧。