如今隨著互聯網技術快速發展,業務越來越複雜,系統的高併發和關鍵數據的場景越來越多。在分散式系統中,機器宕機和消息丟失也是需要重點關註的問題,其中的一個典型就是冪等性問題。 ...
1 冪等性
一句話,冪等就是一個執行操作,無論執行多少次,產生的效果和返回的結果都是一樣的。
2 為什麼要實現冪等性?
如今隨著互聯網技術快速發展,業務越來越複雜,系統的高併發和關鍵數據的場景越來越多。
在分散式系統中,機器宕機和消息丟失也是需要重點關註的問題,其中的一個典型就是冪等性問題。
想想看,一個對外暴露的介面會面領很多次請求,如果不能保證冪等性會帶來什麼樣的後果?
微信進行一次扣款操作,應該只扣用戶一次錢,當遇到網路故障或系統bug,如果沒有實現冪等性扣多了你會不會直接“C語言”投訴?
當然,有些介面是天然保證冪等性的,比如查詢操作、刪除操作。有些對數據的修改是一個常量,無其他操作,也是具有冪等性的。修改操作可能冪等可能不冪等。
SELECT col1 FROM tab1 WHERE col2 = 2UPDATE tab1 SET col1 = 1 WHERE col2 = 2UPDATE tab1 SET col1 = col1 + 1 WHERE col2 = 2
這三個sql只有第三個不是冪等的。
POST請求天生就不是一個冪等操作,每次調用都會在系統中產生新的資源,想要冪等就必須在業務中實現。
需要避免的是,冪等性和併發安全不是一回事。當同一筆訂單即使你不停的提交支付,如果扣了不止一次錢,就說明該操作不冪等。
而有多筆訂單同時進行支付,最後扣除的金額不是這麼多筆金額的總和,說明該操作有併發安全問題。這是兩個維度的問題,應該分開討論解決。
3 如何實現冪等性?
(1)資料庫防重
利用數據表唯一索引的特性,當併發時新增報錯時,再查詢一次,數據已經存在,就避免了臟數據的新增。但註意,不要將uuid作為索引欄位,其大小和類型對於索引而言都會導致速度非常慢。
常見的場景,比如博客/微博系統點贊,一個用戶對一個微博點贊,就把用戶id與該博文id綁定,後續該用戶再對該博文點贊就無法插入。再比如金融賬戶,可以通過在賬戶表中增加唯一索引來存儲用戶id,即使重覆操作一個用戶也只能擁有一個賬戶。
(2)token令牌機制
token機制是適用範圍最廣泛的一種冪等設計。雖然實現方式有很多種,但核心思想就是每次操作都生成一個唯一token憑證,伺服器通過這個唯一憑證確保同樣的操作不會被執行多次。
具體可以分為兩個階段,獲取token和使用token。每次介面請求前先獲取一個token,然後在下次請求時在請求的header體中加上這個token,後端進行校驗,如果驗證通過則刪除token,下次請求再次判斷token。如果在redis緩存的幫助下,流程圖如下:
(3)分散式鎖
資料庫防重表可以通過分散式鎖代替,相比去重表,將放併發做到了緩存中,效率更高。局限性都是同一時間只能完成一次請求。
比如某些業務處理流程很長,要求不能併發執行,可以在流程執行之前根據某個標誌(用戶ID+尾碼等)獲取分散式鎖,其他流程執行時獲取鎖就會失敗,也就是同一時間該流程只能有一個能執行成功,執行完成後,釋放分散式鎖。
4 冪等的優缺點
優點:
業務需要
缺點:
(1)客戶端處理邏輯得以簡化,但服務端控制冪等邏輯變得更加複雜;
(2)把併發執行變成改為串列執行,降低了執行效率。
5 擴展
分散式自增ID可以借鑒Snowflake演算法,優點是高性能、低延遲、按時間有序;缺點是需要獨立的開發和部署。
其結構如下:
- 最高位是符號位,始終為0,不可用。
- 41位的時間序列,精確到毫秒級,41位的長度可以使用 (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69年。時間位還有一個很重要的作用是可以根據時間進行排序。註意,41位時間截不是存儲當前時間的時間截,而是存儲時間截的差值(當前時間截 - 開始時間截) 後得到的值,這裡的的開始時間截,一般是我們的id生成器開始使用的時間,由我們程式來指定的。
- 10位的機器標識,10位的長度最多支持部署1024個節點。
- 12位的計數序列號,序列號即一系列的自增id,可以支持同一節點同一毫秒生成多個ID序號,12位的計數序列號支持每個節點每毫秒產生4096個ID序號。
加起來剛好64位,為一個Long型。這個演算法很簡潔,但依舊是一個很好的ID生成策略。
參考文獻:
[1] 分散式系統互斥性與冪等性問題的分析與解決
https://zhuanlan.zhihu.com/p/22820761
[2] 高併發下介面冪等性解決方案
https://blog.csdn.net/u011635492/article/details/81058153
[3] 冪等性問題和解決方法
https://blog.csdn.net/qq_32020035/article/details/105448889
[4] 雪花演算法
https://www.cnblogs.com/grasp/p/12309726.html
[5] 聊聊開發中冪等問題
https://segmentfault.com/a/1190000018808510
作者:京東零售 李澤陽
來源:京東雲開發者社區 轉載請註明來源