冪等這個詞原自數學,某一元運算爲冪等時,其做用在任一元素兩次後會和其做用一次的結果相同。在編程中,一個冪等操做的特色是其任意屢次執行所產生的影響均與一次執行的影響相同。第一次請求的時候對資源產生了反作用,可是之後的屢次請求都不會再對資源產生反作用。這裏的反作用是不會對結果產生破壞或者產生不可預料的結果。redis
好比,某服務記錄關鍵數據 X,當前值爲 100。A 請求須要將 X 增長 200;同時,B 請求須要將 X 減去 100。在理想的狀況下,A 先讀取到 X=100,而後 X 增長 200,最後 X=300。B 請求接着從讀取 X=300,減去 100,最後 X=200。 然而在真實狀況下,若是不作任何處理,則可能會出現:A 和 B 同時讀取到 X=100;假如 A 比 B 先執行完,那麼最後 X=0,若是 B 比 A 先執行完,那麼最後 X=300。不論是那種狀況發生了,都產生了反作用或者說是產生了不可預料的結果,而且是不能夠接受的異常。這種狀況就是咱們提供的方法或者接口不知足冪等性,致使的不可預料的結果。數據庫
1.創建惟一索引,防止新增髒數據
這個能夠限制重複插入數據,當重複時,數據庫會拋異常,保證不會出現髒數據。但體驗很差,而且實用場景有限制。編程
2.利用 token 機制,防止頁面重複提交
核心思想是爲每一次操做生成一個惟一性的憑證,也就是token。一個token在操做的每個階段只有一次執行權,一旦執行成功則保存執行結果。對重複的請求,返回同一個結果。服務器
3.狀態機冪等
在有狀態的數據中可使用,若是狀態機已經處於下一個狀態,這時候來了一個上一個狀態的變動,理論上是不可以變動的,這樣的話,保證了有限狀態機的冪等。若是狀態是順序的,不可逆,那麼就不會出現 ABA 問題,不然會出現 ABA問題。微信
4.select + insert
這種狀況在沒有併發的系統中能夠解決冪等問題,在單JVM有併發的時候能夠加鎖來保證冪等性,在分佈式環境它是沒發保證冪等的,這時候須要用到分佈式鎖來保證。併發
5.分佈式鎖
在進入方法時,先去獲取鎖,假如獲取到鎖,就繼續後面的流程。假如沒有獲取到鎖,就等待鎖的釋放直到獲取到鎖。當執行完方法時,釋放鎖。固然,鎖要設個超時時間,防止意外沒有釋放到鎖。它用來解決分佈式系統的冪等性,經常使用的實現方案是 redis 和 zookeeper 等工具。分佈式
6.對外提供冪等的接口
經過 source來源+seq序列號來判斷請求是否重複, 在併發時只能處理一個請求。其它相同併發請求要麼返回請求重複,要麼等待前面請求執行完成在執行。工具
1.增長了額外控制冪等的業務邏輯,複雜化了業務功能。
2.把並行執行的功能改成串行執行,下降了執行效率。spa
最後,冪等性雖然複雜化了業務功能和下降了執行效率,但爲了保證系統的正確性,是必要的。就上面更新 X 的例子,在單臺服務器上,給那段代碼加上鎖,並給 X 設爲 volatile,就保證來數據的正確性了。在分佈式環境下而且 X 是從數據庫或者文件裏查詢出來的,用上面加鎖的方式實現就不能保證數據的正確性了,這時候就須要用到分佈式鎖了。因此,保證方法或接口的冪等性是很是有必要的,由於數據是不能出現任何問題的。索引
PS:
清山綠水始於塵,博學多識貴於勤。
微信公衆號:「清塵閒聊」。
歡迎一塊兒談天說地,聊代碼。