欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

從架構(gòu)思維角度分析高并發(fā)下冪等性解決方案

 更新時間:2022年01月27日 08:39:23   作者:Brand  
冪等(idempotent、idempotence)是一個數(shù)學(xué)與計算機學(xué)概念,常見于抽象代數(shù)中。?在編程中.一個冪等操作的特點是其任意多次執(zhí)行所產(chǎn)生的影響均與一次執(zhí)行的影響相同。冪等函數(shù),或冪等方法,是指可以使用相同參數(shù)重復(fù)執(zhí)行,并能獲得相同結(jié)果的函數(shù)

1 背景

我們的云辦公系統(tǒng)有一個會議預(yù)定模塊,每個月最后一個工作日的下午三點,會啟動對下個月會議室的可用預(yù)定。

公司的 會議室大約200個,但是需求量遠不止于此,所以會形成會議室搶訂的場面(搶訂大軍為行政助理、人事助理、開發(fā)經(jīng)理、產(chǎn)品運營等對會議室有剛性需求的人)。

程序團隊,經(jīng)常會接到投訴,A同學(xué)和B同學(xué)搶了同一個會議室, 前端頁面顯示為兩個占位圖片,從數(shù)據(jù)庫看,是插入了兩條同一個會議位置的數(shù)據(jù),這兩條數(shù)據(jù)的發(fā)起人員分別是A和B。

這就牽扯出一個數(shù)學(xué)與計算機學(xué)概念: 冪等。

在計算機系統(tǒng)操作中,有很多種行為,需要保證無論執(zhí)行多少次,都應(yīng)該產(chǎn)生一樣的效果或返回一樣的結(jié)果。 

比如:

1、前端重復(fù)點擊提交表單選中的數(shù)據(jù),在后臺應(yīng)該只能有一個數(shù)據(jù)錄入到數(shù)據(jù)庫;

2、發(fā)送同一個消息,也應(yīng)該只發(fā)一次,用戶不會收到多條一樣的數(shù)據(jù);

3、創(chuàng)建業(yè)務(wù)訂單,一次業(yè)務(wù)請求只能創(chuàng)建一個,如果程序沒有保證冪等,創(chuàng)建出多條訂單數(shù)據(jù),就混亂了。

4、在高并**況下,對于單一的數(shù)據(jù),不可以多次使用,比如一張確定位置的電影票,不會被多次預(yù)訂成功。同理的,同一時間的一個會議室信息,不會被多次預(yù)訂。

etc.很多重要的場景都需要冪等的特性來支持。

2 冪等性概念

冪等(idempotent)是一個數(shù)學(xué)與計算機學(xué)概念,常見于抽象代數(shù)中。

在我們的開發(fā)過程中,保證冪等性就是保證你的程序的無論執(zhí)行多少次,影響均與第一次執(zhí)行的影響是一致的,產(chǎn)生的結(jié)果也是一樣的。

而冪等函數(shù)(冪等方法),是指使用相同的參數(shù)結(jié)構(gòu)重復(fù)執(zhí)行,產(chǎn)生相同的結(jié)果的函數(shù),重復(fù)執(zhí)行冪等函數(shù)不會影響系統(tǒng)的狀態(tài)或者造成改變。

例如,"getUserName(String uCode)" 和 "delUser(String uCode)" 函數(shù)就是典型的冪等函數(shù),而更復(fù)雜的冪等保證是類似 高并發(fā)場景下的訂單號(流水號)或者 秒殺場景下的唯一有效數(shù)據(jù) 等。

所以,冪等就是一個操作,不論執(zhí)行多少次,產(chǎn)生的效果和返回的結(jié)果都是一樣的。

3 冪等性問題的常見解決方案 

3.1 查詢操作和刪除操作

查詢一次和查詢多次,在數(shù)據(jù)不變的情況下,查詢結(jié)果是一樣的,所以嚴格來說, select是天然的冪等操作。

刪除也是一樣的, 對于單條數(shù)據(jù)來說,刪除一次和刪除多次都是把數(shù)據(jù)刪除,影響和結(jié)果都是一樣(當(dāng)然,程序上 的執(zhí)行的返回結(jié)果可能會不一樣,比如操作數(shù)據(jù)庫的時候,刪除的數(shù)據(jù)不存在,返回0,正常刪除成功,返回1) 。 

1 -- 用戶庫查詢某個身份證號的用戶名
2 select user_name from t_user where id_no ='xxx';
3 
4 -- 用戶庫刪除某個身份證號的用戶
5 delete from t_user where id_no ='xxx';

3.2 使用唯一索引 或者唯一組合索引

避免插入同樣信息的臟數(shù)據(jù)。

比如:中秋節(jié)到了,淘寶上線某款**版的月餅,每個用戶都只能購買一盒月餅,如何防止用戶被創(chuàng)建多條月餅訂單數(shù)據(jù),可以給月餅銷售表中的用戶ID加唯一索引( 不允許被索引的數(shù)據(jù)列包含重復(fù)的值),

保證一個用戶只能創(chuàng)建成功一條月餅訂單記錄。

1 CREATE UNIQUE INDEX uni_user_userid ON t_user(userid);

唯一索引或唯一組合索引來防止新增數(shù)據(jù)出現(xiàn)臟數(shù)據(jù)(當(dāng)表存在唯一索引,并發(fā)執(zhí)行時,先進入的執(zhí)行成功,后進入的會執(zhí)行失敗,說明該數(shù)據(jù)已經(jīng)存在了,返回結(jié)果即可)。如下圖所示。

 

回到我們上面的哪個會議室預(yù)訂,也可以是一樣的方式,可以用會議室編號(該編號具有唯一標(biāo)識)作為唯一索引,但是他的實際情況更復(fù)雜。 

3.3 token機制

防止頁面重復(fù)提交而導(dǎo)致的數(shù)據(jù)重復(fù)

業(yè)務(wù)現(xiàn)象: 頁面的數(shù)據(jù)只能被提交一次,或者提交多次的結(jié)果是一致的,不會產(chǎn)生多余的臟數(shù)據(jù)。

產(chǎn)生的原因: 由于系統(tǒng)卡頓導(dǎo)致的重復(fù)點擊或網(wǎng)絡(luò)重發(fā),還有就是nginx重發(fā)等情況,導(dǎo)致的數(shù)據(jù)被重復(fù)提交;

解決方法: 

  • 集群環(huán)境采用token加redis(redis單線程的,處理需要排隊);
  • 單JVM環(huán)境:采用token加redis或token加jvm內(nèi)存。

處理步驟:

  • 數(shù)據(jù)提交前要向服務(wù)的申請token,token放到redis或jvm內(nèi)存,token需要設(shè)置有效時間,一般我們一個請求從request到respond時間是很短的,所以有效時間可以設(shè)置短一點;
  • 提交后后臺校驗token,同時刪除token,返回執(zhí)行結(jié)果。token特點:一次有效性,用完即刪,可以限流執(zhí)行。

流程如下,注意:redis要用刪除操作來判斷token,刪除成功代表token校驗通過;

3.4 悲觀鎖

獲取數(shù)據(jù)的時候加鎖獲取。 select * from t_name where id='xxx' for update; 

注意:這邊的id字段一定是主鍵或者唯一索引,不然會導(dǎo)致鎖表。悲觀鎖使用時一般會配合事務(wù)一起使用,數(shù)據(jù)鎖定時間可能會很長,根據(jù)實際情況選用。  

3.5 樂觀鎖

樂觀鎖只是在更新數(shù)據(jù)那一刻鎖表,其他時間不鎖表,所以相對于悲觀鎖,效率更高,適用于多讀少寫的類型,并發(fā)大的情況。

樂觀鎖的實現(xiàn)方式多種多樣,可以通過version或者其他狀態(tài)條件:

1. 通過版本號實現(xiàn)  update t_name set name=#{name},version=version+1 where version=#{version}; 

2. 通過條件限制  update t_name set avai_amount=avai_amount-#subAmount# where avai_amount-#subAmount# >= 0  

使用版本號的方式執(zhí)行過程如下圖:

這邊需要注意: 樂觀鎖的更新操作,如果加上主鍵或者唯一索引來作為條件, 更新時鎖的是行,否則更新時會鎖表,性能效率差很多。所以上面兩個sql改成下面兩個會好很多。 

1 update t_name set name=#name#,version=version+1 where id=#id# and version=#version#;
2 update t_name set avai_amount=avai_amount-#subAmount# where id=#id# and avai_amount-#subAmount# >= 0;

3.6 分布式鎖

如果是分布是系統(tǒng),構(gòu)建全局唯一索引比較困難,不同的鏈路業(yè)務(wù)可能分布在不同的數(shù)據(jù)庫表中,所以唯一性的字段沒法確定,這時候可以引入分布式鎖,通過第三方的系統(tǒng)(redis或zookeeper),

在業(yè)務(wù)系統(tǒng)插入數(shù)據(jù)或者更新數(shù)據(jù),獲取分布式鎖,然后做操作,完成業(yè)務(wù)操作之后,釋放鎖,這樣其實是把多線程并發(fā)的鎖的思路,引入多多個系統(tǒng),也就是分布式系統(tǒng)中得解決思路。

關(guān)鍵點:某個長流程處理過程要求不能并發(fā)執(zhí)行,可以在流程執(zhí)行之前根據(jù)某個標(biāo)志(用戶ID+后綴等)獲取分布式鎖,其他流程執(zhí)行時獲取鎖就會失敗,也就是同一時間該流程只能有一個能執(zhí)行成功,執(zhí)行完成后,釋放分布式鎖(分布式鎖要第三方系統(tǒng)提供)。 

3.7  select + insert

并發(fā)不高的后臺系統(tǒng),或者一些簡單的執(zhí)行任務(wù),為了支持冪等,支持重復(fù)執(zhí)行,簡單的處理方法是,先查詢下一些關(guān)鍵數(shù)據(jù),判斷是否已經(jīng)執(zhí)行過,在進行業(yè)務(wù)處理,就可以了。

但是同樣有問題,核心高并發(fā)流程不便使用這種方法。因為他本質(zhì)上還是兩個步驟,中間還有執(zhí)行間隙的,在超高并發(fā)的情況還是會造成數(shù)據(jù)不一致的情況,這對于核心業(yè)務(wù)就是災(zāi)難了。 

3.8 狀態(tài)機冪等

在設(shè)計單據(jù)相關(guān)的業(yè)務(wù),或者是任務(wù)相關(guān)的業(yè)務(wù),肯定會涉及到狀態(tài)機(狀態(tài)變更圖),就是業(yè)務(wù)單據(jù)上面有個狀態(tài),狀態(tài)在不同的情況下會發(fā)生變更,一般情況下存在有限狀態(tài)機,

這時候,如果狀態(tài)機已經(jīng)處于下一個狀態(tài),這時候來了一個上一個狀態(tài)的變更,理論上是不能夠變更的,這樣的話,保證了有限狀態(tài)機的冪等。

注意:訂單等單據(jù)類業(yè)務(wù),存在很長的狀態(tài)流轉(zhuǎn),一定要深刻理解狀態(tài)機,對業(yè)務(wù)系統(tǒng)設(shè)計能力提高有很大幫助  

3.9 保證Api接口的冪等性

如銀聯(lián)提供的付款接口:需要接入商戶提交付款請求時附帶:source來源,seq序列號 ,source+seq在數(shù)據(jù)庫里面做唯一索引,防止多次付款(并發(fā)時,只能處理一個請求) 。

關(guān)鍵點:核心業(yè)務(wù)功能,對外提供接口為了支持冪等調(diào)用,接口有兩個字段必須傳,一個是來源source,一個是來源方序列號seq,這個兩個字段在提供方系統(tǒng)里面做聯(lián)合唯一索引,這樣當(dāng)?shù)谌秸{(diào)用時,

先在本方系統(tǒng)里面查詢一下,是否已經(jīng)處理過,返回相應(yīng)處理結(jié)果;沒有處理過,進行相應(yīng)處理,返回結(jié)果。為了冪等友好,最好先查詢一下,是否處理過該筆業(yè)務(wù),不查詢直接插入業(yè)務(wù)系統(tǒng),會報錯,而實際是已經(jīng)處理過了。  

4 會議室的解決方案

將每天的會議預(yù)定按照半個小時1位做48位占用位符預(yù)算,建立緩存機制,進行高效率的占位判斷,并反寫到預(yù)定表;啟動額外調(diào)度服務(wù)做最終的預(yù)定持久化;

采用唯一聯(lián)合索引保障高并發(fā)下的冪等性策略。將會議室ID、時間段、日期,建立唯一組合索引,防止新增臟數(shù)據(jù),保證不會有兩條一樣的會議室預(yù)定記錄插入 

1 CREATE UNIQUE CLUSTERED INDEX [ClusteredIndex_A9_MeetingReser] ON A9_MeetingReser
2 (
3 [timespan] ASC,
4 [roomid] ASC,
5 [sdate] ASC
6 )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]

執(zhí)行會議預(yù)訂的事務(wù)腳本,如下,當(dāng)數(shù)據(jù)庫中存在一樣的會議室信息時,會返回錯誤(被占用)的狀態(tài)值。

1  BEGIN TRAN T_Add;  
2  DECLARE @code INT; DECLARE @occupyMeeing TABLE ( sMeetCode INT ); 
3  DECLARE @resutlTable TABLE ( lType TINYINT,/*返回類型0為失敗類型,1為成功類型*/ resutlValue NVARCHAR(60)/*返回的信息*/ ); 
4  -- Todo 業(yè)務(wù)邏輯 寫入數(shù)據(jù)庫操作,即會議號和占用的時間段標(biāo)識為聯(lián)合索引,不可重復(fù)插入,重復(fù)插入報錯 
5  IF @@ERROR!=0 goto w_err;  
6  COMMIT TRAN T_Add ; 
7  goto w_end   w_err:  
8  ROLLBACK TRAN T_Add ;  
9  w_end:  SELECT * FROM @resutlTable;

原來從預(yù)定到判斷占用到寫庫會耗時0.5~1s,優(yōu)化后整個流程執(zhí)行性能提升到50ms左右,避免了會議室預(yù)定沖突的情況。

結(jié)果:根據(jù)會議室預(yù)定記錄的統(tǒng)計,優(yōu)化發(fā)布之后再未發(fā)生過預(yù)定沖突的問題。免除了會議管理員與預(yù)定人員溝通協(xié)調(diào)會議室的成本,解決了長期困擾他們的問題。 

5 總結(jié)

冪等本質(zhì)上與系統(tǒng)是否分布式、高并發(fā),業(yè)務(wù)執(zhí)行頻率高不高,沒有直接的關(guān)系。關(guān)鍵是程序的操作過程是不是冪等的。

典型的冪等操作就是:把某個變量設(shè)置為1這種行為,不管執(zhí)行多少次都是冪等的,你在進行互聯(lián)網(wǎng)支付的時候,即使系統(tǒng)卡頓,你提交多次,也只支付一次。

要做到冪等性,從接口設(shè)計上來說不設(shè)計任何非冪等的操作即可。特別在類似支付寶,銀行,互聯(lián)網(wǎng)金融公司等涉及的網(wǎng)上資金系統(tǒng),既要高效,數(shù)據(jù)也要準(zhǔn)確,不能出現(xiàn)多扣款,多打款,產(chǎn)生金錢交易不一致等問題。

以上就是從架構(gòu)思維角度分析高并發(fā)下冪等性解決方案的詳細內(nèi)容,更多關(guān)于高并發(fā)下冪等性架構(gòu)思維解決方案的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 微信小程序 開發(fā)中遇到問題總結(jié)

    微信小程序 開發(fā)中遇到問題總結(jié)

    這篇文章主要介紹了微信小程序 開發(fā)中遇到問題總結(jié)的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • Mybatis如何使用注解優(yōu)化代碼

    Mybatis如何使用注解優(yōu)化代碼

    這篇文章主要介紹了Mybatis如何使用注解優(yōu)化代碼,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-11-11
  • 深入理解Java反射

    深入理解Java反射

    在理解反射原理之前先要搞清類型信息。接下來通過本文給大家介紹java反射的深入理解,非常不錯,具有參考借鑒價值,感興趣的朋友一起看下吧
    2016-07-07
  • java實現(xiàn)水仙花數(shù)的計算

    java實現(xiàn)水仙花數(shù)的計算

    這篇文章主要為大家詳細介紹了java實現(xiàn)水仙花數(shù)的計算,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-08-08
  • springboot+kafka中@KafkaListener動態(tài)指定多個topic問題

    springboot+kafka中@KafkaListener動態(tài)指定多個topic問題

    這篇文章主要介紹了springboot+kafka中@KafkaListener動態(tài)指定多個topic問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-12-12
  • Spring @Scheduler使用cron表達式時的執(zhí)行問題詳解

    Spring @Scheduler使用cron表達式時的執(zhí)行問題詳解

    Spring給程序猿們帶來了許多便利。下面這篇文章主要給大家介紹了關(guān)于Spring @Scheduler使用cron表達式時的執(zhí)行問題的相關(guān)資料,文中通過示例代碼介紹的非常詳細,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-09-09
  • Java動態(tài)代理(設(shè)計模式)代碼詳解

    Java動態(tài)代理(設(shè)計模式)代碼詳解

    這篇文章主要介紹了Java動態(tài)代理(設(shè)計模式)代碼詳解,具有一定借鑒價值,需要的朋友可以參考下
    2017-12-12
  • springmvc接口接收參數(shù)與請求參數(shù)格式的整理

    springmvc接口接收參數(shù)與請求參數(shù)格式的整理

    這篇文章主要介紹了springmvc接口接收參數(shù)與請求參數(shù)格式的整理,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • 詳解Java語言中的抽象類與繼承

    詳解Java語言中的抽象類與繼承

    這篇文章主要為大家詳細介紹了Java語言中的抽象類與繼承的相關(guān)資料,文中的示例代碼講解詳細,對我們學(xué)習(xí)Java有一定的幫助,感興趣的小伙伴快跟隨小編一起了解一下
    2022-10-10
  • Java生成堆內(nèi)存dump的問題

    Java生成堆內(nèi)存dump的問題

    這篇文章主要介紹了Java生成堆內(nèi)存dump的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-12-12

最新評論