幂等
帶着以下3個問題來讨論幂等
- 什麼是幂等
- 什麼時候需要幂等
- 怎麼實作幂等
1. 什麼是幂等
-
google Idempotence 得到以下結果 :
Idempotence is the property of certain operations in mathematics and computer science whereby they can be applied multiple times without changing the result beyond the initial application.
- 百度裡搜到的一般都是這段的簡單的中文翻譯. 我了解的幂等, 一般是用在對外暴露的接口上, 目的是為了防止重複調用造成資料錯誤處理.
- 幂等其實我記得最早應該是網絡協定中用到的, 網絡協定中發送封包時, 網絡中經常需要面臨的問題就是網絡逾時, 而逾時的常見處理政策就是重發. 如果用戶端往服務端發送封包逾時了, 可能發送逾時, 服務端沒有收到, 也可能服務端收到了但響應逾時, 隻要服務端是幂等的, 用戶端的重複請求服務方會回應是重複封包, 用戶端就知道已經發送成功了. 這樣就保證了網絡的可靠性設計.
2. 什麼時候需要幂等
幂等是為了保護資料不被重複錯誤處理.
- 正常資料操作就隻有增删改查, 查詢操作總是幂等的, 是以嚴格來說其他三種操作都要考慮幂等性, 特别是在一些關鍵業務資料, 比如賬戶/金額/訂單交易等等.
- 對外暴露的接口, 不管是rpc還是http或者是消費上遊發過來的消息,都有可能會有重複的可能. 這時候服務暴露方或者消息消費方都必須設計為幂等的.
- http: 使用者重複送出頁面請求, 或者用戶端伺服器逾時重發http請求
- rpc : 比如我們常用的dubbo架構, 接口逾時或失敗預設會進行重試 (當然可以設定不重試)
- mq消息 : 很多mq消息為了保證可靠性, 如果消息發送端發送逾時, 會嘗試重新發送消息.
3. 怎麼實作幂等
以下幾種常見的也是開發中常用的方案, 其實是在整個服務執行過程的多個不同階段去保證幂等性的, 其實我認為方案很多, 隻要在破壞資料之前校驗都可以的.
-
- 使用者頁面送出請求的時候, 就先進行重複送出的校驗. 常用的方案是采用唯一token生成器, 使用者加載頁面的時候, 會配置設定一個唯一token, 使用者送出的時候會帶着這個token, 我們校驗同一個token是否重複送出了.
-
- 去重表方案, 個人感覺這個方案還是比較實用的, 而且去重表可以設定為分庫分表的, 可以擴充性能. 去重表就是在操作之前,先插入一條記錄, 利用唯一索引防止重複操作, 如果記錄已存在, 接口可以直接傳回已處理, 不要重複操作, 或者直接傳回成功. 與之類似的方案就是利用緩存比如redis來判斷重複.
-
- CAS方案, 可以是要求請求中必須帶有版本号, 利用版本号來CAS更新資料.
-
- 利用資料庫的一緻性, 比如mysql的insert ignore操作和insert on duplicate update等sql, 也能做到保證資料的一緻性.
這些都是我自己常用的, 在這裡簡單總結一下.