Java生鮮電商平臺-生鮮電商高併發下的接口冪等性實現與代碼講解

Java生鮮電商平臺-生鮮電商高併發下的接口冪等性實現與代碼講解前端

 

說明:Java生鮮電商平臺-生鮮電商高併發下的接口冪等性實現與代碼講解,實際系統中有不少操做,是無論作多少次,都應該產生同樣的效果或返回同樣的結果。例如:java

  • 前端重複提交選中的數據,應該後臺只產生對應這個數據的一個反應結果。nginx

  • 咱們發起一筆付款請求,應該只扣用戶帳戶一次錢,當遇到網絡重發或系統bug重發,也應該只扣一次錢;程序員

  • 發送消息,也應該只發一次,一樣的短信發給用戶,用戶會哭的;redis

  • 建立業務訂單,一次業務請求只能建立一個,建立多個就會出大問題。sql

      等等不少重要的狀況,這些邏輯都須要冪等的特性來支持。數據庫

冪等性概念

冪等(idempotent、idempotence)是一個數學與計算機學概念,常見於抽象代數中。編程

在編程中.一個冪等操做的特色是其任意屢次執行所產生的影響均與一次執行的影響相同。冪等函數,或冪等方法,是指可使用相同參數重複執行,並能得到相同結果的函數。api

這些函數不會影響系統狀態,也不用擔憂重複執行會對系統形成改變。例如,「getUsername()和setTrue()」函數就是一個冪等函數.安全

更復雜的操做冪等保證是利用惟一交易號(流水號)實現.

個人理解:冪等就是一個操做,不論執行多少次,產生的效果和返回的結果都是同樣的

技術方案

1. 查詢操做 查詢一次和查詢屢次,在數據不變的狀況下,查詢結果是同樣的。select是自然的冪等操做

2. 刪除操做 刪除操做也是冪等的,刪除一次和屢次刪除都是把數據刪除。(注意可能返回結果不同,刪除的數據不存在,返回0,刪除的數據多條,返回結果多個)

3.惟一索引,防止新增髒數據 好比:支付寶的資金帳戶,支付寶也有用戶帳戶,每一個用戶只能有一個資金帳戶,怎麼防止給用戶建立資金帳戶多個,那麼給資金帳戶表中的用戶ID加惟一索引,因此一個用戶新增成功一個資金帳戶記錄

要點: 惟一索引或惟一組合索引來防止新增數據存在髒數據 (當表存在惟一索引,併發時新增報錯時,再查詢一次就能夠了,數據應該已經存在了,返回結果便可)

4. token機制,防止頁面重複提交

業務要求:

頁面的數據只能被點擊提交一次

發生緣由:因爲重複點擊或者網絡重發,或者nginx重發等狀況會致使數據被重複提交

解決辦法:集羣環境:採用token加redis(redis單線程的,處理須要排隊) 單JVM環境:採用token加redis或token加jvm內存

處理流程:

  • 數據提交前要向服務的申請token,token放到redis或jvm內存,token有效時間

  • 提交後後臺校驗token,同時刪除token,生成新的token返回

token特色:

要申請,一次有效性,能夠限流

注意:redis要用刪除操做來判斷token,刪除成功表明token校驗經過,若是用select+delete來校驗token,存在併發問題,不建議使用

5. 悲觀鎖

獲取數據的時候加鎖獲取

select * from table_xxx where id='xxx' for update;

注意:id字段必定是主鍵或者惟一索引,否則是鎖表,會死人的

悲觀鎖使用時通常伴隨事務一塊兒使用,數據鎖定時間可能會很長,根據實際狀況選用

6. 樂觀鎖

樂觀鎖只是在更新數據那一刻鎖表,其餘時間不鎖表,因此相對於悲觀鎖,效率更高。

樂觀鎖的實現方式多種多樣能夠經過version或者其餘狀態條件:

一、經過版本號實現

update table_xxx set name=#name#,version=version+1 where version=#version#`

二、經過條件限制

update tablexxx set avaiamount=avaiamount-#subAmount# where avaiamount-#subAmount# >= 0`

 

要求:quality-#subQuality# >= ,這個情景適合不用版本號,只更新是作數據安全校驗,適合庫存模型,扣份額和回滾份額,性能更高

注意:樂觀鎖的更新操做,最好用主鍵或者惟一索引來更新,這樣是行鎖,不然更新時會鎖表,上面兩個sql改爲下面的兩個更好

`update tablexxx set name=#name#,version=version+1 where id=#id# and version=#version#update tablexxx set avaiamount=avaiamount-#subAmount# where id=#id# and avai_amount-#subAmount# >= 0

  

7. 分佈式鎖

仍是拿插入數據的例子,若是是分佈是系統,構建全局惟一索引比較困難,例如惟一性的字段無法肯定

這時候能夠引入分佈式鎖,經過第三方的系統(redis或zookeeper),在業務系統插入數據或者更新數據,獲取分佈式鎖,而後作操做,以後釋放鎖

這樣實際上是把多線程併發的鎖的思路,引入多多個系統,也就是分佈式系統中得解決思路。

要點:某個長流程處理過程要求不能併發執行,能夠在流程執行以前根據某個標誌(用戶ID+後綴等)獲取分佈式鎖,其餘流程執行時獲取鎖就會失敗,也就是同一時間該流程只能有一個能執行成功,執行完成後,釋放分佈式鎖(分佈式鎖要第三方系統提供)

8. select + insert

併發不高的後臺系統,或者一些任務JOB,爲了支持冪等,支持重複執行,簡單的處理方法是,先查詢下一些關鍵數據,判斷是否已經執行過,在進行業務處理,就能夠了

注意:核心高併發流程不要用這種方法

9. 狀態機冪等

在設計單據相關的業務,或者是任務相關的業務,確定會涉及到狀態機(狀態變動圖),就是業務單據上面有個狀態,狀態在不一樣的狀況下會發生變動,通常狀況下存在有限狀態機

若是狀態機已經處於下一個狀態,這時候來了一個上一個狀態的變動,理論上是不可以變動的,這樣的話,保證了有限狀態機的冪等。

注意:訂單等單據類業務,存在很長的狀態流轉,必定要深入理解狀態機,對業務系統設計能力提升有很大幫助

10. 對外提供接口的api如何保證冪等

如銀聯提供的付款接口:須要接入商戶提交付款請求時附帶:source來源,seq序列號

source+seq在數據庫裏面作惟一索引,防止屢次付款,(併發時,只能處理一個請求)

**重點 **對外提供接口爲了支持冪等調用,接口有兩個字段必須傳,一個是來源source,一個是來源方序列號seq,這個兩個字段在提供方系統裏面作聯合惟一索引

這樣當第三方調用時,先在本方系統裏面查詢一下,是否已經處理過,返回相應處理結果;沒有處理過,進行相應處理,返回結果。

注意,爲了冪等友好,必定要先查詢一下,是否處理過該筆業務,不查詢直接插入業務系統,會報錯,但實際已經處理了。

總結

冪等性應該是合格程序員的一個基因,在設計系統時,是首要考慮的問題,尤爲是在像支付寶,銀行,互聯網金融公司等涉及的都是錢的系統,既要高效,數據也要準確,因此不能出現多扣款,多打款等問題,這樣會很難處理,用戶體驗也很差

 

 

實際運營截圖:

 

聯繫QQ:137071249

QQ羣:793305035

相關文章
相關標籤/搜索