中間件學習——metaq

jopen 8年前發布 | 28K 次閱讀 中間件 數據庫 Linux 消息系統

該文章來自阿里巴巴技術協會( ATA )精選集

消息中間件(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的對比

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

Push or Pull:

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

    來自: http://yq.aliyun.com/articles/2892

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!