主要原因:是在高並發情況下,由於來不及同步處理,請求往往會發生堵塞,比如諸多的insert、update之類的請求同時到達mysql,直接導致無數的行鎖表鎖,甚至最后請求會堆積很多,從而觸發大量的too mang connnections錯誤。通過消息隊列,我們可以異步處理請求,從而緩解系統的壓力。
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
MQ(message queue)是一種跨進程的通信機制,用於上下游傳遞消息。
mq的特點:
1、先進先出
不能先進先出,都不能說是隊列了,消息隊列的順序在入隊時基本已經確定,一般是不需要人工干預的。而且最重要的是,數據是只有一條數據在使用中,這也是mq在眾多場景中被使用的原因。
2、發布訂閱
發布訂閱是一種很高效的處理方式,如果不發生阻塞,基本可以當做是同步操作。這種處理方式能非常有效的提升服務器利用率,這樣的應用場景非常廣泛。
3、持久化
持久化確保MQ的使用不只是一個部分場景的輔助工具,而是讓MQ能像數據庫一樣存儲核心的數據。
4、分布式
在現在大流量、大數據的使用場景下,只支持單體應用的服務器軟件基本是無法使用的,支持分布式的部署,才能被廣泛使用。而且,MQ的定位就是一個高性能的中間件。
應用場景
基於上文所述的特點,那么MQ就衍生出了很多的使用場景,在大型的系統中,應用非常廣泛,這里我們就列舉一下常見的應用場景。
應用解耦(異步)
系統之間進行數據交互時,在時效性和穩定性之間我們都要進行選擇;基於線程的異步處理,能確保用戶體驗,但在極端情況下,可能會出現異常,影響系統的穩定性,而同步調用很多時候無法保證理想的性能,那么我們就可以用mq來進行處理,上游系統將數據投遞到mq,下游系統取mq的數據進行消費,投遞和消費可以用同步的方式處理,因為mq接收數據的性能是非常高的,不會影響上游系統的性能,那么下游系統的及時率能保證嗎?當然可以,不然就不會有下面的一個應用場景。
通知
這里就用到了前文一個重要的特點,發布訂閱,下游系統一直在監聽MQ的數據,如果MQ有數據,下游系統則會按照 先進先出 這樣的規則, 逐條進行消費 ,而上游系統只需要將數據存入MQ里,這樣既降低了不同系統之間的耦合度,同時也確保了消息通知的及時性,而且也不影響上游系統的性能。
限流
上文有說了一個非常重要的特性,MQ 數據是只有一條數據在使用中。 在很多存在並發,而又對數據一致性要求高,而且對性能要求也高的場景,如何保證,那么MQ就能起這個作用了。不管多少流量進來,MQ都會讓你遵守規則,排除處理,不會因為其他原因,導致並發的問題,而出現很多意想不到臟數據。
數據分發
MQ的發布訂閱肯定不是只是簡單的一對一,一個上游和一個下游的關系,MQ中間件基本都是支持一對多或者廣播的模式,而且都可以根據規則選擇分發的對象。這樣上游的一份數據,眾多下游系統中,可以根據規則選擇是否接收這些數據,這樣擴展性就很強了。
PS:上文中的上游和下游,在MQ更多的是叫做生產者(producer)和消費者(consumer)
分布式事務
分布式事務是我們開發中一直盡量避免的一個技術點,但是,現在越來越多的系統是基於微服務架構開發,那么分布式事務成為必須要面對的難題,解決分布式事務有一個比較容易理解的方案,就是二次提交。基於MQ的特點,MQ作為二次提交的中間節點,負責存儲請求數據,在失敗的情況可以進行多次嘗試,或者基於MQ中的隊列數據進行回滾操作,是一個既能保證性能,又能保證業務一致性的方案,當然,這個方案的主要問題就是定制化較多,有一定的開發工作量。
應用示例
為了更加直觀的展示MQ的應用場景,這里我們就用一個常見的電商系統中的幾個業務,來具體說明下MQ在實際開發中應用場景。
我們的實際場景大概是一個基於微服務架構的電商系統,分為用戶微服務、商品微服務、訂單微服務、促銷微服務等。基於微服務模式開發的系統,MQ的使用場景更多,下面我們逐一說明:
1、注冊后我們可能需要做很多初始化的操作,如:調用郵件服務器發送郵件、調用促銷服務贈送優惠劵、下發用戶數據到客戶關系系統等。那么這時候我們將這些操作去監聽MQ,當用戶注冊成功過后,通過MQ通知其他業務進行操作。確保注冊用戶的性能。
2、后台發布商品的時候,商品數據需要從數據庫中轉換成搜索引擎數據(基於elasticsearch),那么我們應該將商品寫入數據庫后,再寫入到MQ,然后通過監聽MQ來生成elasticsearch對應的數據。
3、用戶下單后,24小時未支付,需要取消訂單。以前我們可能是定時任務循環查詢,然后取消訂單。實際上,我更推薦類似延遲MQ的方式,避免了很多無效的數據庫查詢,將一個MQ設置為24小時后才讓消費者消費掉,這樣很大程度上能減輕服務器壓力。
4、支付完成后,需要及時的通知子系統(進銷存系統發貨,用戶服務積分,發送短信)進行下一步操作,但是,支付回調我們都是需要保證高性能的,所以,我應該直接修改數據庫狀態,存入MQ,讓MQ通知子系統做其他非實時的業務操作。這樣能保證核心業務的高效及時。
注意事項
其實,還有非常多的業務場景,是可以考慮用MQ方式的,但是很多時候,也會存在濫用的情況,我們需要清楚認識我們的業務場景:
發驗證碼短信、郵件,這種過分依賴外部,而且時效性可以接收幾十秒延遲的,其實更好的方式是多線程異步處理,而不是過多依賴MQ。
秒殺搶購確保庫存不為負數,更多的依賴高性能緩存(如redis),以及強制加鎖,千萬不要依賴消費者最終的返回結果。(實際工作中已經看到好幾個這樣的案例了)上游-下游 這種直接的處理方式效率肯定是比 上游-MQ-下游 方式要高,MQ效率高,是因為,我只是上游-MQ 這個階段就當做已經成功了