面試原題
如何保證消息的順序性?mysql
面試官心理分析
其實這個也是用 MQ 的時候必問的話題,第一看看你了不瞭解順序這個事兒?第二看看你有沒有辦法保證消息是有順序的?這是生產系統中常見的問題。面試
面試題剖析
我舉個例子,咱們之前作過一個 mysql binlog
同步的系統,壓力仍是很是大的,日同步數據要達到上億,就是說數據從一個 mysql 庫原封不動地同步到另外一個 mysql 庫裏面去(mysql -> mysql)。常見的一點在於說好比大數據 team,就須要同步一個 mysql 庫過來,對公司的業務系統的數據作各類複雜的操做。sql
你在 mysql 裏增刪改一條數據,對應出來了增刪改 3 條 binlog
日誌,接着這三條 binlog
發送到 MQ 裏面,再消費出來依次執行,起碼得保證人家是按照順序來的吧?否則原本是:增長、修改、刪除;你楞是換了順序給執行成刪除、修改、增長,不全錯了麼。數據庫
原本這個數據同步過來,應該最後這個數據被刪除了;結果你搞錯了這個順序,最後這個數據保留下來了,數據同步就出錯了。架構
先看看順序會錯亂的倆場景:併發
- RabbitMQ:一個 queue,多個 consumer。好比,生產者向 RabbitMQ 裏發送了三條數據,順序依次是 data1/data2/data3,壓入的是 RabbitMQ 的一個內存隊列。有三個消費者分別從 MQ 中消費這三條數據中的一條,結果消費者2先執行完操做,把 data2 存入數據庫,而後是 data1/data3。這不明顯亂了。
- Kafka:好比說咱們建了一個 topic,有三個 partition。生產者在寫的時候,其實能夠指定一個 key,好比說咱們指定了某個訂單 id 做爲 key,那麼這個訂單相關的數據,必定會被分發到同一個 partition 中去,並且這個 partition 中的數據必定是有順序的。
消費者從 partition 中取出來數據的時候,也必定是有順序的。到這裏,順序仍是 ok 的,沒有錯亂。接着,咱們在消費者裏可能會搞多個線程來併發處理消息。由於若是消費者是單線程消費處理,而處理比較耗時的話,好比處理一條消息耗時幾十 ms,那麼 1 秒鐘只能處理幾十條消息,這吞吐量過低了。而多個線程併發跑的話,順序可能就亂掉了。
解決方案
RabbitMQ
拆分多個 queue,每一個 queue 一個 consumer,就是多一些 queue 而已,確實是麻煩點;或者就一個 queue 可是對應一個 consumer,而後這個 consumer 內部用內存隊列作排隊,而後分發給底層不一樣的 worker 來處理。
Kafka
- 一個 topic,一個 partition,一個 consumer,內部單線程消費,單線程吞吐量過低,通常不會用這個。
- 寫 N 個內存 queue,具備相同 key 的數據都到同一個內存 queue;而後對於 N 個線程,每一個線程分別消費一個內存 queue 便可,這樣就能保證順序性。