大家好,我是【架構擺渡人】,一隻十年的程式猿。這是訊息佇列的第一篇文章,這個系列會給大家分享很多在實際工作中有用的經驗,如果有收穫,還請分享給更多的朋友。
不知道大家平時是否有使用過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),歡迎分享,轉載請保留出處。
本文已收錄至學習網站 http://cxytiandi.com/ ,裡面有Spring Boot, Spring Cloud,分庫分表,微服務,面試等相關內容。