幂等性 (Idempotent)
大家好,我是 Cindy,關於幂等性 (Idempotent)我已經聽説過 3 次了,還記不住(事不過三?亂用成語),所以決定記錄下來,順便分享給大家,下面會是我的筆記,如果有錯歡迎大家留言跟我說唷!
什麼是冪等性?
冪等性最早是數學裡面的一個概念,後來被用於計算機領域,用於表示任意多次請求均與一次請求執行的結果相同,也就是說對於一個介面而言,無論呼叫了多少次,最終得到的結果都是一樣的。詳細可以參考 維基百科。
HTTP 的冪等性
- GET: 安全(Safe)且 冪等(Idempotent),用來讀取數據
- POST: 不安全(Non-safe) 且不是冪等(non-idempotent),用來新增數據或執行某個操作
- PUT: 不安全(Non-safe) 但冪等(idempotent),用來置換數據
- PATCH: 不安全(Non-safe) 且不是冪等(non-idempotent),用來修改數據
- DELETE: 不安全(Non-safe) 但冪等(idempotent),用來刪除數據
- 參考: HTTP Verbs: 談 POST, PUT 和 PATCH 的應用、HTTP 方法
從 RESTful 服務的角度來看,要使操作(或服務調用)具有冪等性,客戶端可以在產生相同結果的同時重複進行相同的調用。換句話說,發出多個相同的請求與發出單個請求具有相同的效果。請注意,雖然冪等操作在服務器上產生相同的結果(沒有副作用),但響應本身可能不同(例如,資源的狀態可能會在請求之間發生變化)。
PUT 和 DELETE 方法被定義為冪等的。但是,有一個關於 DELETE 的警告。DELETE 的問題,如果成功通常會返回 200(OK)或 204(No Content),在後續調用中通常會返回 404(Not Found),除非該服務被配置為“標記”要刪除的資源而不實際刪除它們。但是,當服務實際刪除資源時,下一次調用將找不到資源將其刪除並返回 404。但是,每次 DELETE 調用後服務器上的狀態都是一樣的,只是響應不同。
為什麼 PATCH 是 non-idempotent
A PATCH is not necessarily idempotent, although it can be. Contrast this with PUT; which is always idempotent. The word “idempotent” means that any number of repeated, identical requests will leave the resource in the same state. For example if an auto-incrementing counter field is an integral part of the resource, then a PUT will naturally overwrite it (since it overwrites everything), but not necessarily so for PATCH.
從 MDN Web Docs 的說明可以知道 PATCH 可以是 idempotent,但不一定是,像是自動增加數值的欄位更新。
如何保證介面的冪等性?
前端攔截 (但可能被跳過)
disable 按鈕
前端這邊我沒有詳細察,所以只列了這個QQ
使用資料庫實現冪等性
- 唯一索引,防止新增髒資料
- 悲觀鎖
db lock - 樂觀鎖
用 version 控制
先 select 拿到版號,做完更新版號+1
如果版號不是差 1 就不動做 - Atomic Transactions
- Using Atomic Transactions to Power an Idempotent API
- transaction(isolation: :serializable)
簡單說就是用 db 最嚴格的隔離等級來避免資料重複。
註:關於 isolation 可以參考我以前的 文章
- select insert
併發不高的後臺系統,或者一些任務 JOB,為了支援冪等,支援重複執行,簡單的處理方法是,先查詢下一些關鍵資料,判斷是否已經執行過,在進行業務處理,就可以了。
注意:核心高併發流程不要用這種方法。
使用分散式鎖實現冪等性
如果是分佈式系統,構建全域性唯一索引比較困難,例如唯一性的欄位沒法確定,這時候可以引入分散式鎖,通過第三方的系統(redis 或 zookeeper),在業務系統插入資料或者更新資料,獲取分散式鎖,然後做操作,之後釋放鎖,這樣其實是把多執行緒併發的鎖的思路,引入多個系統,也就是分散式系統中的解決思路。
token 機制
參考 - 流程圖
這裡要結合業務考慮這種場景:如果請求處理失敗,前端是否需要重新申請 token 進行重試(因為此時 token 在服務端已經被刪除)。
tip: 先刪除 token 再進行業務操作
狀態機
在設計單據相關的業務,或者是任務相關的業務,肯定會涉及到狀態機(狀態變更圖),就是業務單據上面有個狀態,狀態在不同的情況下會發生變更,一般情況下存在有限狀態機,這時候,如果狀態機已經處於下一個狀態,這時候來了一個上一個狀態的變更,理論上是不能夠變更的,這樣的話,保證了有限狀態機的冪等。
結論
幂等性其實就是想辦法確保最終一致性,可以當成一種概念,用在我們設計程式的時候,思考的一個方向,像是這個業務邏輯是否有需要確保最終一致性,是否會有重複執行的可能性,重複執行的時候要視為成功或失敗,如何避免重複執行造成的錯誤,都是我們要思考的地方。
其他參考資料: