高並發的核心技術 - 冪等的實現方案

2020-12-11 酷扯兒

本文轉載自【微信公眾號:java進階架構師,ID:java_jiagoushi】經微信公眾號授權轉載,如需轉載與原文作者聯繫

一、背景

我們實際系統中有很多操作,是不管做多少次,都應該產生一樣的效果或返回一樣的結果。 例如:

1. 前端重複提交選中的數據,應該後臺只產生對應這個數據的一個反應結果。 2. 我們發起一筆付款請求,應該只扣用戶帳戶一次錢,當遇到網絡重發或系統bug重發,也應該只扣一次錢; 3. 發送消息,也應該只發一次,同樣的簡訊發給用戶,用戶會哭的; 4. 創建業務訂單,一次業務請求只能創建一個,創建多個就會出大問題。

等等很多重要的情況,這些邏輯都需要冪等的特性來支持。

二、冪等性概念

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

在編程中.一個冪等操作的特點是其任意多次執行所產生的影響均與一次執行的影響相同。冪等函數,或冪等方法,是指可以使用相同參數重複執行,並能獲得相同結果的函數。這些函數不會影響系統狀態,也不用擔心重複執行會對系統造成改變。例如,「getUsername()和setTrue()」函數就是一個冪等函數.

更複雜的操作冪等保證是利用唯一交易號(流水號)實現.

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

三、技術方案

1. 查詢操作 查詢一次和查詢多次,在數據不變的情況下,查詢結果是一樣的。select是天然的冪等操作

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

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

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

4. token機制,防止頁面重複提交 業務要求: 頁面的數據只能被點擊提交一次 發生原因: 由於重複點擊或者網絡重發,或者nginx重發等情況會導致數據被重複提交 解決辦法: 集群環境:採用token加redis(redis單線程的,處理需要排隊) 單JVM環境:採用token加redis或token加jvm內存 處理流程: 1. 數據提交前要向服務的申請token,token放到redis或jvm內存,token有效時間 2. 提交後後臺校驗token,同時刪除token,生成新的token返回 token特點: 要申請,一次有效性,可以限流

注意:redis要用刪除操作來判斷token,刪除成功代表token校驗通過,如果用select+delete來校驗token,存在並發問題,不建議使用

5. 悲觀鎖 獲取數據的時候加鎖獲取 select * from table_xxx where id='xxx' for update; 注意:id欄位一定是主鍵或者唯一索引,不然是鎖表,會死人的 悲觀鎖使用時一般伴隨事務一起使用,數據鎖定時間可能會很長,根據實際情況選用

6. 樂觀鎖 樂觀鎖只是在更新數據那一刻鎖表,其他時間不鎖表,所以相對於悲觀鎖,效率更高。

樂觀鎖的實現方式多種多樣可以通過version或者其他狀態條件: 1. 通過版本號實現 update table_xxx set name=#name#,version=version+1 where version=#version# 如下圖(來自網上):

2. 通過條件限制 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,這個兩個欄位在提供方系統裡面做聯合唯一索引,這樣當第三方調用時,先在本方系統裡面查詢一下,是否已經處理過,返回相應處理結果;沒有處理過,進行相應處理,返回結果。注意,為了冪等友好,一定要先查詢一下,是否處理過該筆業務,不查詢直接插入業務系統,會報錯,但實際已經處理了。

總結

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

相關焦點

  • 高並發分布式場景最全的MQ消息重發冪等性解決方案
    三、防重複消息冪等性解決方案1、生產者重複發消息MQ冪等性設計MQ在接收生產者傳來的消息時,MQ內部會生成一個全局唯一與業務無關的消息ID:inner-msg-id。2、消費者接收重複消息冪等性解決方案利用資料庫唯一性約束去實現冪等性創建消息去重表,把全局唯一ID作為主鍵,做唯一性約束,如果插入成功就表示沒有消費過這條消息,可以進行消費了,插入失敗表示消息已經被消費了。
  • SpringBoot 接口冪等性的實現方案
    五、Restful API 接口的冪等性現在流行的 Restful 推薦的幾種 HTTP 接口方法中,分別存在冪等行與不能保證冪等的方法,如下:- 可能滿足也可能不滿足冪等,根據實際業務邏輯有關六、如何實現冪等性方案一:資料庫唯一主鍵方案描述
  • 以微信紅包為例講解實現接口冪等性的幾種方案
    類似的接口在我們的開發過程中會有很多,比如在電商的下單過程中:訂單創建接口,第一次調用返回超時了,重試機制一般會再次調用這個接口,此時我們不能因為這個接口被調了兩次就創建兩個一樣的訂單;庫存扣減接口,支付接口也是類似的邏輯;今天的文章就來講講什麼是接口的冪等性,並介紹幾種實現接口冪等性的方案
  • RabbitMQ消息中間件技術精講10 高級篇三 冪等性保障不重複消費
    冪等性我們可以借鑑資料庫的樂觀鎖機制來理解:比如,我們執行一條更新庫存的sql語句:update table set count = count -1 where id = 1流程說明:在高並發的情況下
  • SQL Server高並發解決方案四個優化
    【IT168 評論】現在大家都比較關心的問題就是在多用戶高並發的情況下,如何開發系統,這對我們程式設計師來說,確實是值得研究,最近找工作面試時也經常被問到,其實我早有去關心和了解這類問題,但一直沒有總結一下,導致面試時無法很完整全面的回答,所以今天我專門總結概況了一下關於SQL SERVER高並發解決方案,希望能幫助大家
  • 關於高並發,我想告訴你這些!
    2、業務都是從0到1做起來的,並發量和QPS只是參考指標,最重要的是:在業務量逐漸變成原來的10倍、100倍的過程中,你是否用到了高並發的處理方法去演進你的系統,從架構設計、編碼實現、甚至產品方案等維度去預防和解決高並發引起的問題?而不是一味的升級硬體、加機器做水平擴展。
  • 「高並發」億級流量場景下如何實現分布式限流?
    可以採用Redis+Lua技術實現,通過這種技術可以實現高並發和高性能的限流。Lua是一種輕量小巧的腳本程式語言,用標準的C語言編寫的開源腳本,其設計的目的是為了嵌入到應用程式中,為應用程式提供靈活的擴展和定製功能。
  • 微服務冪等性
    1.3 重試機制降低微服務失敗率提高至四個或五個9提高微服務架構的容錯性提高微服務架構的高可靠性2 冪等分析2.1 冪等場景        可能會發生重複請求或消費的場景,在微服務架構中是隨處可見的。>2.3 冪等重要性針對一個微服務架構,如果不支持冪等操作,那將會出現以下情況:電商超賣現象重複轉帳、扣款或付款重複增加金幣、積分或優惠券超賣現象        比如某商品的庫存為1,此時用戶1和用戶2並發購買該商品,用戶1提交訂單後該商品的庫存被修改為0,而此時用戶2並不知道的情況下提交訂單,該商品的庫存再次被修改為
  • 如何確保分布式場景下的並發冪等性?
    Java面試筆試面經、Java技術每天學習一點 作者:_BKing 來源:https://www.cnblogs.com/xiaowei123/ 冪等是什麼 ?
  • 接口的冪等性的多重考慮,你會了嗎?
    2.5 樂觀鎖(更新操作)2.6 悲觀鎖(更新操作)結語前言今天的主題:接口冪等性的解決方案當然,在接口設計中我們要考慮很多問題,安全性,格式,設計等等,今天我們先來聊聊,在高並發環境下,接口冪等性的解決方案有哪些。正文1 接口冪等性就是說在多次相同的操作下保證最終的結果是一致的。
  • 接口的冪等性,Restful接口的冪等性
    接口的冪等性,Restful接口的冪等性說到接口的冪等性,我們先看看什麼是冪等?什麼是冪等?在訂單的支付中,如果沒有冪等性,接口的重試可能造成重複支付。接口的冪等性有了上面的介紹,對接口的冪等性的理解就簡單了,接口的冪等性就是多次調用一個接口的效果是一樣的,比如更新一個訂單,更新一次和相同請求發送N次的結果一樣。
  • 浪潮VIRES中汽數據聯合發布支持百萬場景並發的自動駕駛仿真計算方案
    北京2020年12月21日 /美通社/ -- 12月19日,在GTC China 2020大會上,浪潮聯合VIRES和中汽數據有限公司發布了自動駕駛高並發仿真解決方案,為創新車企提供針對私有雲部署的高並發大規模仿真計算模式,幫助用戶極大地縮短測試時間,節省仿真業務構建和服務的部署成本,加速自動駕駛技術開發,推動自動駕駛汽車的商業化進程
  • 冪等性學習及接口的冪等性
    冪等性學習一:什麼是冪等性在這裡需要有以下幾個問題需要注意:1:冪等性的實質是一次或多次請求同一個資源,其結果是相同的。其關注的是對資源產生的影響(副作用)而不是結果,結果可以不同。冪等性是系統服務對外的一種承諾(注意,是一種承諾,而不是一種實現),接口服務提供方承諾只要調用接口成功了,外部多次調用對系統的影響是一致的。這裡需要強調一點就是,聲明為冪等的服務會認為調用方調用失敗是常態,是正常業務,並且允許在調用失敗後必然會有重試的。
  • 高並發編程系列:ConcurrentHashMap的實現原理(JDK1.7和JDK1.8)
    3.應用場景我們熟知的緩存技術(比如redis、memcached)的核心其實就是在內存中維護一張巨大的哈希表3.ConcurrentHashMap主要就是為了應對hashmap在並發環境下不安全而誕生的,ConcurrentHashMap的設計與實現非常精巧,大量的利用了volatile,final,CAS等lock-free技術來減少鎖競爭對於性能的影響。
  • 為什麼用 Java —— 關於並發編程
    陶濤,是我科大少年班的同系師兄,2006 年到 2010 年在微軟鍛鍊了四年之後,2010 年在起在 Twitter 就職了兩年參與了 Twitter 早期的架構。和陶師兄每次吃飯聊天都覺得可以從他那學習到很多他多年在 Infrasturcture 上積累下來的寶貴經驗。本來這個話題其實想讓他自己寫的,可是貌似很多牛人對寫文章還是有點惰性的,所以今天很多的內容來自於陶濤師兄,不過還是由我操筆了。提高並發的兩種模式提高高並發其實有兩種大思路。
  • 支付核心系統設計:Airbnb的分布式事務方案簡介
    分布式系統中使用三種不同的常用技術來實現最終的一致性:讀修復,寫修復和異步修復。每種方法各有利弊。三種方式在我們的支付系統中都有使用。異步修復通過伺服器負責運行數據一致性檢查來實現,例如表掃描,lambda函數和cron job。此外,從伺服器到客戶端的異步通知廣泛用於支付行業,以保持客戶端的一致性。
  • 網易雲信「三板斧」,實現千萬級高並發
    如何應對更大數量級的高並發消息量,並能夠真正保障IM服務的穩定和快速,成為各IM雲平臺的重中之重。 其中,周梁偉先生重點分享了網易雲信在連接層的「三板斧」優化是如何在保證穩定快速的情況下實現支持千萬級高並發消息量的,引發了現場參會者和行業人士的極大關注和思考。
  • 如何防止網站高並發引起的系統崩潰?
    如何解決高並發引起的系統崩潰?讓我們來看一下。由高並發引起系統崩潰的解決方案二、由高並發引起系統崩潰的解決方案1.提高硬體能力、增加系統伺服器2.消息隊列在高並發時,資料庫壓力劇增下使用消息隊列,用戶的請求數據發送給消息隊列後立即返回,再由消息隊列的消費者進程從消息隊列中獲取數據,異步寫入資料庫。由於消息隊列伺服器處理速度快於資料庫,因此響應速度得到大幅改善。
  • 1號店11.11:從應用架構落地點談高可用高並發高性能
    1.背景 1.1三高是電商核心交易系統的基礎電商核心交易系統有很多特點,如分布式、高可擴展等,在眾多特性中,高可用、高並發、高性能是基礎。大到技術峰會、論壇、研討會,小到一場面試,高可用、高並發、高性能始終是焦點,是技術大牛、技術追隨者永遠津津樂道的話題,成為他們畢生的追求。
  • 課程實錄:大規模高並發下的分布式存儲架構設計
    【IT168 資訊】雲計算、大數據、人工智慧等技術的廣泛應用,使數據開始呈指數級增長。在海量數據時代,傳統存儲系統已難以滿足業務運行需求,分布式存儲大放異彩,發展迅速。但對於許多企業來說,提高存儲系統的並發性能仍然是一大挑戰,此外系統穩定性、靈活擴展能力、整合異構存儲資源的能力、以及對資源進行智能化管理的需求也不斷增長。