敢在簡歷上寫訊息佇列,這幾個問題必須拿下!
來源:碼猿技術專欄
大家好,我是不才陳某~
面試官在面試候選人時,如果發現候選人的簡歷中寫了在專案中使用了 MQ 技術(如 Kafka、RabbitMQ、RocketMQ),基本都會丟擲一個問題:在使用 MQ 的時候,怎麼確保訊息 100% 不丟失?
這個問題在實際工作中很常見,既能考察候選者對於 MQ 中介軟體技術的掌握程度,又能很好地區分候選人的能力水平。接下來,我們就從這個問題出發,探討你應該掌握的基礎知識和答題思路,以及延伸的面試考點。
案例背景
以京東系統為例,使用者在購買商品時,通常會選擇用京豆抵扣一部分的金額,在這個過程中,交易服務和京豆服務透過 MQ 訊息佇列進行通訊。在下單時,交易服務傳送“扣減賬戶 X 100 個京豆”的訊息給 MQ 訊息佇列,而京豆服務則在消費端消費這條命令,實現真正的扣減操作。
那在這個過程中你會遇到什麼問題呢?
案例分析
要知道,在網際網路面試中,引入 MQ 訊息中介軟體最直接的目的是:做系統解耦合流量控制,追其根源還是為了解決網際網路系統的高可用和高效能問題。
系統解耦:用 MQ 訊息佇列,可以隔離系統上下游環境變化帶來的不穩定因素,比如京豆服務的系統需求無論如何變化,交易服務不用做任何改變,即使當京豆服務出現故障,主交易流程也可以將京豆服務降級,實現交易服務和京豆服務的解耦,做到了系統的高可用。 流量控制:遇到秒殺等流量突增的場景,透過 MQ 還可以實現流量的“削峰填谷”的作用,可以根據下游的處理能力自動調節流量。
不過引入 MQ 雖然實現了系統解耦合流量控制,也會帶來其他問題。
引入 MQ 訊息中介軟體實現系統解耦,會影響系統之間資料傳輸的一致性。 在分散式系統中,如果兩個節點之間存在資料同步,就會帶來資料一致性的問題。同理,在這一講你要解決的就是:訊息生產端和訊息消費端的訊息資料一致性問題(也就是如何確保訊息不丟失)。
而引入 MQ 訊息中介軟體解決流量控制, 會使消費端處理能力不足從而導致訊息積壓,這也是你要解決的問題。
所以你能發現,問題與問題之間往往是環環相扣的,面試官會藉機考察你解決問題思路的連貫性和知識體系的掌握程度。
那面對“在使用 MQ 訊息佇列時,如何確保訊息不丟失”這個問題時,你要怎麼回答呢?首先,你要分析其中有幾個考點,比如:
如何知道有訊息丟失? 哪些環節可能丟訊息? 如何確保訊息不丟失?
候選人在回答時,要先讓面試官知道你的分析思路,然後再提供解決方案:網路中的資料傳輸不可靠,想要解決如何不丟訊息的問題,首先要知道哪些環節可能丟訊息,以及我們如何知道訊息是否丟失了,最後才是解決方案(而不是上來就直接說自己的解決方案)。就好比“架構設計”“架構”體現了架構師的思考過程,而“設計”才是最後的解決方案,兩者缺一不可。
案例解答
我們首先來看訊息丟失的環節,一條訊息從生產到消費完成這個過程,可以劃分三個階段,分別為訊息生產階段,訊息儲存階段和訊息消費階段。
訊息生產階段: 從訊息被生產出來,然後提交給 MQ 的過程中,只要能正常收到 MQ Broker 的 ack 確認響應,就表示傳送成功,所以只要處理好返回值和異常,這個階段是不會出現訊息丟失的。 訊息儲存階段: 這個階段一般會直接交給 MQ 訊息中介軟體來保證,但是你要了解它的原理,比如 Broker 會做副本,保證一條訊息至少同步兩個節點再返回 ack。 訊息消費階段: 消費端從 Broker 上拉取訊息,只要消費端在收到訊息後,不立即傳送消費確認給 Broker,而是等到執行完業務邏輯後,再傳送消費確認,也能保證訊息的不丟失。
方案看似萬無一失,每個階段都能保證訊息的不丟失,但在分散式系統中,故障不可避免,作為訊息生產端,你並不能保證 MQ 是不是弄丟了你的訊息,消費者是否消費了你的訊息,所以,本著 Design for Failure
的設計原則,你還是需要一種機制,來 Check 訊息是否丟失了。
緊接著,你還可以向面試官闡述怎麼進行訊息檢測? 總體方案解決思路為:在訊息生產端,給每個發出的訊息都指定一個全域性唯一 ID,或者附加一個連續遞增的版本號,然後在消費端做對應的版本校驗。
具體怎麼落地實現呢?你可以利用攔截器機制。 在生產端傳送訊息之前,透過攔截器將訊息版本號注入訊息中(版本號可以採用連續遞增的 ID 生成,也可以透過分散式全域性唯一 ID生成)。然後在消費端收到訊息後,再透過攔截器檢測版本號的連續性或消費狀態,這樣實現的好處是訊息檢測的程式碼不會侵入到業務程式碼中,可以透過單獨的任務來定位丟失的訊息,做進一步的排查。
這裡需要你注意:如果同時存在多個訊息生產端和訊息消費端,透過版本號遞增的方式就很難實現了,因為不能保證版本號的唯一性,此時只能透過全域性唯一 ID 的方案來進行訊息檢測,具體的實現原理和版本號遞增的方式一致。
現在,你已經知道了哪些環節(訊息儲存階段、訊息消費階段)可能會出問題,並有瞭如何檢測訊息丟失的方案,然後就要給出解決防止訊息丟失的設計方案。
回答完“如何確保訊息不會丟失?” 之後,面試官通常會追問“怎麼解決訊息被重複消費的問題? ”
比如:在訊息消費的過程中,如果出現失敗的情況,透過補償的機制傳送方會執行重試,重試的過程就有可能產生重複的訊息,那麼如何解決這個問題?
這個問題其實可以換一種說法,就是如何解決消費端冪等性問題(冪等性,就是一條命令,任意多次執行所產生的影響均與一次執行的影響相同),只要消費端具備了冪等性,那麼重複消費訊息的問題也就解決了。
我們還是來看扣減京豆的例子,將賬戶 X 的金豆個數扣減 100 個,在這個例子中,我們可以透過改造業務邏輯,讓它具備冪等性。
最簡單的實現方案,就是在資料庫中建一張訊息日誌表, 這個表有兩個欄位:訊息 ID 和訊息執行狀態。這樣,我們消費訊息的邏輯可以變為:在訊息日誌表中增加一條訊息記錄,然後再根據訊息記錄,非同步操作更新使用者京豆餘額。
因為我們每次都會在插入之前檢查是否訊息已存在,所以就不會出現一條訊息被執行多次的情況,這樣就實現了一個冪等的操作。當然,基於這個思路,不僅可以使用關係型資料庫,也可以透過 Redis 來代替資料庫實現唯一約束的方案。
在這裡我多說一句,想要解決“訊息丟失”和“訊息重複消費”的問題,有一個前提條件就是要實現一個全域性唯一 ID 生成的技術方案。這也是面試官喜歡考察的問題,你也要掌握。
在分散式系統中,全域性唯一 ID 生成的實現方法有資料庫自增主鍵、UUID、Redis,Twitter-Snowflake 演算法,我總結了幾種方案的特點,你可以參考下。
我提醒你注意,無論哪種方法,如果你想同時滿足簡單、高可用和高效能,就要有取捨,所以你要站在實際的業務中,說明你的選型所考慮的平衡點是什麼。我個人在業務中比較傾向於選擇 Snowflake 演算法,在專案中也進行了一定的改造,主要是讓演算法中的 ID 生成規則更加符合業務特點,以及最佳化諸如時鐘回撥等問題。
當然,除了“怎麼解決訊息被重複消費的問題?”之外,面試官還會問到你“訊息積壓”。 原因在於訊息積壓反映的是效能問題,解決訊息積壓問題,可以說明候選者有能力處理高併發場景下的消費能力問題。
你在解答這個問題時,依舊要傳遞給面試官一個這樣的思考過程: 如果出現積壓,那一定是效能問題,想要解決訊息從生產到消費上的效能問題,就首先要知道哪些環節可能出現訊息積壓,然後在考慮如何解決。
因為訊息傳送之後才會出現積壓的問題,所以和訊息生產端沒有關係,又因為絕大部分的訊息佇列單節點都能達到每秒鐘幾萬的處理能力,相對於業務邏輯來說,效能不會出現在中介軟體的訊息儲存上面。毫無疑問,出問題的肯定是訊息消費階段,那麼從消費端入手,如何回答呢?
如果是線上突發問題,要臨時擴容,增加消費端的數量,與此同時,降級一些非核心的業務。透過擴容和降級承擔流量,這是為了表明你對應急問題的處理能力。
其次,才是排查解決異常問題,如透過監控,日誌等手段分析是否消費端的業務邏輯程式碼出現了問題,最佳化消費端的業務處理邏輯。
最後,如果是消費端的處理能力不足,可以透過水平擴容來提供消費端的併發處理能力,但這裡有一個考點需要特別注意, 那就是在擴容消費者的例項數的同時,必須同步擴容主題 Topic 的分割槽數量,確保消費者的例項數和分割槽數相等。如果消費者的例項數超過了分割槽數,由於分割槽是單執行緒消費,所以這樣的擴容就沒有效果。
比如在 Kafka 中,一個 Topic 可以配置多個 Partition(分割槽),資料會被寫入到多個分割槽中,但在消費的時候,Kafka 約定一個分割槽只能被一個消費者消費,Topic 的分割槽數量決定了消費的能力,所以,可以透過增加分割槽來提高消費者的處理能力。
總結
至此,我們講解了 MQ 訊息佇列的熱門問題的解決方案,無論是初中級還是高階研發工程師,本篇文章的內容都是你需要掌握的,你都可以從這幾點出發,與面試官進行友好的交流。我來總結一下今天的重點內容。
如何確保訊息不會丟失? 你要知道一條訊息從傳送到消費的每個階段,是否存在丟訊息,以及如何監控訊息是否丟失,最後才是如何解決問題,方案可以基於“ MQ 的可靠訊息投遞 ”的方式。 如何保證訊息不被重複消費? 在進行訊息補償的時候,一定會存在重複訊息的情況,那麼如何實現消費端的冪等性就這道題的考點。 如何處理訊息積壓問題? 這道題的考點就是如何透過 MQ 實現真正的高效能,回答的思路是,本著解決線上異常為最高優先順序,然後透過監控和日誌進行排查並最佳化業務邏輯,最後是擴容消費端和分片的數量。
在回答問題的時候,你需要特別注意的是,讓面試官瞭解到你的思維過程,這種解決問題的能力是面試官更為看中的,比你直接回答一道面試題更有價值。
另外,如果你應聘的部門是基礎架構部,那麼除了要掌握本講中的常見問題的主線知識以外,還要掌握訊息中介軟體的其他知識體系,如:
如何選型訊息中介軟體? 訊息中介軟體中的佇列模型與釋出訂閱模型的區別? 為什麼訊息佇列能實現高吞吐? 序列化、傳輸協議,以及記憶體管理等問題 … >
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/70024922/viewspace-2942658/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 訊息佇列簡史佇列
- 訊息佇列常見問題分析佇列
- 全面理解Handler-1:理解訊息佇列,手寫訊息佇列佇列
- 用 Go 寫一個簡單訊息佇列(一):定義訊息和基礎工具Go佇列
- 訊息佇列批次收發訊息,請避開這 5 個坑!佇列
- 離線資料推送問題(訊息佇列)佇列
- 使用 Laravel 訊息佇列要注意的問題Laravel佇列
- 訊息佇列系列一:訊息佇列應用佇列
- 3. 懂了這些,方敢在簡歷上說會用Jackson寫JSONJSON
- 訊息佇列佇列
- 訊息佇列常見面試題佇列面試題
- 每個 Android 開發者必須知道的訊息機制問題總結Android
- redis訊息佇列簡單應用Redis佇列
- “簡單”的訊息佇列與kafka佇列Kafka
- Redis實現簡單訊息佇列Redis佇列
- 訊息佇列(MQ)佇列MQ
- Kafka訊息佇列Kafka佇列
- RabbitMQ訊息佇列MQ佇列
- kafka 訊息佇列Kafka佇列
- POSIX訊息佇列佇列
- 訊息佇列(一)佇列
- 訊息佇列(二)佇列
- 訊息佇列二佇列
- [Redis]訊息佇列Redis佇列
- [訊息佇列]rocketMQ佇列MQ
- [訊息佇列]RabbitMQ佇列MQ
- RabbitMQ 訊息佇列之佇列模型MQ佇列模型
- 如何設計一個訊息佇列?佇列
- 兩個專案用訊息佇列通訊佇列
- 釋出新聞稿必須瞭解的幾個問題
- RabbitMQ,RocketMQ,Kafka 幾種訊息佇列的對比MQKafka佇列
- MQ訊息佇列_RabbitMQMQ佇列
- Java面試—訊息佇列Java面試佇列
- 訊息佇列雜談佇列
- 訊息佇列二三事佇列
- rabbitmq訊息佇列原理MQ佇列
- 訊息佇列設計佇列
- 訊息佇列之RabbitMQ佇列MQ