搜尋
首頁JavaJava面試題【面試】如何保障訊息100%投遞成功?如何保證訊息冪等性?


【面試】如何保障訊息100%投遞成功?如何保證訊息冪等性?

一、前言

我們小夥伴應該都聽說夠訊息中間件MQ,如:RabbitMQ,RocketMQ,Kafka等。引入中間件的好處可以起到抗高並發,削峰,業務解耦的作用。

【面試】如何保障訊息100%投遞成功?如何保證訊息冪等性?

如上圖:

(1)訂單服務投遞訊息給MQ中介軟體(2)物流服務監聽MQ中介軟體,從而進行消費

我們這篇文章討論一下,如何保障訂單服務把訊息成功投遞給MQ中間件,以RabbitMQ舉例。

二、分析問題

小夥伴們對此會有些疑問,訂單服務發起訊息服務,回傳成功不就成功了嗎?如下面的偽代碼:

【面試】如何保障訊息100%投遞成功?如何保證訊息冪等性?

上面程式碼中,一般發送訊息就是這麼寫的,朋友們覺得有什麼問題嗎?

下邊說一個場景,如果MQ伺服器突然宕機了會出現什麼狀況?是不是我們訂單服務寄過去的訊息全部沒有了嗎?是的,一般MQ中間件為了提高系統的吞吐量會把訊息保存在記憶體中,如果不作其他處理,MQ伺服器一旦宕機,訊息就會全部遺失。這個是業務不允許的,造成很大的影響。

三、持久化

有經驗的小夥伴會說,我知道一個方法就是把訊息持久化,RabbitMQ中發送訊息的時候會有個durable參數可以設置,設定為true,就會持久化。

【面試】如何保障訊息100%投遞成功?如何保證訊息冪等性?

這樣的話MQ伺服器即使宕機,重啟後磁碟檔案中有訊息的存儲,這樣就不會遺失了吧。是的這樣就一定機率的保障了訊息不遺失。

但還會有個場景,就是訊息剛剛儲存到MQ記憶體中,但還沒來得及更新到磁碟檔案中,突然宕機了。 (我靠,這個時間這麼短,也會出現,機率太低了吧),這個場景在持續的大量訊息投遞的過程中,會很常見。

那怎麼辦?我們要如何作才能保障一定會持久化到磁碟上面呢?

四、confirm機制

上面問題出現在,沒有人告訴我們持久化是否成功。還好很多MQ有回呼通知的特性,RabbitMQ就有confirm機制來通知我們是否持久化成功?

【面試】如何保障訊息100%投遞成功?如何保證訊息冪等性?

confirm機制的原理:

(1)訊息生產者把訊息傳送給MQ,如果接收成功,MQ會回傳一個ack訊息給生產者;

(2)如果訊息接收不成功,MQ會回傳一個nack訊息給生產者;

【面試】如何保障訊息100%投遞成功?如何保證訊息冪等性?

上面的偽代碼,有兩個處理訊息方式,就是ack回調和nack回調。

這樣是不是就可以保障100%訊息不遺失了呢?

我們來看看confirm的機制,試想一下,如果我們生產者每發一則訊息,都要MQ持久化到磁碟中,然後再發起ack或nack的回呼。這樣的話是不是我們MQ的吞吐量很不高,因為每次都要把訊息持久化到磁碟中。寫入磁碟這個動作是很慢的。這個在高並發場景下是不能夠接受的,吞吐量太低了。

所以MQ持久化磁碟真實的實現,是透過非同步呼叫處理的,他是有一定的機制,如:等到有幾千個訊息的時候,會一次性的刷盤到磁碟上面。而不是每來一則訊息,就刷盤一次。

所以comfirm機制其實是一個非同步監聽的機制,是為了確保系統的高吞吐量,這樣就導致了還是不能夠100%保障訊息不遺失,因為即使加上了confirm機制,訊息在MQ記憶體中還沒刷盤到磁碟就宕機了,還是沒辦法處理。

說了這麼多,還是沒辦法確保,那該怎麼辦呢? ? ?

五、訊息提前持久化 定時任務

#其實本質的原因是無法確定是否持久化?那我們是不是可以自己讓消息持久化呢?答案是可以的,我們的方案再一步的演化。

【面試】如何保障訊息100%投遞成功?如何保證訊息冪等性?

上圖流程:

(1)訂單服務生產者再投遞訊息之前,先把訊息持久化到Redis或DB中,建議Redis ,高性能。訊息的狀態為發送中。

(2)confirm機制監聽訊息是否發送成功?如ack成功訊息,刪除Redis中此訊息。

(3)如果nack不成功的訊息,這個可以根據自身的業務選擇是否重發此訊息。也可以刪除此訊息,由自己的業務決定。

