訊息佇列最簡單入門教程(碼農不會訊息佇列,不如回家養豬)
一、什麼是訊息佇列?
訊息佇列(Message Queue),是分散式系統中重要的元件,其通用的使用場景可以簡單地描述為:
當不需要立即獲得結果,但是併發量又需要進行控制的時候,差不多就是需要使用訊息佇列的時候
二、訊息佇列有什麼用?
1. 非同步處理,提高響應速度
將序列化的功能變成並行化,從而提升系統性能,縮短響應時間
常用於於秒殺、傳送簡訊通知等,需要立即返回結果
2. 流量控制
在高併發的情況,為了避免大師的請求衝擊後端服務,可以使用訊息佇列暫存請求,後端服務按照自己的重能力,從佇列中消費,例如秒殺、埋點場景。
這樣可以隨時增加服務的例項數量水平擴容,而不用對系統的其他部分做修改
3.系統解耦
例如一個下單的資訊需要同步多個子系統,每個子系統都需要儲存訂單的資料的一部分,如果光靠訂單服務的團隊去維護所有的子系統資料同步,代價太大
解決方法是,通過釋出訂閱模型,訂單服務在訂單變化 時傳送一條訊息到一個主題中,所有的下游子系統都訂單主題,這樣可以每個子系統都可以獲得一份完整的訂單資料
即使是增加、減少子系統,也不會對訂單服務造成任務電話號
三、訊息佇列有什麼缺點?
- 同步訊息改成了非同步,增加了系統的呼叫鏈,增加了系統的複雜度
- 降低了資料一致性,如果要保持一致性,需要高代價的補償(如分散式事務、對賬)
- 引入了訊息佇列帶來的延遲問題
四、常見的訊息佇列
RabbitMQ https://www.rabbitmq.com/
優點:輕量,迅捷,容易部署和使用,擁有靈活的路由配置
缺點:效能和吞吐量較差,由於其採用的是Erlang語言不易進行二次開發
RocketMQ http://activemq.apache.org/
優點:效能好,穩定可選,有活躍的中文社群,實時性比較好,
缺點:但是相容性較差,但隨影響力的擴大,以後會有改善
Kafka http://kafka.apache.org/
優點:擁有強大的效能及吞吐量,在大資料和流計算領域,幾乎所有的相關開源軟體都會優先支援kafka
缺點:當訊息數量沒有那麼多的時候,時延會比較高
五、訊息佇列的兩種模型
1. 點對點模型
- 每個訊息只有一個接收者(Consumer),一旦被訊息,就不再在訊息佇列中
- 傳送者和接收者間沒有依賴性,傳送者傳送訊息後,不管有沒有接收者在執行,不會影響下一次傳送
2. 釋出訂閱模型
- 每個訊息可以有多個訂閱者
- 每個訂閱者都可以接收到主題的所有訊息
兩種模型區別
兩個模型的區別:一份訊息是否能被多次消費
如果只有一個訂閱者,兩個模型基本一樣,所以釋出訂閱模型在功能層面是相容佇列模型的
六、訊息佇列如何實現分散式事務
一個嚴格意義的事務實現是ACID4個屬性:原子性、一致性、隔離性、永續性
- 原子性:一個事務操作不可分割,要麼全部成功,要麼全部失敗,不能一半成功一半失敗
- 一致性:事務執行完成之前的時間點,讀到的一定是更新前的資料,之後讀到的一定是更新後的資料
- 隔離性:一個事務的執行不能被其他事務干擾(一個事務內部的操作及使用的資料對正在進行的其他事務是隔離的,併發執行的各個事務之間不能互相干擾)
- 永續性:事務一旦提交,後續的其他操作和故障都不會對事務的結果有任何影響
在分散式系統中,光是要實現資料一致性就已經非常困難了,所以一般只保證達到最終一致性。比較常見的分散式事務實現有
- 2PC(Two-phase Commit)二階段提交
- TCC(Try-Confirm-Cancel)
- 事務訊息
訊息佇列分散式事務實現
Kafka和RocketMQ都提供了事務相關功能,下面以訂單為例看下如何如何實現的
Kafka和RocketMQ都提供了事務相關功能,核心:半訊息
”半訊息“:這個半訊息不是指訊息內容不完整,而是指在事務提交前,對於消費者來說,這個訊息是不可見的(sendMessageInTransaction)
如果資料庫事務提交失敗怎麼辦
- 業務程式碼中反覆重試提交,直到提交成功
- 刪除之前建立的訂單進行補償
- 提供一個反查本地事務狀態介面給MQ,告知成功或失敗(RocketMQ支援)
我的部落格即將同步至騰訊雲+社群,邀請大家一同入駐:https://cloud.tencent.com/developer/support-plan?invite_code=6gzygn4c3