冪等的這幾個問題沒有考慮到,你恐怕是在寫Bug吧!

免費視頻福利推薦:

2T免費學習視頻,內含精選高頻面試題、SSM、Spring全家桶、微服務、MySQL、MyCat、集羣、分佈式、高併發、中間件、Linux、網絡、多線程,Jenkins、Nexus、Docker、ELK等等免費學習視頻,持續更新!


往期熱門文章推薦:

1、《2019年精選優秀博文都在這裏了!》

2、格式化時間用了YYYY-MM-dd,元旦當天老闆喊我回去改Bug!

3、39 個奇葩代碼註釋,看完笑哭了。。。

4、牛逼的人,都已經開始用文言文寫代碼了!

5、如何優雅地根治null值引起的Bug!


關於冪等處理的幾種方式,不是本文所要闡述的內容,有需要的可以參考:《高併發下的接口冪等性解決方案!

一、冪等的分類

1.1、半冪等

例如:

插入一條數據,調用服務A,A服務插入數據庫的時候,根據主鍵衝突策略,發現已經已經存在了,直接返回錯誤,報已經存在主鍵了;

這種方式,服務A冪等做的不徹底,只是保證數據不會變更,但是通過返回錯誤來實現,這樣的話,就需要調用方先進行一次查詢操作,判斷數據是否存在了,如果存在則不插入,如果不存在再調用A服務插入數據了;

1.2、全冪等

相對的,如果調用的服務A,在插入數據的時候,自己先查詢一下數據是否已經存在,如果存在直接返回成功,如果不存在則執行插入操作,那麼調用方就就直接執行插入操作就可以了,無需自己判斷數據是否已經存在了,那麼接口A就是全冪等的了;

二、冪等需要關注的幾個問題

以下幾點並不是需要注意問題的全部,歡迎大家留言補充!

2.1、服務的調用方和服務的提供方冪等鍵要保證一致,唯一性,並且不變性;

這個很好理解,例如:

  • 服務的調用方以爲調用方是按照用戶身份證號做冪等的,但其實服務提供方是按照手機號做冪等的,這樣就出現問題了;

  • 服務的提供方前段時間還是用A做冪等鍵的,後邊卻用B了,說變就變的也是不可以的;

因此,服務調用方在調用服務之前一定要確定好服務提供方冪等鍵的設置;

2.3、調用方不能單純的依靠查詢來做冪等

例如:用戶咔咔點擊了兩次,兩個線程執行,同時執行插入操作,兩個線程都先查詢,結果某一時間點查詢的數據都不存在,然後就執行插入操作了,就插入了兩條數據;

在這裏插入圖片描述
這個時候,就需要加鎖處理了或者根據主鍵衝突策略等方式判斷冪等了;

1.1、1.2中舉例還是有瑕疵的,大家注意!

2.4、調用方冪等鍵唯一了,但是其他數據卻變了,業務做好處理,具體業務具體分析

這種情況很常見,例如:服務提供方約定以手機號作爲冪等鍵,但是服務的調用方第一次插入數據的時候,手機號是A,其他數據是B,第二次調用的時候,手機號是A,其他數據確是C,那服務提供方到底讓不讓你插哪?這個就需要根據具體的業務做分析了,如果業務決定,讓你插,你就插,不讓你插就不能插了!

2.5、冪等鍵跟隨數據做好持久化,做到“有據可依”,禁止冪等鍵純內存拼接

這個很好理解,舉個例子吧:

插入一條數據,拼接了一個冪等鍵ABC,你如果不做持久化,數據存儲不包含ABC三個字段,那麼你下次如何判斷數據是否已經存在哪?

2.6、消息冪等處理的幾個關鍵

消息冪等是一個比較複雜的場景,因爲消息可能存在的無序性、重複性、延遲,都增加了冪等處理的複雜性,其中重複性則是冪等的時候需要重點考慮的;

2.6.1、重複性

例如:交易系統存在下單、支付、發貨行爲,交易系統如果多次消費同一筆定金支付成功消息時,由於冪等問題可能導致很多問題:
在這裏插入圖片描述
一般,我們在發送交易消息的時候,會把 “訂單的狀態和訂單ID” 作爲消息體的一部分,然後在接收到消息的時候,根據消息的類型判斷是不是下單消息,以及判斷當前訂單的狀態是否是”用戶下單“,這樣在消息不重複消費的時候,是沒有問題的。

如果出現上述情況,用戶下單消息重複消費,在接收到用戶支付消息的時候訂單狀態已經被修改爲已支付,但是由於用戶下單消息重複消費,消息體是沒有變化的(狀態沒有發生變化),就又修改訂單狀態爲待支付狀態了,這裏顯然是不對的。

我們應該做:

我們應該在接收到消息的時候,根據訂單ID去數據庫查詢一下訂單此時的狀態,然後根據當前的狀態判斷下一步的操作,並且消息處理的時候還要加鎖哦!加鎖的維度可以是訂單ID!防止併發的時候,出現3.3.2中的情況!

因此,不要把可變值作爲冪等的條件,加鎖查詢訂單最新的狀態!

2.6.2、無序性

保證消息的順序消費是比較複雜的,並且成本也很高,一般我們可以根據不同的業務判斷消息消費的順序性的;

例如:用戶下單消息=>用戶支付消息,順序的行爲是這樣消費的。但無序的時候,我們可能先接收到”用戶支付消息“然後纔會接收到”用戶下單消息“。

如果你的業務在接收用戶下單消息做的處理不影響主鏈路的話,則可以直接先處理”用戶支付消息“,當在收到”用戶下單消息“的時候,查詢訂單的狀態已經變爲”已支付“,則直接把消息冪等掉,返回true,結束消息的消費。

但是,如果你的”用戶下單消息“有重要的邏輯,必須先消費了之後,纔可以消費”用戶支付消息“,那我們就需要特別注意了!根據查詢出來的訂單狀態進行判斷,判斷是否已經消費了”用戶下單消息“,當先接收到”用戶支付消息“的時候,消息直接重發就可以了,等消費了”用戶下單消息“之後,再消費”用戶支付消息“。
在這裏插入圖片描述

2.7、定時任務冪等處理的幾個關鍵

定時任務的冪等需要解決的主要問題就是”重複性“,和消息的重複消費問題大致相同,需要根據查詢最新的狀態進行業務的處理,這裏不做過多說明;


往期熱門文章:

1、Stack Overflow上188W+程序員都關注的問題:Java到底是值傳遞還是引用傳遞?

2、Dubbo必會的18個面試題!一網打盡!

3、可以提高千倍效率的Java代碼小技巧

4、後端開發甩鍋指南!

5、答應我,別再if/else走天下了可以嗎?
在這裏插入圖片描述

【視頻福利】2T免費學習視頻,搜索或掃描上述二維碼關注微信公衆號:Java後端技術(ID: JavaITWork),和20萬人一起學Java!回覆:1024,即可免費獲取!內含SSM、Spring全家桶、微服務、MySQL、MyCat、集羣、分佈式、中間件、Linux、網絡、多線程,Jenkins、Nexus、Docker、ELK等等免費學習視頻,持續更新!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章