從上一章,大致已經知道消息隊列是什么。
而本章,講述消息隊列在實際項目中的價值,即應用場景。
> 在合適的時候,引入消息隊列,能讓我們的服務架構可用性更高,能力更優秀。
下面,一起來了解消息隊列的應用場景。
# 數據冗余
我們可能在看到“冗余”這個詞的時候,覺得他是個貶義詞。
但實際上,一定程度的冗余,會讓我們的數據更加安全。
比如,數據庫備份,就是一種數據冗余,mysql讀寫分離,亦是通過日志和輪詢實現數據冗余。
**這樣,當我們某一份數據出現問題時,我們還有第二份數據,數據就更加安全。**
那么,消息隊列如何提供冗余功能呢?
> 常見的消息隊列系統,會將數據保存在內存中,以提高數據讀寫效率。既然數據在內存中,就可能出現丟失的情況,所以,它們又提供持久化的功能,保證在隊列系統崩潰后,數據仍然存在。
> 另外,消息隊列內的每一條消息,都必然存在 reserved 和 deleted 兩個狀態,只有當消費者給隊列系統發送處理成功的信號時,消息才會從隊列中刪除,并不會因為消息已接收,就刪除消息。
可以說,消息隊列,也是增對數據庫層的一道輸入向緩存,對數據有冗余作用。即,當有數據需要進入數據庫,會先經過消息隊列,再進入數據庫。
# 解耦合
我們知道軟件工程講究**高內聚低耦合**,所以我們會想許多辦法來控制耦合度,即解耦。
消息隊列,也是一種解耦的方案。
按照普通流程,**消費代碼**可能會直接跟在**生產代碼**后面,那么,生產和消費就成了彼此的上下文,甚至連變量、作用域等都會有依賴,此時,你若對生產代碼的某個變量進行修改,你必須仔細檢查消費代碼是否也使用了這個變量。
> 通過消息隊列,我們將生產代碼和消費代碼拆分開來,它們不再互相依賴彼此的具體實現,只依賴于消息隊列中**消息的結構**。只要消息結構不變,生產代碼和消費代碼如何修改,都不會影響到彼此。
這一點,我們可以聯想到上一章《什么是消息隊列?》中的下單功能輔助理解。
# 異步能力
有人說,**高性能離不開異步,異步離不開隊列**。
一定意義上來說,這句話是很有道理的。
異步,它讓每一個調用都能及時返回,提升響應速度。在這里,可能需要理解一下異步:[《關于異步的理解》](https://www.jianshu.com/p/1593a1d2c002)
隊列,保證了異步調用的處理不會丟失。這句話中的“處理”一詞,指處理工作,是個名詞。
> 我們知道,異步,它先返回的是調用動作是否成功的結果,而具體調用執行的邏輯和結果,并不在這里返回,而是以通知(回調)的形式進行。隊列,是確保每一個調用的處理都會被執行數據結構。
這一點,我們可以在之后消息隊列的實踐中,體會到。
消息隊列,能夠讓在架構上提供異步能力(注意,是架構上,而非代碼層面如函數調用的異步能力)。
關于這個異步能力,還是可以參考上一章《什么是消息隊列?》中的下單功能,
# 擴展性
當架構中加入消息隊列,生產者和消費者就比較容易擴展。
仍然以下單功能舉例,如果生產者和消費者的代碼耦合在一起,互相嚴重依賴,當我們想對生產者產生內容進行不同的處理(消費)時,則需要在原有的源碼中進行擴展,這對原有代碼產生傷害,便不必說擴展性了。
> 但如果以消息隊列將生產者和消費者進行解耦,則,我們只需要添加訂閱消息的消費者程序即可,新的消費者對舊消費者沒有任何傷害,它依舊依賴于消息隊列,只需要確保它能收到消息即可。
# 順序保證
隊列本身具備“先進先出”的特性,消息隊列是一種隊列結構的中間件,則,消費者會根據消息進入的先后順序,進行先后處理。
**其本身就能解決順序問題**
# 削峰填谷
在某些高并發的場景下,流量突然激增,比如秒殺。
此時,數據庫的壓力很大,而數據庫的讀寫處理能力普遍低于內存式的消息隊列。
此時,可以將消息臨時存儲于消息隊列中,減少數據庫的壓力,然后再由消費者按數據庫能夠接受的頻率去讀取消息,進行處理,因為數據庫只在秒殺那一刻壓力很大,平時會清閑一些。
**這就是將山峰削掉,填補山谷**