往軟件系統中添加組件就是嚴重增長複雜性的一種作法。咱們來拿消息隊列舉個例子。html
消息隊列是一個能讓你得到容錯性,分佈式,解耦等架構能力的系統。紙上談兵的話,它看起來還不錯。數據庫
或許消息列隊在你的應用中有很多適用的場景。你能夠看下這篇關於消息隊列優勢的文章,看看到底有哪些合適的場景。但可不要由於說"能解耦那太好了」就輕易使用它。咱們來看一個例子——你但願你的郵件發送和訂單處理互相解耦。網絡
所以你發送一個消息到消息隊列裏,而後郵件處理系統取出這個消息併發送郵件。那你在一個獨立的單classpath的應用中怎麼實現呢?讓你的訂單處理服務依賴於一個郵件服務,而後調用sendEmail()方法,而不是sendToMQ()方法。若是你使用了消息隊列,你須要定義一個兩個系統都能識別的消息格式 ;若是你不使用消息隊列,那麼你得定義一個方法簽名。它們有什麼本質的區別嗎?其實沒有。架構
不過你可能還有別的消費者想要對某個指定的消息進行額外的處理?這的確是可能發生的,而並不僅是針對咱們這裏說到的這個項目而已。儘管確有可能,但相比添加另外一個方法調用而言,它可能並不值當。耦合?是的。不過這個耦合並無什麼不方便的。併發
那我應該如何處理峯值流量?你能夠經過消息隊列將請求放到一個持久化隊列中,而後再一併處理它們。這是一個很是有用的特性,不過它也受限於幾個 因素——你的請求是在UI後臺處理,仍是須要即時響應?serlvet容器的線程池某種程度上能夠看成是一個隊列,用戶最終會拿到響應,可是得須要等待(若是線程的超時時間太短的話,請求可能會丟失)。負載均衡
你可使用一個內存隊列來存儲那些較重的請求(得在UI後臺進行處理)。不過注意了,你的隊列並非默認高可用的。好比說,若是一個消息隊列節點掛掉了,你的消息就丟失了。所以,不去使用應用節點內的內存隊列,而是去使用一個消息隊列,這可能並無什麼優點。異步
消息隊列使得咱們能夠進行異步處理——這的確是個有用的特性。你不但願在用戶等待的時候作一些很重的操做。不過你也可使用一個內存隊列,或者簡單地啓動一個新的線程(好比Spring的@Async註解)。這樣又有另外一個問題——若是消息丟失的話是否有問題?若是你應用處理請求的節點掛了,你能夠進行恢復嗎?你會發現這事會常常發生,若是不保證全部消息都處理到的話,很難保證功能的正確性。所以,僅將較重的調用進行異步處理是比較可取的。分佈式
把消息放到隊列以便讓另外一個組件來進行處理,對於這個場景,若是消息丟失是沒法接受的 ,這也有一個很簡單的解決方案——數據庫。你能夠把一條processed=false的數據存儲到數據庫中。而後再運行一個調度做業,將全部未處理的記錄挑選出來,異步地進行處理。當處理完成的時候,將標記設爲true。我常常用這個方法,包括在一些大型的線上系統中,它也工做得挺好的。學習
這樣你還能不斷地對你的應用節點進行擴展,只要它們的內存中沒有任何的持久化狀態的話。無論你是否使用了消息隊列均可以(臨時的內存處理隊列並不屬於持久化狀態)。spa
爲何我要給常常用到的消息隊列提供一些備選方案?由於若是你因爲不恰當的緣由選擇了它,那麼消息隊列可能會成爲一個負擔。它們並不是如想像中那樣容易使用。首先,它有一個學習曲線。通常來講,你集成的組件切分得越多,就越容易出現問題。其次,還有一個設置及配置的成本。好比說,當消息隊列須要在一個集羣中運行的話,好比說多個數據中心,那麼這就變得複雜了。
高可用性並非上來就有的——默認它是不會打開的。還有就是你的應用節點如何鏈接到消息隊列?經過一個刷新的鏈接池,或者使用短生命週期的DNS記錄,仍是經過一個負載均衡器?你的隊列可能還有許多配置項,大小是多少,行爲是怎樣的(消費者需不須要確認接受,要不要通知處理失敗,多個消費者可以取到同一個消息嗎,消息有沒有TTL,等等)同時還有網絡及消息傳遞的開銷,尤爲是如今你們都喜歡用XML或者JSON來傳輸消息。若是你過分地使用了消息隊列,那麼它會增長你係統的延時。
最後一點,但並非最次要的——若是出現問題的話,使用消息隊列會讓問題跟蹤變得異常困難。你無法在IDE中看到所謂的調用層次,由於一旦你發送消息到隊列裏了,你就得本身去查找它在哪裏處理的了。這可不是聽起來那麼簡單的。你看到了吧,它會給你增長許多的複雜性,以及許多須要注意的東西。
一般而言,在某些上下文中,消息隊列仍是很是有用的。當它們的確適合的話,我也會在項目中使用它們——比方說,咱們不想丟失消息,但又但願能快速地進行處理。我也見過它在一些不太常見的場景中使用的狀況,好比說只有一個應用節點來進行消費,不論是哪一個節點投遞過來的消息。你還能夠看下stackoverflow上的這個問題。還有一些使用場景就是,或許你的確須要進行多語言間的通訊,又或者你的數據流已通過於複雜了,不使用新的消息消費者而是增長新方法調用的話代價會很大。
我想說的是那句老掉牙的真理「殺雞焉用牛刀」。若是你不是很肯定已經沒有別的更容易管理和維護的方法,必定要使用消息隊列的話,最好不要使用它。不要由於」萬一它有用呢「而去用它——只有你確實以爲須要的話再去使用。由於頗有可能,就像這裏說到的這個項目同樣,消息隊列實際上是沒有必要的。