(4)這邊加了個定時任務,來拉取隔一定時間了,訊息狀態還是為發送中的,這個狀態就表明,訂單服務是沒有收到ack成功訊息。

(5)定時任務會作補償性的投遞訊息。這時候如果MQ回呼ack成功接收了,再把Redis中這個訊息刪除。

這樣的機制其實就是補償機制,我不管MQ有沒有真正的接收到,只要我的Redis中的訊息狀態也是為【發送中】,就表示此訊息沒有正確成功投遞。再啟動定時任務去監控,發起補償投遞。

當然定時任務那邊我們還可以加上一個補償的次數,如果大於3次,還是沒有收到ack訊息,那就直接把訊息的狀態設定為【失敗】,由人工去排查到底是為什麼?

這樣的話方案就比較完美了,保障了100%的訊息不遺失(當然不包含磁碟也壞了,可以做主從方案)。

不過這樣的方案,就會有可能發送多次相同的訊息,很有可能MQ已經收到了訊息,就是ack訊息回呼時出現網路故障,沒有讓生產者收到。

那就要要求消費者一定在消費的時候保障冪等性!

六、冪等意義

我們先了解什麼叫冪等?在分散式應用中,冪等是非常重要的,也就是相同條件下對一個業務的操作,不管操作多少次,結果都是一樣。

6.1、為什麼要有冪等這種場景?

為什麼要有冪等這種場景?因為在大型的系統中,都是分散式部署,如:訂單業務 和 庫存業務有可能都是獨立部署的,都是單獨的服務。用戶下訂單,會呼叫到訂單服務和庫存服務。

【面試】如何保障訊息100%投遞成功?如何保證訊息冪等性?

因為分散式部署,很有可能在呼叫庫存服務時,因為網路等原因,訂單服務呼叫失敗,但其實庫存服務已經處理完成,只是返回給訂單服務處理結果時出現了異常。這時候一般系統會作補償方案,也就是訂單服務再此放起庫存服務的調用,庫存減1。

【面試】如何保障訊息100%投遞成功?如何保證訊息冪等性?

這樣就出現了問題,其實上一次呼叫已經減了1,只是訂單服務沒有收到處理結果。現在又呼叫一次,又要減1,這樣就不符合業務了,多扣了。

冪等這個概念就是,不管庫存服務在相同條件下呼叫幾次,處理結果都一樣。這樣才能保證補償方案的可行性。

6.2、樂觀鎖定方案

借鏡資料庫的樂觀鎖定機制,如:

【面試】如何保障訊息100%投遞成功?如何保證訊息冪等性?

根據version版本,也就是在操作庫存前先取得目前商品的version版本號,然後操作的時候帶上此version號。我們梳理下,我們第一次操作庫存時,得到version為1,調用庫存服務version變成了2;但返回給訂單服務出現了問題,訂單服務又一次發起調用庫存服務,當訂單服務傳如的version還是1,再執行上面的sql語句時,就不會執行;因為version已經變成2了,where條件就不成立。這樣就保證了不管呼叫幾次,只會真正的處理一次。

6.3、唯一ID 指紋碼

#原理就是利用資料庫主鍵去重,在業務完成後插入主鍵標識

【面試】如何保障訊息100%投遞成功?如何保證訊息冪等性?
  • #唯一ID就是業務表的唯一的主鍵,如商品ID

  • 指紋碼就是為了區別每次正常操作的碼,每次操作時產生指紋碼;可以用時間戳 業務編號的方式。

上面的sql語句:

  • #傳回如果為0 表示沒有操作過,那麼業務操作後就可以insert into t_check(唯一ID 指紋碼)

  • #返回如果大於0 表示操作過,就直接回傳

##好處:實作簡單

壞處:高並發下資料庫瓶頸

解決方案:根據ID進行分庫分錶進行演算法路由
##### ####6.4、Redis原子操作#########利用redis的原子操作,做個操作完成的標記。這個性能就比較好。但會遇到一些問題。 ######第一:我們是否需要把業務結果進行資料落庫,如果落庫,關鍵解決的問題時資料庫和redis操作如何做到原子性? #########這個意思是庫存減1了,但redis進行操作完成標記時,失敗了怎麼辦?也就是一定要保證落庫和redis 要嘛一起成功,要嘛一起失敗#########第二:如果不進行落庫,那麼都儲存到快取中,如何設定定時同步策略? #########這個意思是庫存減1,不落庫,直接先操作redis操作完成標記,然後由另外的同步服務進行庫存落庫,這個就是增加了系統複雜性,而且同步策略如何設定#########

以上是【面試】如何保障訊息100%投遞成功?如何保證訊息冪等性?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:Java学习指南。如有侵權,請聯絡admin@php.cn刪除

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )專業的PHP整合開發工具

EditPlus 中文破解版

EditPlus 中文破解版

體積小,語法高亮,不支援程式碼提示功能

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。