消息隊列為何如此重要?

大家好,我是【架構擺渡人】,一隻十年的程式猿。這是消息隊列的第一篇文章,這個系列會給大家分享很多在實際工作中有用的經驗,如果有收穫,還請分享給更多的朋友。

不知道大家平時是否有使用過Queue相關的類,比如ArrayBlockingQueue,DelayQueue等隊列。如果你說你平時寫業務程式碼都沒用過這些,其實也很正常,但是你其實間接都使用過。

比如執行緒池,這個大家肯定都用過,那麼你想像下,如果你一直往執行緒池裡面丟任務,當任務丟不進去之後會觸發拒絕策略。但是前期的這個任務都是在排隊等待執行,那這些任務暫存在哪裡呢?這個暫存的容器就是Queue。

我們通過ThreadPoolExecutor的構造函數就可以看出是否使用了Queue,程式碼如下:

 public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), handler);
}

可以看出,Queue的作用就是存儲。但是為什麼大家在業務開發中很少直接使用Java中的Queue,那是因為業務程式碼都涉及到數據的存儲,而Queue這些的數據都是在記憶體中,沒有持久化,所以能用的場景比較有限。

雖然沒有用到這些Queue,但是我們卻經常用到一些開源的消息中間件,因為這些中間件都支援了持久化,並且功能更強大,但其實本質上他們都是消息隊列,都是數據暫存的容器。

那麼消息隊列為何如此重要呢?我覺得主要就是可以將系統進行解耦同時能夠非同步處理,提升吞吐量。

系統間的解耦

假設你做的電商的業務,下單後需要給用戶發簡訊,需要移除購物車內的數據等等操作。按正常邏輯那就是在下單邏輯中調用購物車和簡訊服務的介面,那麼此時就相當於直接依賴了簡訊和購物車。

假設購物車服務掛掉了,那麼下單時調用移除介面必然報錯。報錯要處理還是不處理呢?從業務上來說這個報錯肯定不能影響下單對吧,但是這樣就會導致下單後,購物車的數據還存在。那麼必然要對異常的請求進行處理,比如記個日誌,然後人工或者程式進行後置的操作。這樣就麻煩了呀,而且將整個邏輯的複雜度提高了。

如果我們引入了消息隊列,那這件事情就簡單多了。直接將要處理的動作,通過消息的形式告訴消息隊列,只要告訴就完了,然後就可以告訴用戶下單成功了。簡訊服務和購物車服務會去消費消息隊列的消息,然後去執行對應的業務邏輯。我在下圖中對於投遞消息用的是虛線,目的是告訴大家,這塊就解耦了。

假設購物車服務有幾分鐘掛了,那麼等它重啟正常後就會繼續消費消息,然後把對應的數據移除,這裡是最終一致性。

非同步處理,提升吞吐量

這裡就不貼圖了,大家一看上面那張圖就知道了。當下單完成後,消息投遞之後,就立馬返回了。而投遞消息會非常快,因為不涉及到業務邏輯的處理。所以我們通過消息的形式,將一些不需要立馬獲得返回值的業務場景,進行了非同步處理。同時下單的響應時間變短了,吞吐量自然就上來了。

總結

消息隊列之所以在面試過程中必問,也是因為它是我們工作中不可缺少的一款中間件。正因為它的重要性,我們才更要去學習,要了解它的功能特點和使用場景,這樣才能在工作中去解決具體的問題。

原創:架構擺渡人(公眾號ID:jiagoubaiduren),歡迎分享,轉載請保留出處。

本文已收錄至學習網站 //cxytiandi.com/ ,裡面有Spring Boot, Spring Cloud,分庫分表,微服務,面試等相關內容。