2019螞蟻金服後端核心部門面試真題:如何保證消息不被重複消費?或者說,如何保證消息消費的冪等性?
歡迎大家關注Java經驗分享,裡面大量BATJ面試題,Java技術乾貨、行業雜談,也歡迎大家投稿~
java經驗分享
面試題
如何保證消息不被重複消費?或者說,如何保證消息消費的冪等性?
面試官心理分析
其實這是很常見的一個問題,這倆問題基本可以連起來問。既然是消費消息,那肯定要考慮會不會重複消費?能不能避免重複消費?或者重複消費了也別造成系統異常可以嗎?這個是 MQ 領域的基本問題,其實本質上還是問你使用消息隊列如何保證冪等性,這個是你架構裏要考慮的一個問題。
面試題剖析
回答這個問題,首先你別聽到重複消息這個事兒,就一無所知吧,你先大概說一說可能會有哪些重複消費的問題。
首先,比如 RabbitMQ、RocketMQ、Kafka,都有可能會出現消息重複消費的問題,正常。因為這問題通常不是 MQ 自己保證的,是由我們開發來保證的。挑一個 Kafka 來舉個例子,說說怎麼重複消費吧。
Kafka 實際上有個 offset 的概念,就是每個消息寫進去,都有一個 offset,代表消息的序號,然後 consumer 消費了數據之後,每隔一段時間(定時定期),會把自己消費過的消息的 offset 提交一下,表示「我已經消費過了,下次我要是重啟啥的,你就讓我繼續從上次消費到的 offset 來繼續消費吧」。
但是凡事總有意外,比如我們之前生產經常遇到的,就是你有時候重啟系統,看你怎麼重啟了,如果碰到點著急的,直接 kill 進程了,再重啟。這會導致 consumer 有些消息處理了,但是沒來得及提交 offset,尷尬了。重啟之後,少數消息會再次消費一次。
舉個例子。
有這麼個場景。數據 1/2/3 依次進入 kafka,kafka 會給這三條數據每條分配一個 offset,代表這條數據的序號,我們就假設分配的 offset 依次是 152/153/154。消費者從 kafka 去消費的時候,也是按照這個順序去消費。假如當消費者消費了 offset=153
的這條數據,剛準備去提交 offset 到 zookeeper,此時消費者進程被重啟了。那麼此時消費過的數據 1/2 的 offset 並沒有提交,kafka 也就不知道你已經消費了 offset=153
這條數據。那麼重啟之後,消費者會找 kafka 說,嘿,哥兒們,你給我接著把上次我消費到的那個地方後面的數據繼續給我傳遞過來。由於之前的 offset 沒有提交成功,那麼數據 1/2 會再次傳過來,如果此時消費者沒有去重的話,那麼就會導致重複消費。