設計很獨特,它採用pull機制,而不是通常MQ的push模型;大量利用了zookeeper作服務發現和offset存儲;它來源於kafka(scala),可是有本身的特色:事務、多種offset存儲、高可用方案(HA)等。java
MetaQ相對kafka特有功能:python
文本協議設計,很是透明,支持相似memcached stats的協議來監控brokermysql
純Java實現,從通信到存儲,從client到server都是從新實現。git
提供事務支持,包括本地事務和XA分佈式事務github
支持HA複製,包括異步複製和同步複製,保證消息的可靠性web
支持異步發送消息sql
消費消息失敗,支持本地恢復數據庫
多種offset存儲支持,數據庫、磁盤、zookeeper,可自定義實現緩存
支持group commit,提高數據可靠性和吞吐量。安全
支持消息廣播模式
一系列配套項目:python客戶端、twitter storm的spout、tail4j等。
Meta適合的應用:
日誌傳輸,高吞吐量的日誌傳輸原本就是kafka的強項
消息廣播功能,如廣播緩存配置失效。
數據的順序同步功能,如mysql binlog複製
分佈式環境下(broker,producer,consumer都爲集羣)的消息路由,對順序和可靠性有極高要求的場景。
做爲通常MQ來使用的其餘功能
Message Producer:生產者;
Message Consumer:消費者,meta採用pull模型,由消費者主動從meta服務器拉取數據並解析成消息並消費;
topic:消息的主題,由用戶定義並在服務端配置。
partition:分區,同一個topic下面還分爲多個分區;分區跟消費者的負載均衡機制有很大關係。
message:消息;
broker:服務器;
group:消費者能夠是多個消費者共同消費一個topic下的消息,每一個消費者消費部分消息。這些消費者就組成一個分組,擁有同一個分組名稱,一般也稱爲消費者集羣;
Offset:消息在broker上的每一個分區都是組織成一個文件列表,消費者拉取數據須要知道數據在文件中的偏移量,這個偏移量就是所謂offset。Offset是絕對偏移量,服務器會將offset轉化爲具體文件的相對偏移量。詳細內容參見#消息的存儲結構;
生產者可靠性:
消息生產者發送消息後返回SendResult,若是isSuccess返回爲true,則表示消息已經確認發送到服務器並被服務器接收存儲。整個發送過程是一個同步的過程。保證消息送達服務器並返回結果。
服務器可靠性:
消息生產者發送的消息,meta服務器收到後在作必要的校驗和檢查以後的第一件事就是寫入磁盤,寫入成功以後返回應答給生產者。所以,能夠確認每條發送結果爲成功的消息服務器都是寫入磁盤的。
寫入磁盤,不意味着數據落到磁盤設備上,畢竟咱們還隔着一層os,os對寫有緩衝。Meta有兩個特性來保證數據落到磁盤上
每1000條(可配置),即強制調用一次force來寫入磁盤設備。
每隔10秒(可配置),強制調用一次force來寫入磁盤設備。
所以,Meta經過配置可保證在異常狀況下(如磁盤掉電)10秒內最多丟失1000條消息。固然經過參數調整你甚至能夠在掉電狀況下不丟失任何消息。
服務器一般組織爲一個集羣,一條從生產者過來的消息可能按照路由規則存儲到集羣中的某臺機器。Meta已經實現高可用的HA方案,相似mysql的同步和異步複製,將一臺meta服務器的數據完整複製到另外一臺slave服務器,而且slave服務器還提供消費功能(同步複製不提供消費)。
消費者可靠性:
消息的消費者是一條接着一條地消費消息,只有在成功消費一條消息後纔會接着消費下一條。若是在消費某條消息失敗(如異常),則會嘗試重試消費這條消息(默認最大5次),超過最大次數後仍然沒法消費,則將消息存儲在消費者的本地磁盤,由後臺線程繼續作重試。而主線程繼續日後走,消費後續的消息。所以,只有在MessageListener確認成功消費一條消息後,meta的消費者纔會繼續消費另外一條消息。由此來保證消息的可靠消費。
消費者的另外一個可靠性的關鍵點是offset的存儲,也就是拉取數據的偏移量。咱們目前提供瞭如下幾種存儲方案
zookeeper,默認存儲在zoopkeeper上,zookeeper經過集羣來保證數據的安全性。
mysql,能夠鏈接到您使用的mysql數據庫,只要創建一張特定的表來存儲。徹底由數據庫來保證數據的可靠性。
file,文件存儲,將offset信息存儲在消費者的本地文件中。
Offset會按期保存,而且在每次從新負載均衡前都會強制保存一次。
不少人關心的消息順序,但願消費者消費消息的順序跟消息的發送順序是一致的。好比,我發送消息的順序是A、B、C,那麼消費者消費的順序也應該是A、B、C。亂序對某些應用多是沒法接受的。
Metamorphosis對消息順序性的保證是有限制的,默認狀況下,消息的順序以誰先達到服務器並寫入磁盤,則誰就在先的原則處理。而且,發往同一個分區的消息保證按照寫入磁盤的順序讓消費者消費,這是由於消費者針對每一個分區都是按照從前到後遞增offset的順序拉取消息。
Meta能夠保證,在單線程內使用該producer發送的消息按照發送的順序達到服務器並存儲,並按照相同順序被消費者消費,前提是這些消息發往同一臺服務器的同一個分區。爲了實現這一點,你還須要實現本身的PartitionSelector用於固定選擇分區
public interface PartitionSelector { public Partition getPartition(String topic, List<Partition> partitions, Message message) throws MetaClientException; }
選擇分區能夠按照必定的業務邏輯來選擇,如根據業務id來取模。或者若是是傳輸文件,能夠固定選擇第n個分區使用。固然,若是傳輸文件,一般咱們會建議你只配置一個分區,那也就無需選擇了。
消息的順序發送咱們在1.2這個版本提供了OrderedMessageProducer,自定義管理分區信息,並提供故障狀況下的本地存儲功能。
消息的重複包含兩個方面,生產者重複發送消息以及消費者重複消費消息。
針對生產者來講,有可能發生這種狀況,生產者發送消息,等待服務器應答,這個時候發生網絡故障,服務器實際已經將消息寫入成功,可是因爲網絡故障沒有返回應答。那麼生產者會認爲發送失敗,則再次發送同一條消息,若是發送成功,則服務器實際存儲兩條相同的消息。這種由故障引發的重複,meta是沒法避免的,由於meta不判斷消息的data是否一致,由於它並不理解data的語義,而僅僅是做爲載荷來傳輸。
針對消費者來講也有這個問題,消費者成功消費一條消息,可是此時斷電,沒有及時將前進後的offset存儲起來,則下次啓動的時候或者其餘同個分組的消費者owner到這個分區的時候,會重複消費該條消息。這種狀況meta也沒法徹底避免。
Meta對消息重複的保證只能說在正常狀況下保證不重複,異常狀況沒法保證,這些限制是由遠程調用的語義引發的,要作到徹底不重複的代價很高,meta暫時不會考慮。