基於netty的消息隊列設計(一)

一.什麼是消息隊列

消息隊列技術是分佈式應用間信息交換的一種技術,消息隊列可駐留在內存或磁盤上,隊列存儲消息直到它們被應用程序讀走,通過消息隊列,應用程序可以獨立地執行,而不需要知道彼此的位置……….當然,上面所說,是比較抽象的,簡單點來說,消息隊列,就是一個消息的轉發器,聯繫應用間關係的樞紐.

二.何時需要消息隊列

上面簡單瞭解了消息隊列,那麼,我們什麼時候會用到消息隊列,用它能給我們的程序帶來什麼好處,這是我們應該考慮的事情.當需要使用消息隊列時,首先需要考慮它的必要性,可以使用mq的場景很多,比如說業務解耦/最終一致性/廣播/錯峯流控等,反之,如果需要強一致性性,RPC更合適.
1.解耦 
解耦是消息隊列要解決的最本質問題。所謂解耦,簡單點講就是一個事務,只關心核心的流程。而需要依賴其他系統但不那麼重要的事情,有通知即可,無需等待結果。換句話說,基於消息的模型,關心的是“通知”,而非“處理”。
舉個例子:我們註冊成功一個網站,註冊成功後往往需要向用戶發送一個郵件通知,但是這其實已經不是我們系統的核心流程了,如果外部系統速度慢,就會有很大的延時,用戶肯定不希望點擊註冊後幾分鐘後纔看到結果,我們只需要通知郵件系統我們註冊成功了,至於郵件什麼時候發,不是用戶直接在乎的.
2.最終一致性:
最終一致性指的是兩個系統的狀態保持一致,要麼都成功,要麼都失敗。當然有個時間限制,理論上越快越好,但實際上在各種異常的情況下,可能會有一定延遲達到最終一致狀態,但最後兩個系統的狀態是一樣的。
舉個例子:
大家都用支付寶給銀行卡轉過帳,如果支付寶扣錢成功,則銀行卡加錢一定成功,反之則一起回滾.
最終一致性,主要是用“記錄”和“補償”的方式。在做所有的不確定的事情之前,先把事情記錄下來,然後去做不確定的事情,結果可能是:成功、失敗或是不確定,“不確定”(例如超時等)可以等價爲失敗。成功就可以把記錄的東西清理掉了,對於失敗和不確定,可以依靠定時任務等方式把所有失敗的事情重新搞一遍,直到成功爲止。
4.錯峯與流控
試想上下流對於事情的處理能力是不同的,比如,Web前端每秒承受上千萬的請求,並不是什麼神奇的事情,只需要加多一點機器,再搭建一些LVS負載均衡設備和nginx等即可,但數據庫的處理能力卻十分有限,這時,消息隊列就能處理這個問題,對於前端的請求先發送到消息隊列中,數據庫處理機器根據自己的最大處理能力從消息隊列服務器上拉數據,消息隊列上堆積的數據可以採用持久化,這樣,即使處理會出現延時,但前端頁面不會出現大量的無響應頁面.

三.消息隊列的設計

前面簡單介紹了消息隊列的基本概念.下面,我就說說我對自己個項目的
設計:

1.項目需求

  • 實現一個基於發佈訂閱的消息隊列.
  • broker提供可靠的消息服務,要保證數據同步落盤後才能向生產者返回發送成功ACK,消費成功,失敗都會返回ack.消費超時重投.
  • 採用實時推送模式(暫時只考慮由broker push消息給消費者),消息一旦到達broker,要立馬推送給消費者,消息延遲不能高於50ms.
  • 消息支持簡單的屬性過濾.
  • 消息存儲基於文件系統(初步設想),自己實現一個簡單的文件系統
  • 消息要先持久化再給發送者響應發送成功,重啓後消息數據不丟失.
    暫時就想到這麼多,以後優化還可以考慮消費者集羣等……

2.消息隊列包含的主要模塊:

  • broker:消息中間件服務器模塊,負責消息的路由、負載均衡,對於生產者、消費者進行消息的應答回覆處理(ACK),是連接生產者和消費者的橋樑樞紐.
  • consumer:消息中間件中的消費者模塊,負責接收生產者過來的消息,在設計的時候,會對消費者進行一個集羣花管理,同一個集羣標識的消費者,會構成一個大的消費者集羣,作爲一個整體,接收生產者投遞過來的消息. 同時,提供消費者接收消息相關的API給客戶端進行調用.
  • producer:消息中間件中的生產者模塊,負責生產特定主題(Topic)的消息,傳遞給對此主題感興趣的消費者,同時提供生產者生產消息的API接口,給客戶端使用。
  • core:消息處理的核心模塊,負責消息的內存存儲、應答控制、對消息進行多線程任務分派處理。
  • model:定義消息類型的數據模型對象.
  • netty:主要封裝了Netty網絡通信相關的核心模塊代碼,比如訂閱消息事件的路由分派策略、消息的編碼、解碼器等等。
  • serialize:利用Kryo這個優秀高效的對象序列化、反序列框架對消息對象進行序列化網絡傳輸。

3.消息隊列的架構設計

這裏寫圖片描述

4.主要的數據結構

  • 請求數據和迴應數據的來源
Consumer,   //這個消息來自消費者.
Broker, //這個消息broker.
Produce  //此消息來自生產者.
  • 生產者或者消費者的請求類型.
Message, //Producer 發送的消息
ConsumerResult, //消費者的消費結果.
Subscript, //Consumer的訂閱消息
Stop //消費者的退訂消息
  • broker的迴應消息類型
SendResult, //broker迴應給生產者的ACK
Message, //消息 由broker發送給消費者的消息.
AckSubscript  //消費者訂閱主題後,broker
  • 生產者和消費者的一次請求的數據結構,不管請求來自誰,.是何類型,客戶端(生產者和消費者)發送的請求的結構體一值爲StormRequest:
private String requestId;  //請求的Id.
private Object parameters; //請求的參數
private RequestResonseFromType fromType;  //消息來自哪裏private RequestType requestType; //請求的類型
  • broker迴應生產者或消費者的消息結構體.
private String requestId; //對應的迴應的是哪個請求
private Object response;// 迴應的消息
private RequestResonseFromType fromtype; //消息來自哪裏
private ResponseType responseType; //響應的類型
  • 訂閱請求消息 
 private String groupId; //消費者屬於哪個消費組.
 private String topic; //消費者要訂閱的主題.
 private String propertieName; //訂閱的過濾屬性名
 private String propertieValue; //訂閱的過濾值
 private String clientKey; //客戶端的id.

在我們的系統中服務器端收到的數據只能是StormRequest,客戶端收到的數據只能是StormResponse.
Producer 是客戶端.
Consumer 也是客戶端,
broker是服務器
producer ——> broker 是request.
consumer ——> broker 是request.
broker ——>consumer 是response
broker ——>producer 是response.
規定以上模型,方便我們對數據的編解碼.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章