隊列做爲一種比較抽象的數據結構,在程序世界中被普遍的應用,而實現方式和形態也各式各樣,有使用進程內堆棧實現的,如stl庫中的queue;有基於管道、Shmem實現的,如常見的同機進程間通訊模型,而隨着分佈式系統應用愈來愈普遍,跨機通訊的場景需來需多,面臨的問題不只是消息投遞問題,分佈式系統普適性的挑戰也隨着應用場景的多樣性而愈來愈多。java
一個優秀的分佈式消息隊列,我的分析應該具有如下的能力:高吞吐、低時延(因場景而異),傳輸透明,伸縮性強,有冗災能力,一致性順序投遞,同步+異步的發送方式,完善的運維和監控工具,開源。但上面的能力有一些在設計理念上多是相悖的,或者是應用場景不一樣,在最終的實現上會有所側重。以騰訊互娛內部普遍使用的TBUS\TBUSD爲例,最爲看重的是一致性順序投遞以及低時延,但傳輸上作不到透明,須要使用者手工初始化隊列,瞭解整個網格的拓撲,另外故障後也須要手工處理。和TSFG的負責人溝通,新版本在研發中的TBUS正在解決這個問題,從而減小使用者的學習和運營成本。golang
從消息傳輸模型上,大體能夠抽象爲如下幾種:apache
點對點模型(Point-to-point)api
基礎模型中,只有一個發送者、一個接收者和一個分佈式隊列。以下圖所示:安全
生產者消費者模型(Producer–consumer)服務器
若是發送者和接收者均可以有多個部署實例,甚至不一樣的類型;可是共用同一個隊列,這就變成了標準的生產者消費者模型。在該模型,三個角色通常稱爲生產者(Producer)、分佈式隊列(Queue)、消費者(Consumer)。markdown
發佈訂閱模型(PubSub)數據結構
若是隻有一類發送者,發送者將產生的消息實體按照不一樣的主題(Topic)分發到不一樣的邏輯隊列。每種主題隊列對應於一類接收者。這就變成了典型的發佈訂閱模型。在該模型,三個角色通常稱爲發佈者(Publisher),分佈式隊列(Queue),訂閱者(Subscriber)。併發
看下業界,開源的分佈式消息隊列有不少種,側重的維度也略有不一樣,包括支持的消息模型也有一些差別,若是按是否有獨立進程來看,能夠分爲兩個大類:負載均衡
Broker
Broker類的分佈式消息隊列,是指有獨立部署進行的分佈式服務,即發送者把消息發佈到Broker進程,再由Broker進程推(或者是拉)給訂閱者。
RabbitMq
RabbitMQ是使用Erlang編寫的一個開源的消息隊列,自己支持不少的協議:AMQP,XMPP, SMTP, STOMP,也正因如此,它很是重量級,更適合於企業級的開發。同時實現了Broker構架,這意味着消息在發送給客戶端時先在中心隊列排隊。對路由,負載均衡或者數據持久化都有很好的支持。
RocketMq
RocketMq是由阿里研發團隊開發的分佈式隊列,側重在消息的順序投遞、高吞吐量、可靠性,在阿里內部大量使用,屢次在雲棲社區中被說起是「淘寶雙11」的保障。目前已捐贈給Apache軟件基金會。
Nats
Ruby-Nats做者開發,Derek Collison自稱作了20多年的MQ,並經歷過TIBOC、Rendezvous、EMC公司. 目前由Apcera公司維護,提供源碼、二進制文件以及Docker鏡像,用戶有愛立信、HTC、百度、西門子、Vmware.Nats用Golang編寫,Nats的設計思念中消息的成功投遞不作保證,須要發送者本身維護,所以Nats在應用場景上仍是比較有侷限性。
Nats-streaming
目前由Apcera公司維護,也採用Golang編寫,在保證吞吐量和時延的基礎上,解決了Nats消息投遞一致性的問題。以前和Apcera的Community Manager有過接觸,Apcera目前只有5位工程師在進行開發維護,因此Nats-streaming目前支持的客戶端API還比較少,只有Go、Java、Nodejs、C#,CAPI支持可能要到2017年中。
Kafka
Kafka是Apache下的一個子項目,是一個高性能跨語言分佈式發佈/訂閱消息隊列系統,而Jafka是在Kafka之上孵化而來的,即Kafka的一個升級版。具備如下特性:快速持久化,能夠在O(1)的系統開銷下進行消息持久化;高吞吐,在一臺普通的服務器上既能夠達到10W/s的吞吐速率;徹底的分佈式系統,Broker、Producer、Consumer都原生自動支持分佈式,自動實現負載均衡;支持Hadoop數據並行加載,對於像Hadoop的同樣的日誌數據和離線分析系統,但又要求實時處理的限制,這是一個可行的解決方案。Kafka經過Hadoop的並行加載機制統一了在線和離線的消息處理。Apache Kafka相對於ActiveMQ是一個很是輕量級的消息系統,除了性能很是好以外,仍是一個工做良好的分佈式系統。
ActiveMq
ActiveMQ是Apache下的一個子項目。 相似於ZeroMQ,它可以以代理人和點對點的技術實現隊列。同時相似於RabbitMQ,它少許代碼就能夠高效地實現高級應用場景。
Brokerless
Brokerless類的消息隊列,主要採用api的方式,編譯到應用程序中,在應用程序間進行點對點的通訊。
ZeroMq
ZeroMQ號稱最快的消息隊列系統,尤爲針對大吞吐量的需求場景。ZeroMQ可以實現RabbitMQ不擅長的高級/複雜的隊列,可是開發人員須要本身組合多種技術框架,技術上的複雜度是對這MQ可以應用成功的挑戰。ZeroMQ具備一個獨特的非中間件的模式,你不須要安裝和運行一個消息服務器或中間件,由於你的應用程序將扮演這個服務器角色。你只須要簡單的引用ZeroMQ程序庫,可使用NuGet安裝,而後你就能夠愉快的在應用程序之間發送消息了。可是ZeroMQ僅提供非持久性的隊列,也就是說若是宕機,數據將會丟失。其中,Twitter的Storm 0.9.0之前的版本中默認使用ZeroMQ做爲數據流的傳輸(Storm從0.9版本開始同時支持ZeroMQ和Netty做爲傳輸模塊)。
NanoMq
在技術選型時,咱們通常從三個維度上去考量,吞吐量、時延、可靠性,不一樣的業務場景對兩個維度的技術指標會有比較大的差別。 好比阿里的rocketmq,由於面臨秒級的高併發場景,所以會十分看中吞吐量和消息的可靠性(不丟、順序投遞),而時延基本在100ms的級別,再好比kafka,最高的設計初衷也是作爲分佈式日誌系統,由於看中的也是高吞吐量和可靠性。但對於遊戲業務,實時音視頻業務,不太會面臨瞬間的訪問高峯,而對低時延、時延穩定性會更加看中,通常認爲消息投遞應該在1-4ms之內。
既然業界有如此豐富的組件,是否能夠找到一種比TBUS更優的同時也適合遊戲服務器的組件呢?帶着這個問題,做者對Kafka、Nats、Nats-streaming進行了測試,主要關注時延、吞吐量、消息安全性這三個維度上。測試方法以下:搭建了兩臺機器,發送者和接收者在同一臺物理機,broker部署在另外一臺機,兩臺機器ping時延在0.8ms左右。 測試結果以下:
得益於JAVA的跨平臺能力,Kafka不須要安裝,可直接運行。 由於Kafka藉助zookeeper進行節點的故障探測與路由管理,因些須要先啓動zookeeper。
測試版本爲kafka_2.10-0.10.0.1 ,測試的時候碰到一些小問題,啓動不成功,後面看了下,kafka啓動不成功,常見的有兩個問題,一是內存不夠,由於java虛擬機運行時須要配置內存大小,若是內存不夠能夠調整下運行腳本。 二是jmx服務,註釋掉bin/kafka-run-class.sh 下的這幾行就ok。
# JMX settings #if [ -z "$KAFKA_JMX_OPTS" ]; then # KAFKA_JMX_OPTS="-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false " #fi # JMX port to use #if [ $JMX_PORT ]; then # KAFKA_JMX_OPTS="$KAFKA_JMX_OPTS -Dcom.sun.management.jmxremote.port=$JMX_PORT " #fi
由於Kafka本週對消息是持久化的,可靠性不須要測試,所以主要關注時延和吞吐量,測試結果顯示吞吐量能達到65M/s, 很顯然是進行過了合包,但時延的表現不是很理想,無送包有多小,消息發送後,Consumer收到的時延的最小極限在32ms,調整了不少參數,都無然進行一步優化。
路由模式上,Kafka只支持發佈\訂閱模型,即一個消息只能被一個訪閱者收到,在這一點Nats更豐富一些。 整理的測試結果來看,Kafka作爲一個分佈式日誌\流水\經營分析系統,仍是很不錯的,難怪不少2B的系統以及電商金融類的產品都在使用。
正如上面介紹的,Nats是由原Ruby-Nats做者Derek Collison設計開發,目前由Apcera維護,由golang語言編寫,研發團隊只有5我的,受限於團隊的規模,所以在API的支持上有必定的侷限性。感興趣的同窗能夠看下源碼,協程的功能劃分十分清晰,一些用法也很巧妙。 Nats和Nats-streaming最大的區別在於,Nats異步模式須要發送者本身處理消息丟失的問題,即不保證消息的「100%投遞成功」,也不作消息暫存, 而Nats-streaming解決了這個問題。
在吞吐量、時延測試上,兩者表現也十分優異。 做者實測結果顯示,100W條消息投遞時耗時在3-4s,1秒能夠投遞30-40w條消息,1k條消息投遞耗時在1毫秒,徹底能夠知足像多人遊戲等對時延比較挑剔的場景。
從路由模式上,Nats的支持很是豐富,支持如下三種:
Publish Subscribe
發佈訂閱模式,一對多,一個消息多個訂閱者均可以收到,相似廣播的場景。支持同步和異步調用。
Request Reply
發送應答模式,Nats支持一對一和一對多的發送應答模式,能夠手工指定有幾個訂閱者能夠收到。發送應答模式採用同步調用。
Queue
隊列模式,一個消息發佈後,只有一個訪閱者會收到,支持同步和異步調用。這個模式對於一些無狀態處理服務十分有用,好比數據倉庫的無狀態接入層,接入層可部署多臺物理機組成一個集羣,每一個物理機無狀態,採用這個方式即達到了冗災能力,同時也能夠保證每個消息只會被處理一次。
從測試結果來看,Nats-streaming在安全性、時延、吞吐量上均可以達到一個比較好的水平,惟一不足的是API對各語言支持的還不夠,CAPI可能要到2017年才能release.
分佈式消息隊列種類不少,沒有精力一一測試,在網上找了一個比較權威的測試結果跟你們分享下。
測試包量和發佈速率以下所示,每次測試持續時間在30S以上。
256B requests at 3,000 requests/sec (768 KB/s) 1KB requests at 3,000 requests/sec (3 MB/s) 5KB requests at 2,000 requests/sec (10 MB/s) 1KB requests at 20,000 requests/sec (20.48 MB/s) 1MB requests at 100 requests/sec (100 MB/s)
時延統計爲一次發佈並收到回包的總體耗時,在不一樣的包量和發佈量的分佈以下:
Nats VS Redis
Kafka VS RabbitMQ