消息隊列已經逐漸成爲企業IT系統內部通訊的核心手段。它具備低耦合、可靠投遞、廣播、流量控制、最終一致性等一系列功能,成爲異步RPC的主要手段之一。前端
消息被處理的過程至關於流程A被處理。咱們這裏以一個實際的模型來討論下,好比用戶下單成功時給用戶發短信,若是沒有這個消息隊列,咱們會選擇同步調用發短信的接口,數據庫
並等待短息發送成功,這時候假設短信接口實現出現問題了,或者短信調用端超時了,又或者短信發送達到上限了,咱們是選擇重試幾回仍是放棄,仍是選擇把這個放到數據庫緩存
過一段時間再看看呢,無論怎樣,實現都很複雜。服務器
咱們能夠將發短信這個請求放在消息隊列裏,消息隊列按照必定的順序挨個處理隊列裏的消息,當處理到發送短信的任務時,通知短信服務發送消息,若是出現以前出現的問題,那麼把這個消息從新放到消息隊列中。網絡
消息隊列的好處:併發
1.成功完成了一個異步解耦的過程。短信發送時只要保證放到消息隊列中就能夠了,接着作後面的事情就行。一個事務只關心本質的流程,須要依賴其餘事情可是不那麼重要的時候,有通知便可,無需等待結果。每一個成員沒必要受其餘成員影響,能夠更獨立自主,只經過一個簡單的容器來聯繫。負載均衡
對於咱們的訂單系統,訂單最終支付成功以後可能須要給用戶發送短信積分什麼的,但其實這已經不是咱們系統的核心流程了。若是外部系統速度偏慢(好比短信網關速度很差),那麼主流程的時間會加長不少,用戶確定不但願點擊支付過好幾分鐘纔看到結果。那麼咱們只須要通知短信系統「咱們支付成功了」,不必定非要等待它處理完成。異步
2.保證了最終一致性,經過在隊列中存聽任務保證它最終必定會執行。分佈式
最終一致性指的是兩個系統的狀態保持一致,要麼都成功,要麼都失敗。固然有個時間限制,理論上越快越好,但實際上在各類異常的狀況下,可能會有必定延遲達到最終一致狀態,但最後兩個系統的狀態是同樣的。
業界有一些爲「最終一致性」而生的消息隊列,如Notify(阿里)、QMQ(去哪兒)等,其設計初衷,就是爲了交易系統中的高可靠通知。
以一個銀行的轉帳過程來理解最終一致性,轉帳的需求很簡單,若是A系統扣錢成功,則B系統加錢必定成功。反之則一塊兒回滾,像什麼都沒發生同樣。
然而,這個過程當中存在不少可能的意外:高併發
可見,想把這件看似簡單的事真正作成,真的不那麼容易。全部跨VM的一致性問題,從技術的角度講通用的解決方案是:
消息隊列的基本功能之一是進行廣播。若是沒有消息隊列,每當一個新的業務方接入,咱們都要聯調一次新接口。有了消息隊列,咱們只須要關心消息是否送達了隊列,至於誰但願訂閱,是下游的事情,無疑極大地減小了開發和聯調的工做量。
3.提速。假設咱們還須要發送郵件,有了消息隊列就不須要同步等待,咱們能夠直接並行處理,而下單核心任務能夠更快完成。加強業務系統的異步處理能力。甚至幾乎不可能出現並發現象。
4.削峯和流控。不對於不須要實時處理的請求來講,當併發量特別大的時候,能夠先在消息隊列中做緩存,而後陸續發送給對應的服務去處理
試想上下游對於事情的處理能力是不一樣的。好比,Web前端每秒承受上千萬的請求,並非什麼神奇的事情,只須要加多一點機器,再搭建一些LVS負載均衡設備和Nginx等便可。但數據庫的處理能力卻十分有限,即便使用SSD加分庫分表,單機的處理能力仍然在萬級。因爲成本的考慮,咱們不能奢求數據庫的機器數量追上前端。
這種問題一樣存在於系統和系統之間,如短信系統可能因爲短板效應,速度卡在網關上(每秒幾百次請求),跟前端的併發量不是一個數量級。但用戶晚上個半分鐘左右收到短信,通常是不會有太大問題的。若是沒有消息隊列,兩個系統之間經過協商、滑動窗口等複雜的方案也不是說不能實現。但系統複雜性指數級增加,勢必在上游或者下游作存儲,而且要處理定時、擁塞等一系列問題。並且每當有處理能力有差距的時候,都須要單獨開發一套邏輯來維護這套邏輯。因此,利用中間系統轉儲兩個系統的通訊內容,並在下游系統有能力處理這些消息的時候,再處理這些消息,是一套相對較通用的方式。
總而言之,消息隊列不是萬能的。對於須要強事務保證並且延遲敏感的,RPC是優於消息隊列的。
對於一些無關痛癢,或者對於別人很是重要可是對於本身不是那麼關心的事情,能夠利用消息隊列去作。
支持最終一致性的消息隊列,可以用來處理延遲不那麼敏感的「分佈式事務」場景,並且相對於笨重的分佈式事務,多是更優的處理方式。
當上下游系統處理能力存在差距的時候,利用消息隊列作一個通用的「漏斗」。在下游有能力處理的時候,再進行分發。
若是下游有不少系統關心你的系統發出的通知的時候,果斷地使用消息隊列吧。
消息隊列的使用場景:
主要特色是異步處理,主要目的是減小請求響應時間和解耦。因此主要的使用場景就是將比較耗時並且不須要即時(同步)返回結果的操做做爲消息放入消息隊列。
可是對於用戶來講,註冊功能實際只須要第一步,只要服務端將他的帳戶信息存到數據庫中他即可以登陸上去作他想作的事情了。至於其餘的事情,非要在這一次請求中所有完成麼?值得用戶浪費時間等你處理這些對他來講可有可無的事情麼?因此實際當第一步作完後,服務端就能夠把其餘的操做放入對應的消息隊列中而後立刻返回用戶結果,由消息隊列異步的進行這些操做。
或者還有一種狀況,同時有大量用戶註冊你的軟件,再高併發狀況下注冊請求開始出現一些問題,例如郵件接口承受不住,或是分析信息時的大量計算使cpu滿載,這將會出現雖然用戶數據記錄很快的添加到數據庫中了,可是卻卡在發郵件或分析信息時的狀況,致使請求的響應時間大幅增加,甚至出現超時,這就有點不划算了。面對這種狀況通常也是將這些操做放入消息隊列(生產者消費者模型),消息隊列慢慢的進行處理,同時能夠很快的完成註冊請求,不會影響用戶使用其餘功能。
爲何須要消息隊列?
生產和消費的速度或者穩定性不一致。
當今市面上有不少主流的消息中間件,如老牌的ActiveMQ、RabbitMQ,煊赫一時的Kafka,阿里巴巴自主開發的Notify、MetaQ、RocketMQ等。
Kafka是一種高吞吐量的分佈式發佈訂閱消息系統,它能夠處理消費者規模的網站中的全部動做流數據。
Kafka 有以下特性: