消息隊列、消息代理和消息中間件的區別和聯繫

若是你常常看技術文章應該聽過「消息隊列」、「消息代理」和「消息中間件」這三個詞,它們有什麼區別和聯繫呢?但願這篇文章能告訴你答案。html

中間件(Middleware)

首先就要說什麼是中間件?個人理解是:git

中間件是幫助應用程序與其餘應用程序、網絡、硬件、操做系統交互或通訊的軟件。github

換句更簡潔的話:「將具體業務和底層邏輯解耦的軟件」。其實符合中間件的軟件範疇很是寬,平常用的Redis、Nginx、Zookeeper、Memcached等等都是「中間件」。所謂的「中間」是相對於架構體系內的,它不涉及具體的業務邏輯也不涉及底層的硬件邏輯,用於用戶數據交換和管理,可以起到「中介」的做用,這就是中間件。數據庫

那麼問題來了:爲何須要中間件的幫助(代理),直接去和對應的應用程序、硬件、操做系統等交互/通訊很差嘛?django

回答問題前,咱們要明確一點:編程

任何中間件必然是爲了解決特定領域的某個(些)問題而出現的。服務器

我舉2個例子來幫助你們理解。網絡

數據庫中間件

當項目很小的時候,直接使用編程語言下的數據庫驅動操做數據庫就能夠了,有些開發會用ORM的方式操做數據庫:這是夠用的。數據結構

但隨着業務發展,數據量和讀寫QPS愈來愈高,主從模式的MySQL實例壓力愈來愈大,單純的對服務器硬件升級已經沒法知足生產環境的須要。在我司不成文的習慣是單表不要超過5千萬條記錄,數據庫量大的時候就設計分庫分表,也就是「分而治之」,把QPS和數據量分片限定在一個範圍內。架構

固然還有不少其餘相關的功能,如讀寫分離、路由策略、統計、管理、鑑權等等。這些是在業務邏輯之上的,不該該在業務代碼中把這部分堆進去,應該抽象它們出來做爲一個獨立的組件,這就是數據庫中間件。

如今主流的開源數據庫中間件有Mycat、MySQL-proxy、Atlas等等,不過如今都不怎麼維護了,另外還有Cetus,做者是tcpcopy的做者,這個項目還在不斷維護,有同窗有興趣的能夠試試。固然其實各大公司內部都有本身的數據庫中間件產品,更多的貼近公司的業務產品和基礎設施。

Web框架中間件

通常Web框架都支持中間件,Web框架中間件的本質是插件系統,是一系列的框架鉤子,在收到請求和返回響應這個過程裏面去作一些額外的事情。中間件種類不少,舉例一些:

  1. 響應壓縮
  2. 記錄日誌
  3. 支持會話Session
  4. CSRF保護
  5. 驗證/身份鑑別
  6. 訪問控制
  7. 資源使用檢查(如內存佔用)
  8. 請求指標
  9. 健康檢查
  10. 靜態資源管理 ...

這些中間件將業務和非業務代碼功能進行解耦:

  1. 框架裏面可能內置了一些經常使用的中間件,也可能只是內置中間件支持。你能夠配置使用某個(些),也能方便的自定義中間件
  2. Web視圖中不須要手寫中間件邏輯,按約定好的用法框架會在對應的生命週期中按照約定的順序去執行這些中間件邏輯

PS: Golang語言中最知名的Web框架Gin支持中間件,並且還官網搞了個叫gin-gonic/contrib的項目蒐集社區裏面的中間件。

消息隊列(Message Queue)

消息隊列就是Message+Queue。其實消息能夠說是一個數據傳輸單位,它包含了建立時間、通道/主題信息、輸入參數等所有數據;隊列(Queue)是一種FIFO(先進先出)的數據結構,編程語言通常都內置(內存中的)隊列實現,能夠做爲進程間通信(IPC)的方法。使用隊列最多見的場景就是生產者/消費者模式:生產者生產消息放到隊列中,消費者從隊列裏面獲取消息消費。

