消息中間件

  • 消息中間件爲咱們帶來了異步特性,爲系統解耦,對於大型分佈式系統具備很是重大的意義

  • 這樣系統變得很是複雜
  • 引入可擴展配置算是比較優雅的解決方案
    • 下降了開發部署成本
    • 並沒實質性下降複雜性

引入消息中間件解耦服務調用java

  • 只須要向消息中間件發送消息
  • 其餘服務訂閱該消息
  • 成功解耦,不用關心多少系統須要知道登錄成功這個事件
  • 各個系統互不影響

  • 上面用數據庫 記錄中間狀態,寫入時數據庫不可用,仍是會有問題
  • 對於須要感知的應用,須要定時輪詢查看狀態,完成操做也要修改
  • 能解決問題,實現簡單,可是也存在問題:
    • 增長了業務庫的負擔
    • 依賴的複雜和不安全(發短信的服務對數據庫有操做權限,這樣不安全)
    • 擴展性很差

互聯網時代的消息中間件數據庫

  • JMS(java message service)是JavaEE(企業版)關於消息的規範
  • ActiveMQ 等產品是對該規範的實現
    • 企業內部或小型系統直接使用JMS產品是很經濟的
    • 大型系統有一些場景不適合
  • 在大型互聯網中,使用消息中間件,最基礎倆特色
    • 應用之間解耦
    • 操做的異步
  • 重點考慮:
    • 消息的順序保證
    • 擴展性
    • 可靠性
    • 業務操做與消息發送的一致性
    • 及多集羣訂閱者
  • 消息發送一致性
    • 產生消息的業務動做和消息發送的一致性
    • 上述兩種作法,第一種丟失消息的機率是很低的,
    • 可是對於必須保證一致性的場景,上面的兩種方案都不可取
  • JMS 能保證消息發送的一致性嗎?
    • JMS 重要要素
    • JMS 模型分爲:Queue模型(PTP Domain模型)和Topic模型(pub/sub Domain模型)
      • XA 開頭的接口表示支持XA協議(分佈式事務協議)
        • 引入分佈式事務帶來的問題:
          • 帶來開銷增長複雜性
          • 對業務操做有限制,業務操做資源必須支持XA協議
  • 最總一致性方案:

  • 定時重複反向流程,重複查詢就能夠了
    • 大多數狀況下,反向流程是不須要工做的

  • 新方案開銷:僅僅增長了一次網絡通訊、一次更新消息狀態,開銷並不大

  • 如何解決消息中間件和使用者之間的強依賴問題?
    • 思路有三:
      • 增強消息中間件可靠性,使之100%可靠
      • 消息中間件影響業務進行的部分加強可靠性
        • 業務表和消息表放在一個庫,業務應用底層調用數據庫同一個事務操做這倆表,保證一致性
        • 影響有三:
          • 業務庫承載消息數據
          • 消息中間件去訪問業務庫
          • 業務操做的對象是一個數據庫,支持事務的存儲,知足消息的存儲
        • 變通方案
          • 較多的邏輯從消息中間件的服務端挪到了消息中間件的客戶端,而且在業務應用上執行
      • 提供弱依賴支持,可以較好的保證一致性
      • 利用本地磁盤方案
        • 若是消息中間件不可用,並且寫入本地磁盤也壞了,消息就丟了
        • 兩種用法:
          1. 容災方案,平時不用,出現問題才使用
          2. 直接使用,能夠控制調用發送消息接口的時間,好比作批處理
    • 業務應用和發送消息一致性帶來的倆限制:
      • 須要肯定要發送消息的內容
      • 須要實現對業務的檢查(實現反向流程)

消息模型對消息接收的影響緩存

  • JMS Queue 模型(點對點模型):
    • peer to peer 點對點
    • 消息發送出來不能肯定會被誰消費,但只有一個應用回去消費這條消息
  • JMS Topic模型
    • 發送消息和topic內部邏輯與Queue 模型同樣
    • 接收消息很不相同,每一個應用都能接收到全部的消息
    • 每一個鏈接connection 都有惟一clientId
    • 下圖是多連接的狀況:
      • 應用3有兩個鏈接
    • 換作topic 模型
  • 模型須要知足的條件:
    • 一個進程能夠有多個connection鏈接到消息Server
    • topic模型,實際應用中每一個集羣節點可能會很大,這個發送那麼多重複數據負擔太大
    • 整合這倆模型:
      • 面向集羣用topic模型,具體應用使用queue模型來分發
        • 級聯方案:

消息訂閱者訂閱消息的方式:安全

  • 持久訂閱和非持久訂閱
  • 要作到可靠,選擇持久訂閱
    • 接收者應用中止,消息保留,一旦上線再次發送

保證消息可靠性網絡

  • 三個階段均可靠,才能保證消息可靠:
    • 發送階段要有明確的返回成功,才表明成功;
      • 失敗、超時、異常都表明沒成功
    • 消息存儲(持久化存儲)
        • 基於現有能夠選擇分佈式文件系統、關係型數據庫、NOSQL
      • 使用關係型數據庫,不會那麼嚴格按照範式,更多地使用冗餘和寬表
        • 好比 學生id和學生名稱,不少時候要一塊兒展現
        • 單表查詢比多表聯查快的多,名稱字段常常做爲冗餘字段存在
    • 消息中間件存儲,一條消息存儲一條數據
      • 表設計:
      • 單條消息訂閱集羣比較多時,更新投遞次數頻繁,把該字段放到消息表
        • 沒法給投遞列表裏面的單獨的接收者創建索引,損失了這個維度的靈活性
        • 堆積消息多的時候,不能針對特定集羣調度,處理效率低
      • 基於雙機內存保持數據的可靠
        • 內存速度遠超磁盤,可是斷電消失,可考慮雙機內存
        • 一旦一臺出問題,中止另外一臺的寫操做,並把數據落盤
        • 這種適用於大部分消息到了消息中間件後能大部分很快消費掉
  • 消息中間件擴容
    • 消息中間件自己沒有持久狀態擴容簡單
    • 讓發送者接收者感知到,有新的消息中間件加入集羣,可以使用軟負載配置
      • 不一樣消息中間件使用相同存儲,同一個消息中間件使用多個存儲、
      • 消息存儲中加入ServerId 來記錄消息來自哪臺機器
      • 須要注意:
        • 若是某個中間件長時間不可用,考慮加入新機器對應他的ServerId
        • 沒處理完的消息,分給別的機器處理
  • 消息存儲擴容
    • 不存在複雜查詢,服務端主動調度,繞開了根據消息id 取消息
  • 消息投遞可靠性保證
    • 業務處理完再確認
    • 不要吃掉異常,再確認,這樣出現異常消息就丟了
    • 投遞處理優化
      • batch操做
      • 一個應用上多個訂閱者訂閱同一個消息

訂閱者視角,消息重複的產生和應對異步

  • 消息發送端重複發送
    • 解決:相同消息使用同一個id
  • 消息中間件向外投遞重複
    • 中間件不能及時更新已投遞狀態,可用分佈式事務來解決,可是代價高
    • 也可要消息接受者來處理,進行冪等操做:
      • 冪等是一個數學概念
      • 屢次重複操做和一次操做效果同樣

JMS消息確認方式:分佈式

  • AUTO_ACKNOWLEDGE
    • 接收到自動確認
  • CLIENT_ACKNOWLEDGE
    • 調用acknowledge() 函數確認
  • DUPS_ACKNOWLEDGE
    • 客戶端處理函數執行完再確認
  • connection 建立queue 或topic 時設置

消息投遞其餘屬性:函數

  • 優先級
  • 訂閱者消息處理順序和分級訂閱
  • 自定義屬性
  • 局部順序
    • 須要一個屬性區分和哪些消息一塊兒排隊

保證順序的消息隊列的設計性能

  • 單機多隊列
  • 變推(push)爲拉(pull)
  • 多個物理隊列

單機多隊列問題與優化優化

  • 隊列多,查詢性能差
  • 根據隊列作索引

  • 好處:
  • 壞處:
  • 克服壞處:
    • 做緩存
    • 因爲是順序讀取,可採用預讀策略
  • 本地消息存儲可靠性:
    • 把單個消息中間件機器變成Master-slave形式
    • 發送消息向中間件,等slave複製完畢再返回」成功「
  • 隊列擴容:

推(Push)和拉(Pull)對比:

相關文章
相關標籤/搜索