天天看點

為什麼需要消息隊列,及使用消息隊列的好處?

一、消息隊列的特性

業務無關,一個具有普适性質的消息隊列元件不需要考慮上層的業務模型,隻做好消息的分發就可以了,上層業務的不同子產品反而需要依賴消息隊列所定義的規範進行通信。

FIFO,先投遞先到達的保證是一個消息隊列和一個buffer的本質差別。

容災,對于普适的消息隊列元件來說,節點的動态增删和消息的持久化,都是支援其容災能力的重要基本特性。當然,這個特性對于遊戲伺服器中大部分應用中的消息隊列來說不是必須的,這個也是跟應用情景有關的,很多時候沒有這種持久化的需求。

性能,這個不必多說了,消息隊列的吞吐量上去了,整個系統的内部通信效率也會有提高。

二、為什麼需要消息隊列?

當系統中出現“生産“和“消費“的速度或穩定性等因素不一緻的時候,就需要消息隊列,作為抽象層,彌合雙方的差異。“ 消息 ”是在兩台計算機間傳送的資料機關。消息可以非常簡單,例如隻包含文本字元串;也可以更複雜,可能包含嵌入對象。消息被發送到隊列中,“ 消息隊列 ”是在消息的傳輸過程中儲存消息的容器 。

舉幾個例子

1)業務系統觸發短信發送申請,但短信發送子產品速度跟不上,需要将來不及處理的消息暫存一下,緩沖壓力。就可以把短信發送申請丢到消息隊列,直接傳回使用者成功,短信發送子產品再可以慢慢去消息隊列中取消息進行處理。

2)調遠端系統下訂單成本較高,且因為網絡等因素,不穩定,攢一批一起發送。

3)任務處理類的系統,先把使用者發起的任務請求接收過來存到消息隊列中,然後後端開啟多個應用程式從隊列中取任務進行處理。

三、使用消息隊列有什麼好處?

3.1、提高系統響應速度

使用了消息隊列,生産者一方,把消息往隊列裡一扔,就可以立馬傳回,響應使用者了。無需等待處理結果。

處理結果可以讓使用者稍後自己來取,如醫院取化驗單。也可以讓生産者訂閱(如:留下手機号碼或讓生産者實作listener接口、加入監聽隊列),有結果了通知。獲得約定将結果放在某處,無需通知。

3.2、提高系統穩定性

考慮電商系統下訂單,發送資料給生産系統的情況。電商系統和生産系統之間的網絡有可能掉線,生産系統可能會因維護等原因暫停服務。如果不使用消息隊列,電商系統資料釋出出去,顧客無法下單,影響業務開展。兩個系統間不應該如此緊密耦合。應該通過消息隊列解耦。同時讓系統更健壯、穩定。

異步化、解耦、消除峰值

以上三點其實可以用一個例子來解釋——設想有一款MMO遊戲,沒有人肉寫的緩存層或者ORM,所有邏輯節點都直連MySQL,邏輯節點内除了要關注場景、戰鬥、互動等複雜邏輯以外,還要有個拼SQL語句的子產品,想想簡直是蛋疼。先考慮一下這樣設計的弊端所在:

1.邏輯節點與Db的互動會有大量IO,即使把與Db互動的子產品耦合在邏輯節點内,其實作對你來說是黑盒,如果内部是同步實作的,那就直接卡你遊戲主邏輯,就因為一次存盤操作,玩家們都掉線了,伺服器也可以關掉了。

2.那麼我們改進一下,針對1的情況,可以把這個子產品做到一個線程裡挂在邏輯節點上。這樣其實邏輯節點跟這個Db前端子產品的互動就會基于一個比較原始的消息隊列。但是這樣還有一個壞處,那就是這兩種任務一種是計算密集的(玩家的邏輯處理)、一種是IO密集的(隻負責寫入讀取MySQL),搞到一個節點中,擴充起來會非常麻煩,而且耦合度太高。比如說現在發現場景放單節點上有瓶頸,要按場景分節點,那麼這種挂在上面的資料子產品怎麼跟其他場景的互動呢?

3.峰值的問題。在分布式系統中,一次分布式事務關聯的是多個節點,其中每一個節點出現問題都會成為整個事務處理流程中的瓶頸。如果邏輯節點與資料庫之間沒有一個起到緩沖作用的節點,那就是每次操作都要通路資料庫,對于MMO來說,一個玩家上線load幾百K資料,一個服10萬個玩家上線已經足夠搞垮一個mysql節點了。如果直接搞垮還是比較好的結果,至少是前面的玩家确實登入上去了并且可以正常遊戲,後面的玩家登入不上。但是很可惜,十年前開始流行的C10K說法就是在講:并發量上來之後,會造成chain reaction,大量的并發不會直接挂掉你的mysql節點,但是會拖慢速度,降低吞吐量,一個玩家的請求由于處理時間太長,導緻玩家放棄重試,但是對于後端來說,對該玩家之前的處理過程消耗的資源就全部浪費了,陷入惡性循環。

是以,這種情景下,一個介于邏輯節點和db節點之間的緩存節點就是理所當然的事情了。這個緩存節點其實很多時候也可以看作是一個更複雜的消息隊列節點。

四、為什麼需要分布式?

4.1、多系統協作需要分布式

消息隊列中的資料需要在多個系統間共享資料才能發揮價值。是以必須提供分布式通信機制、協同機制。

4.2、單系統内部署環境需要分布式

單系統内部,為了更好的性能、為了避免單點故障,多為叢集環境。叢集環境中,應用運作在多台伺服器的多個JVM中;資料也儲存在各種類型的資料庫或非資料庫的多個節點上。為了滿足多節點協作需要,需要提供分布式的解決方案。

五、分布式環境下需要解決哪些問題?

5.1、并發問題

需進行良好的并發控制。確定“線程安全“。不要出現一個訂單被出貨兩次。不要出現顧客A下的單,發貨發給了顧客B等情況。

5.2、簡單的、統一的操作機制

需定義簡單的,語義明确的,業務無關的,恰當穩妥的統一的通路方式。

5.3、容錯

控制好單點故障,確定資料安全。

5.4、可橫向擴充

可便捷擴容。

六、如何實作?

成熟的消息隊列中間件産品太多了,族繁不及備載。成熟産品經過驗證,接口規範,可擴充性強。

結合事業環境因素、組織過程遺産、實施運維考慮、技術路線考慮、開發人員情況等原因綜合考慮。

原文釋出時間為:2018-07-03

本文來自雲栖社群合作夥伴“

Golang語言社群

”,了解相關資訊可以關注“

”。