準確的說,消息隊列(如下簡稱MQ**是一種能實現生產者到消費者單向通訊的通訊模型,而通常你們說MQ是指實現了這個模型的中間件,好比RabbitMQ、RocketMQ、Kafka等。

設想一個訂單場景,當你付款成功以後要作什麼:

  1. 通知/提醒系統。通知商家有人買了Ta的商品,通知買家你購買成功(至關於確認訂單)。通知/提醒的方式不少,如郵件、短信、App內消息等等
  2. 會員系統。更新用戶的積分、等級等
  3. 日誌系統。訂單這麼重要的服務須要有日誌能夠用於將來回溯問題
  4. 推薦系統。更新用戶畫像,從新給用戶推薦他可能感興趣的商品 ..

這就出現了一些問題:

  1. 響應耗時。事實上作的比這要多得多,每一項都須要有開銷,增長響應時間。若是這些邏輯是同步執行的,用戶要等多久?這種體驗是徹底不能夠接受的!因此呢,須要一種異步消費的機制
  2. 過分耦合。原本僅僅是一個訂單系統,結果上述的那些東西都要堆進來,這就成了一個巨無霸應用,將來開發、維護都是問題
  3. 錯誤丟失。假如這些後續的行爲中某個(些)服務正好出現了故障執行失敗或者驗證超時,可是付款成功的確認是必須完成的,那麼須要有個地方存這些尚未被正確消費的部分
  4. 須要組(廣)播。就像上面的訂單場景,付款成功這個消息被髮送給多個子系統,至關於組播。將來若是要新增刪減訂閱源,怎麼便捷的實現呢?

固然還有其餘的問題:

  1. 秒殺場景下併發可能會很高的,很是有可能出現出現遠超現有服務器處理能力的狀況,這就容易把系統搞崩了,若是出現這種問題時把未處理的放進消息隊列,這就達到了「削峯」和「限流」的做用。
  2. 某些場景下須要有消息的優先級 ...

而消息中間件就是解決上述問題的,雖然不一樣的中間件的實現方案不一樣,但都具有如下特色:

  1. 分佈式。其實消息中間件解決的就是分佈式系統之間消息傳遞的問題,消費者能夠分佈在多臺服務器上,一方面下降了因爲單點故障引發的消息隊列阻塞的風險,另一方面也很是容易橫向擴展。
  2. 持久可靠。消息隊列通常會把接收到的消息存儲到本地硬盤上,保證消息不會在未消息前莫名丟失。
  3. 高性能和高吞吐量。例如RocketMQ有億級消息堆積能力,普遍應用在阿里系的各類高併發場景下;而Kafka在實時計算、日誌採集等場景下算是業界的標準。

能夠說,消息中間件是如今企業架構中不可或缺的組合部分,用了都說好。

消息代理(Message Broker)

消息代理是一種架構模式,用於消息驗證、變換、路由。雖然不一樣的消息中間件架構和實現各不相同,可是大部分都實現了Broker:其實就是消息中間件服務器,它是中間件的核心。

注意:RabbitMQ、Kafka、RocketMQ等都有消息代理,可是注意,不是全部中間件都這麼選,例如ZeroMQ,它用了套接字風格的API。

在一些地方其實說消息代理就是指消息中間件,如Python語言知名的分佈式任務隊列框架Celery中就這麼稱呼的(所謂的「任務」其實就是一個包含了任務所有數據的消息)。固然,Celery中使用的消息代理比知名的消息中間件範圍廣得多,其餘的如Redis、MongoDB、Zookeeper等均可以做爲消息代理,由於對於Celery來講,它要的只是一個消息存儲的「代理」,相似數據庫這種具有存儲特性的軟件均可以做爲消息代理。

延伸閱讀

原文地址: strconv.com/posts/messa…

  1. github.com/Meituan-Dia…
  2. docs.djangoproject.com/en/2.2/ref/…
  3. dbaplus.cn/news-159-99…
  4. en.wikipedia.org/wiki/Messag…
相關文章
相關標籤/搜索