天天看點

一款消息隊列的用戶端架構——啟明資訊車聯網MQ演進實踐分享

分享人:阿裡雲MVP曾憲宇,2014開始 就職于啟明資訊,負責車聯網平台的架構和建設,坐标吉林長春。

分享内容:結合主流MQ,介紹一款基于Java的開源消息隊列用戶端架構。

在不同階段,如何選擇合适的MQ?

一款消息隊列的用戶端架構——啟明資訊車聯網MQ演進實踐分享
這幾年随着物聯網的發展,對消息中間件的應用越來越廣泛,像ActiveMQ、RabbitMQ、阿裡的RocketMQ、Kafka、雅虎的Pulsar等這些開源消息中間件,在不同的行業和系統中都擔任着重要的角色。關于這些MQ的資料,也很容易搜尋到,但有很多将它們之間進行對比。在此說一下我的個人看法,因為每一款MQ專注的地方和發展路徑以及它的優勢都不一樣,是以沒有絕對的可比性。我們的系統要使用這些中間件,一定是為了解決某些問題,是以就要選擇最适合的。
一款消息隊列的用戶端架構——啟明資訊車聯網MQ演進實踐分享

下面介紹我們在使用消息中間件的演進曆程,可能很多數公司都有相似之處。

主要分了三個階段,而每個階段的訴求都不一樣,是以要使用不同的MQ:

第一階段:需要一個與平台無關并且能夠支援多協定的MQ,因為是異構系統,而且上下遊不同的技術棧,上遊是C++,下遊是Java系統,是以中間使用ActiveMQ進行異步通訊。

第二階段:建設車輛網IOT,因為高并發量和資料量,需要一個高吞吐中間件,此時ActiveMQ就不合适了,并且Kafka和大資料生态元件結合的比較好,像Strom/Spark/Flink一些流計算架構對Kafka支援也比較好。其實做物聯網(IOT)的小夥伴應該比較清楚,從終端裝置采集上來的資料品質其實是很差的,可能是因為強弱電或者網絡的一些關系,會照成部分資料的丢失和不準确,基本上是在資料接入之後,甚至落地之後,通過一些算法和模型來提高資料品質,其實考驗IOT中間件最重要的不是資料的可靠性,而是資料的接入能力和處理能力,是以Kafka是當時一個不錯的選擇。

第三階段:我們的部分業務想移植到共有雲上,需要一個款面向雲原生,具備自動化能夠彈性伸縮的MQ,對Kafka比較了解的同學應該知道,Kafka的Topic和Partition不建議太多,過多的磁盤IO會嚴重影響broker端的寫入性能,而且又因為broker是和存儲綁定在一起,擴充和減少kafka叢集需要對分區rebalance,這些,其實是很頭疼的,而 RocketMQ是把資料都順序寫入了一個檔案(commit log),很好的解決了這些問題,而且當時公司也更傾向于阿裡雲,不過這部分業務因為一些原因擱置了。

一款消息隊列的用戶端架構——啟明資訊車聯網MQ演進實踐分享

在MQ演進的過程中,就會面臨一個問題和思考:如果能讓應用快速切入,想要在不改動業務代碼的情況下,可以在不同的消息中間件間切換,也就是說需要一個公共的API,這就是消息隊列用戶端架構初衷和想要解決的問題。

消息隊列用戶端架構實踐分享

一款消息隊列的用戶端架構——啟明資訊車聯網MQ演進實踐分享

這款消息隊列用戶端架構,開源在GitHub上。

項目首頁:

http://www.darkphoenixs.org/message-queue-client-framework/ Maven的中央倉庫也可以下載下傳,目前最新版本1.5.8

<dependency>
    <groupId>org.darkphoenixs</groupId>
    <artifactId>messagequeue-framework</artifactId>
    <version>x.x.x</version>
</dependency>           

(說到開源架構,一般都有一個響亮或者洋氣的名字,但是作者本身比較詞窮,是以這個架構的名字就叫做消息隊列用戶端架構:Message Queue Client Framework)

一款消息隊列的用戶端架構——啟明資訊車聯網MQ演進實踐分享

這個架構設計之初非常簡單,就抽象出這麼幾個接口:

  • Producer:通過send方法發送消息
  • Consumer:通過receive方法接收消息
  • Encoder和Decoder:定制消息序列化和反序列化

這樣一個最基本的生産消費模式就出現了,基于這些接口使用者就可以根據自己的業務開發完成消息的收發功能了。

具體代碼示例可以參考:

https://github.com/DarkPhoenixs/message-queue-client-framework/wiki/Configuration-Examples
一款消息隊列的用戶端架構——啟明資訊車聯網MQ演進實踐分享

對于Kafka Consumer的增強,作者是從Kafka 0.8.x版本開始使用Kafka的,那個時候的kafka還隻是分布式消息中間件,在使用和開發過程中的一個感受就是Kafka的API真的是過于“簡單”,尤其是Consumer端的API,隻提供一種poll方式讓使用者自由發揮,這樣使用者需要額外做很多工作,再加上非常奇怪的4位版本号,曾經一度認為Kafka是Linkedin内部的閹割版,後來感覺這可能是和kafka的設計思想有關系,有句話好像是這麼說的:“在計算機領域,一些比較複雜的問題,往往是不需要解決的”,那既然這樣總要有人來做,是以架構對Kafka Consumer做了一些特性增強。

一款消息隊列的用戶端架構——啟明資訊車聯網MQ演進實踐分享

一個最主要的特性是消費模式的增強,分了兩種模式:

MODEL_1:是預設的模式,每一個線程消費一個分區(partition)的資料,缺點就是并行度受限于Topic的分區總數,

MODEL_2:之前也說過kafka并不适用于過多分區;是以把消費線程與處理線程分離,在消費線程受限的情況下,增加處理線程能夠有效提高吞吐量,但是缺點就是不能保證消息順序。

一款消息隊列的用戶端架構——啟明資訊車聯網MQ演進實踐分享

然後還有批量處理的特性,

NON_BATCH:預設是非批量的,一條一條的處理。

BATCH:在批量場景下使用批量處理能提高消費端的處理能力,比如批量入庫。

一款消息隊列的用戶端架構——啟明資訊車聯網MQ演進實踐分享

Message Retry,這是一個容錯機制,就是消息處理出現異常時,可重新處理,能提高了資料可靠性,但是目前僅在非批量處理時可用。

(這些特性隻是針對kafka增加,并沒有對 RocketMQ做增強,因為RocketMQ已經具備了這些特性,是以架構沒有過多封裝,API和配置盡量全都用的它自己的。)

一款消息隊列的用戶端架構——啟明資訊車聯網MQ演進實踐分享

至于為什麼不封裝成一套統一的API,所有的接口和配置全都由架構實作,從代碼層面就讓MQ完全透明(Spring Cloud的做法),因為封裝過度會産生一些問題:

一方面是可能會屏蔽原因特性,因為随着MQ的疊代更新,肯定會有些新特性,如果架構無法跟上MQ的疊代速度,這些新特性可能會被屏蔽,而且未來的維護成本也很巨大。

另一方面就是性能,架構過度封裝,本身就會占用很多資源,肯定會影響性能。

一款消息隊列的用戶端架構——啟明資訊車聯網MQ演進實踐分享

針對這個架構進行了性能測試和性能對比,以Kafka用戶端為例,因為對kafka的API封裝的比較多。對直接使用Kafka API、使用用戶端架構、和使用spring cloud stream做了對比。

測試伺服器用的是阿裡雲的ECS 4核8G,測試場景完全一樣。

Kafka Native API:TPS 80W+

Client Framework API:TPS 80W-

Spring Cloud API:TPS 10W+

從測試結果上來看性能差距還是很大的,是以如果對吞吐和成本有很高要求,其實不建議使用Spring Cloud,不過Spring Cloud封裝的确很好,使用也非常友善,是以就要自己衡量了,就像很多在開源微服務架構技術選型上,最終還是放棄Spring Cloud,而使用Dubbo是一個道理,即便是Spring Cloud提供了非常豐富的微服務套件。

一款消息隊列的用戶端架構——啟明資訊車聯網MQ演進實踐分享

最後分享一個大件事,OpenMessaging,在2017杭州雲栖大會,由阿裡和其他幾家公司共同發起的分布式消息領域的國際标準。

目标打造廠商中立,面向雲原生,對流計算和大資料生态友好的分布式消息标準,未來就可以在不同廠商的産品和平台之間進行無縫遷移。

目前RocketMQ和Pulsar完成了對OpenMessaging支援,後續會推動更多消息中間件廠商落地該标準。

結束語:目前這個消息隊列用戶端架構隻支援ActiveMQ、RocketMQ和Kafka,接下來也會考慮把OpenMessaging內建到這個架構裡面,如果感興趣的小夥伴也可以加入進來,非常的歡迎,一起把它完善的更好。