本文來自阿里云云棲社區,未經許可禁止轉載。

更多資訊,盡在雲棲科技快訊~

來科技快訊看新聞鴨~

快點關注我認識我愛上我啊~~~

消息中間件(MOM)的準備知識

請自行補充下相關基礎知識

metaq是什麼?

是一個基於“發佈-訂閱”的隊列模型消息中間件,服務端使用JAVA編寫,客戶端支持JAVA、C++。

對外已開源,名字叫RocketMQ。

metaq的特性

消費模型

metaq採用發佈-訂閱模型,發佈者發佈消息到metaq,訂閱者向metaq訂閱消息。

消息的消費方式是pull方式,由消費者主動從metaq服務器拉取數據,解析成消息並消費。

消息持久性

metaq 接收到消息之後,會先把消息持久化到本地。

常用的持久化方式:

持久化到DB持久化到KV存儲,如levelDB,伯克利DB持久化到文件

metaq使用的是 持久化到文件 ,並充分利用Linux文件系統內存cache來提高性能。

注: 持久化部分的性能會直接影響消息中間件的性能。

消息堆積能力:metaq每臺服務器提供大約億級的消息堆積能力(多個業務方共用),超過堆積閾值,訂閱消息吞吐量會下降。

消息過濾

對於應用比較多,訪問量比較大的情況,消息量也就隨之增大,一方面服務端給每個客戶端發送消息時,總不能把全站的消息都發送過去,這樣大量的無用消息在網絡上傳輸是一種資源浪費。另一方面,客戶端也不需要接收所有的消息,而只需要接收自己需要的消息。這時,消息中間件就需要一個消息過濾的功能。

metaq支持兩種過濾方式:服務器端過濾,客戶端過濾。

服務器端過濾: 優點 是減少網絡上無用消息的傳輸, 缺點 是增加服務端負擔,實現複雜客戶端過濾: 優點 是可以完全根據自己的需要定製哪些需要哪些不要, 缺點 是很多無用的消息要傳輸到客戶端。如果客戶端對應的應用不足以支撐這麼多消息,就會造成應用的所有計算資源全部都在處理這些消息,甚至拖垮整個應用。

消息實時性

metaq客戶端通過長輪詢的方式連接服務端,可以保證消息非常實時,實時性不低於push

每個消息至少投遞一次

Consumer先pull消息到本地,消費完之後,纔會向服務器返回。

爲了追求性能,metaq並不保證消息不重複發送,但是正常情況下很少出現。只有網絡異常,consumer啓動、停止等異常情況下才會出現重複。

本質原因是網絡調用的不確定性,即會出現既不成功也不失敗的第三種狀態。

保證消息局部有序

通過隊列的特性,保證消息的順序。

發送端,將需要保證順序的消息發送到同一個隊列中。消費端,從隊列裏取消息,順序消費。

不同的幾組消息,可以發送到不同的隊列中,提高並行性。

metaq的存儲結構

metaq的邏輯存儲結構是一種物理隊列+邏輯隊列的結構。

物理隊列只有一個,採用固定大小的文件順序存儲消息。邏輯隊列有多個,每個邏輯隊列有多個分區,每個分區有多個索引。

a.消息順序寫入物理文件裏面,每個文件達到一定的大小,新建一個文件繼續順序寫數據(消息的寫入是串行的,避免了磁盤競爭)。

b.消息的索引則順序的寫入邏輯文件中,並不存放真正的消息,只是存放指向消息的索引。

metaq對於客戶端展現的是邏輯隊列就是消費隊列,consumer從消費隊列裏順序取消息進行消費。

這種設計是把物理和邏輯分離,消費隊列更加輕量化。所以metaq可以支撐更多的消費隊列數,提升消息的吞吐量,並且有一定的消息堆積能力。

缺點 :

寫雖然是順序寫,但是讀卻是隨機讀的

解決辦法 :儘可能讓讀命中pageCache,減少磁盤IO次數 (參考下文所述:Linux的文件Cache管理)

metaq的所有消息都是持久化的,先寫入系統PAGECACHE(頁高速緩存),然後刷盤,可以保證內存與磁盤都有一份數據,訪問時,直接從內存讀取。

刷盤策略分爲異步和同步兩種。

Linux的文件Cache管理

在 Linux 操作系統中,爲了加快文件的讀寫,當應用程序需要讀取文件中的數據時,操作系統先分配一些內存,將數據從存儲設備讀入到這些內存中,然後再將數據分發給應用程序;當需要往文件中寫數據時,操作系統先分配內存接收用戶數據,然後再將數據從內存寫到磁盤上。

文件 Cache 管理就是對這些由操作系統分配,並用來存儲文件數據的內存的管理。

Cache 管理的優劣通過兩個指標衡量:

Cache 命中率:Cache 命中時數據可以直接從內存中獲取,不再需要訪問低速外設,因而可以顯著提高性能;有效 Cache 的比率:有效 Cache 是指真正會被訪問到的 Cache 項。如果有效 Cache 的比率偏低,則相當部分磁盤帶寬會被浪費到讀取無用 Cache 上,而且無用 Cache 會間接導致系統內存緊張,最後可能會嚴重影響性能。 在 Linux 的實現中,文件 Cache 分爲兩個層面,一是 Page Cache,另一個 Buffer Cache。 每一個 Page Cache 包含若干 Buffer Cache。

