1.什么是接口冪等
接口冪等性就是用戶對同一操作發(fā)起了一次或多次請求的對數(shù)據(jù)的影響是一致不變的系忙,不會因為多次的請求而產(chǎn)生副作用。
副作用:可以認為多次請求操作,每一次對數(shù)據(jù)狀態(tài)都會產(chǎn)生影響 。
注意這里并沒有要求接口返回結果是一致的唐片。
例如:update order set moeny = 100 where orderId = 2029282312
該操作無論執(zhí)行多少次丙猬,對數(shù)據(jù)的影響都是一致的,不變的费韭。
接口不做冪等處理會怎樣茧球?
支付場景:用戶購買商品后,發(fā)起支付操作星持,支付系統(tǒng)處理支付成功后抢埋,由于網(wǎng)絡原因沒有及時返回給用戶結果,其實這個時候訂單已經(jīng)扣過款督暂,相應的支付流水也都已經(jīng)生成揪垄,這個時候用戶又點擊支付操作,此時會進行第二次扣款逻翁,扣款成功后返回給用戶饥努。用戶去查看支付訂單和流水會發(fā)現(xiàn)自己支付兩次,完蛋了要用戶被投訴了八回,這就是接口沒有處理冪等造成的酷愧。
2.什么情況需要處理接口冪等性問題?
2.1 select 天然自帶冪等性缠诅。
每次查詢對數(shù)據(jù)都不會產(chǎn)生副作用溶浴。
2.2 insert 當我們重復插入數(shù)據(jù)的時候,會出現(xiàn)什么情況 管引?
第一種情況:自增主鍵士败,沒有冪等性。
eg:insert into product_info (id,name,type,price,tm)
執(zhí)行多次褥伴,會新增多條記錄拱烁。對結果集產(chǎn)生了副作用。
第二種情況:業(yè)務主鍵噩翠,具有冪等。
eg:insert into product_info (orderId,name,type,price,tm) orderId 為主鍵唯一
無論該sql執(zhí)行多少次邦投,對結果集產(chǎn)生的效果都是一樣只增加了一條數(shù)據(jù)伤锚。
2.3 delete 是否具有冪等性?
第一種情況:絕對刪除志衣,具有冪等性屯援。
eg;delete from order where id = 3 念脯。
無論該sql執(zhí)行多少次狞洋,對結果集產(chǎn)生的效果都是一樣只刪除了一條數(shù)據(jù)。
第二種情況: 相對刪除绿店,不具有冪等性吉懊。
eg:delete from order where id > 23 .
該操作每執(zhí)行一次庐橙,對結果集產(chǎn)生的結果,可能都不一樣借嗽,同一操作多次執(zhí)行對數(shù)據(jù)產(chǎn)生了副作用态鳖。
2.4 update 猜一猜是否具有天熱冪等性?
第一種情況:絕對更新恶导,具有冪等性浆竭。
eg:update good set stock= 586 where goodId = 10;
該操作無論執(zhí)行多少次操作對結果的影響都是一樣。
第二種情況:相對更新惨寿,不具有冪等性邦泄。
eg:update good set stock = stock+10 where goodid= 10 ;
每次執(zhí)行該操作庫存數(shù)量都會加10裂垦,所以不具備冪等操作顺囊。
總結:以上都是基于單庫,單表的操作冪等性的分析缸废,其實在具體業(yè)務當中包蓝,可能要設計多個表,多個庫企量,甚至跨服務操作测萎。比如分布式系統(tǒng)中,我們一個接口届巩,可能需要調(diào)用多個服務來完成任務硅瞧。那么這種情況,如何保證接口的冪等性呢?
接口冪等性解決方案
前言:接口冪等處理要根據(jù)具體業(yè)務來判斷怎么處理恕汇,以下會舉例來闡述接口冪等處理解決方案腕唧。
1.token+redis 機制
比如訂單支付場景:
該支付分為兩個步驟:
1.1 獲取全局唯一token
接口處理生成唯一標識(token) 存儲到redis中,并返回給調(diào)用客戶端瘾英。
1.2 發(fā)起支付操作并附帶token
接口處理:
1.2.1 獲得分布式鎖(處理并發(fā)情況)
1.2.2 判斷redis中是否存在token
1.2.3 存在 執(zhí)行支付業(yè)務邏輯枣接,否則返回該訂單已經(jīng)支付
1.2.4 釋放分布式鎖
思考:為什么要加分布式鎖?
原因1:在高并發(fā)請求中 缺谴,token判斷是否存在是非線程安全的但惶,所以要加分布式鎖來保證 該條件的判斷為線程安全
注釋:也可redis用刪除操作來判斷token,刪除成功代表token校驗通過 這個刪除是原子操作的
原因2:在支付業(yè)務中湿蛔,判斷支付訂單是否已經(jīng)存在膀曾,存在說明該訂單已經(jīng)支付過了,不存在就執(zhí)行扣款操作阳啥,如果相同操作并發(fā)兩個請求來到判斷條件可能兩個請求都能判斷支付訂單不存在添谊,造成重復扣款。 所以也要加分布式鎖保證線程的安全察迟。
2.CAS 保證接口冪等性
2.1 狀態(tài)機制冪等(狀態(tài)不可逆)
針對更新操作:
例如 電商訂單斩狱,訂單支付狀態(tài) 0 待支付 耳高, 1 支付中 , 3 支付成功 4 支付失敗喊废。
update order set status = 1 where status =0 and orderId = “201251487987”
該sql語句利用狀態(tài)CAS 保證該操作的冪等祝高。
eg:比如要進行訂單支付,上來先用CAS更新訂單狀態(tài)污筷,
返回影響說為1 代表修改成功工闺,可以支付,繼續(xù)執(zhí)行支付業(yè)務代碼
返回影響數(shù) 0 代表修改失敗瓣蛀,該訂單已經(jīng)不是待支付訂單了陆蟆。
注釋:實際這里是利用CAS原理
3 樂觀鎖實現(xiàn)冪等
背景由來:
為什么要有冪等這種場景?因為在大的系統(tǒng)中惋增,都是分布式部署叠殷,如:訂單業(yè)務 和 庫存業(yè)務有可能都是獨立部署的,都是單獨的服務诈皿。用戶下訂單林束,會調(diào)用到訂單服務和庫存服務。
比如:訂單系統(tǒng):
訂單服務 —> 庫存服務 (PRC遠程調(diào)用(服務接口))
因為分布式部署稽亏,很有可能在調(diào)用庫存服務時壶冒,因為網(wǎng)絡等原因,訂單服務調(diào)用失敗截歉,但其實庫存服務已經(jīng)處理完成胖腾,只是返回給訂單服務處理結果時出現(xiàn)了異常。這個時候一般系統(tǒng)會作補償方案瘪松,也就是訂單服務再此放起庫存服務的調(diào)用,庫存減1
update t_goods set count = count -1 where good_id=2
這樣就出現(xiàn)了問題咸作,其實上一次調(diào)用已經(jīng)減了1,只是訂單服務沒有收到處理結果∠溃現(xiàn)在又調(diào)用一次记罚,又要減1,這樣就不符合業(yè)務了壳嚎,多扣了桐智。
冪等這個概念就是,不管庫存服務在相同條件下調(diào)用幾次诬辈,處理結果都一樣。這樣才能保證補償方案的可行性荐吉。
樂觀鎖方案
借鑒數(shù)據(jù)庫的樂觀鎖機制焙糟,如:
update t_goods set count = count -1 , version = version + 1 where good_id=2 and version = 1
4 防重表
1.利用數(shù)據(jù)庫建一張防重表(加唯一索引)
比如訂單支付,
反正重復支付:訂單號插入防重表 成功 執(zhí)行支付業(yè)務邏輯样屠,失敗說明已經(jīng)支付過穿撮。
防重表支付成功是否要刪除:
1.可定期清除數(shù)據(jù)
2.也可結合 訂單狀態(tài) 缺脉,在支付前查詢訂單狀態(tài)為待支付 執(zhí)行支付操作 ,操作后刪除訂單號 若 第二個請求插入防重表成功悦穿,但是這個時候查詢訂單狀態(tài)失敗攻礼。
(實際這個防重表就是實現(xiàn)了分布式鎖)
- 緩存隊列
將請求放入隊列,后續(xù)使用異步任務處理隊列中的數(shù)據(jù)栗柒,過濾掉重復的消息礁扮。 和防止重復消費道理是一樣。
————————————————
版權聲明:本文為CSDN博主「完美天空」的原創(chuàng)文章瞬沦,遵循CC 4.0 BY-SA版權協(xié)議太伊,轉(zhuǎn)載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/qq_29978863/article/details/107739744