通過內存映射的方式讀寫文件

metaq在文件讀寫操作上做了一定的優化,使用內存映射的方式完成讀寫,替代了傳統的IO操作,從而大大的減少了文件讀寫系統調用的次數,提升了IO的性能。

傳統的文件訪問:

系統調用打開文件,獲取文件描述符使用read write 系統調用進行IO系統調用關閉文件

這種方式是非常低效的, 每一次I/O操作都需要一次系統調用。 另外, 如果若干個進程訪問同一個文件, 每個進程都要在自己的地址空間維護一個副本, 浪費了內存空間

內存映射的方式:

打開文件,得到文件描述符。獲取文件大小把文件映射成虛擬內存(mmap)通過對內存的讀寫來實現對文件的讀寫(memset或memcpy)卸載映射關閉文件

首先建立好虛擬內存和磁盤文件之間的映射(mmap系統調用),當進程訪問頁面時產生一個缺頁中斷,內核將頁面讀入內存(也就是說把磁盤上的文件拷貝到內存中),並且更新頁表指向該頁面。

所有進程共享同一物理內存,物理內存中可以只存儲一份數據,不同的進程只需要把自己的虛擬內存映射過去就可以了,這種方式非常方便於同一副本的共享,節省內存。

經過內存映射之後,文件內的數據就可以用內存讀/寫指令來訪問,而不是用Read和Write這樣的I/O系統函數,從而提高了文件存取速度。

metaq架構&消息的收發

metaq的整體架構如下圖所示,主要包括Broker集羣(metaq的服務端),client集羣(發佈者集羣和訂閱者集羣),nameServer集羣。

Broker分爲master和slave。每個Broker與nameserver集羣中的所有節點建立長連接,定時註冊topic信息到所有的nameServer。

Producer與nameServer集羣中的一個節點(隨機)建立長連接,定期從nameServer 取topic路由信息,並向提供topic服務的master broker建立長連接,且定時向master發送心跳。Producer發佈消息是發佈到master,在由master同步到所有broker。

Consumer與nameServer集羣中的一個節點建立長連接,定期從nameServer取topic的路由信息,並向提供topic服務的master、slave broker建立長連接,並定時向master、slave發送心跳。Comsumer既可以從slave訂閱消息,也可以從master訂閱消息。

保證消息的可靠性

一個消息從發送端應用,到消費端應用,中間有三個過程需要保證消息的可靠性。

1.發送端發消息

消息生產者發送消息後返回SendResult,如果isSuccess返回爲true,則表示消息已經確認發送到服務器並被服務器接收存儲。整個發送過程是一個同步的過程。保證消息送達服務器並返回結果。

只有當消息中間件及時明確的返回成功,才能確認消息可靠到達消息中間件。

2.消息中間件把消息存儲起來

metaq服務器收到消息後首先把消息存放在磁盤文件中,確保持久存儲,寫入成功之後返回應答給發佈者。因此,可以確認每條發送結果爲成功的消息服務器都是寫入磁盤的。

內存中內容屬於非持久數據,會在斷電之後丟失。

3.消費端消費消息

消費者是一條接着一條地順序消費消息,只有在成功消費一條消息後纔會接着消費下一條。

如果在消費某條消息失敗(如異常),則會嘗試重試消費這條消 息(默認最大5次),超過最大次數後仍然無法消費,則將消息存儲在消費者的本地磁盤,由後臺線程繼續做重試。而主線程繼續往後走,消費後續的消息。。由此來保證消息的可靠消費。

metaq消息底層通信組件

metaq消息的傳遞,通信,是使用的netty,並在netty之上作了簡單的協議封裝。

網絡協議如下:

數據部分採用json序列化。

metaq的主要應用場景

1.消息推送

許多系統通過metaq進行消息推送

2.數據庫同步

精衛是通過metaq發消息感知數據庫binlog的變化,並進行數據庫複製的。

精衛是阿里的一個數據庫同步中間件。

精衛首先解析mysql的binlog,然後以消息的形式發往metaq,下游應用(比如終搜,TC,IC等)來消費Mysql數據庫操作的變更事件完成數據庫同步。

整個過程,metaq通過提供嚴格的順序消息,事務消費方式保證了數據的可靠,高效。

3.實時消息

IM對消息實時性要求極高,metaq目前在來往得到了廣泛使用,包括註冊通知、私信、扎堆分享,語音文字消息等功能在使用metaq。

metaq使用長輪詢拉模式,可保證消息同push方式一樣實時,通常在幾個毫秒。

metaq與notify的對比

notifymetaq消息不保證100%有序消息有序push模式(服務端主動推)pull模式(客戶端主動拉)支持分佈式事務不支持基於jms標準基於消息隊列可以選擇持久化or非持久化所有消息都是持久化的不支持消息回溯,只能重發支持消息回溯不支持集羣內廣播消息支持(集羣內每臺機器都能收到消息)適合比較複雜的業務模型輕量級,高性能接入方式更靈活接入方式不如Notify靈活

Push or Pull:

Push模式:很難掌握消息推送的時機和速率,因爲consumer的消費速率不同。Pull模式:consumer可以根據自己的狀況選擇拉取消息的時機和速率,缺點在於如果服務端沒有可供消費的消息,將導致consumer不斷輪詢,浪費資源。

查看原文 >>
相關文章