最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

1 背景

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

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

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

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

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

比如:

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

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

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

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

etc.很多重要的場(chǎng)景都需要冪等的特性來(lái)支持。

2 冪等性概念

冪等(idempotent)是一個(gè)數(shù)學(xué)與計(jì)算機(jī)學(xué)概念,常見(jiàn)于抽象代數(shù)中。

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

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

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

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

3 冪等性問(wèn)題的常見(jiàn)解決方案 

3.1 查詢操作和刪除操作

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

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

1 -- 用戶庫(kù)查詢某個(gè)身份證號(hào)的用戶名
2 select user_name from t_user where id_no ='xxx';
3 
4 -- 用戶庫(kù)刪除某個(gè)身份證號(hào)的用戶
5 delete from t_user where id_no ='xxx';

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

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

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

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

1 CREATE UNIQUE INDEX uni_user_userid ON t_user(userid);

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

 

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

3.3 token機(jī)制

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

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

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

解決方法: 

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

處理步驟:

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

流程如下,注意:redis要用刪除操作來(lái)判斷token,刪除成功代表token校驗(yàn)通過(guò);

3.4 悲觀鎖

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

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

3.5 樂(lè)觀鎖

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

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

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

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

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

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

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ù)庫(kù)表中,所以唯一性的字段沒(méi)法確定,這時(shí)候可以引入分布式鎖,通過(guò)第三方的系統(tǒng)(redis或zookeeper),

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

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

3.7  select + insert

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

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

3.8 狀態(tài)機(jī)冪等

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

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

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

3.9 保證Api接口的冪等性

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

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

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

4 會(huì)議室的解決方案

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

采用唯一聯(lián)合索引保障高并發(fā)下的冪等性策略。將會(huì)議室ID、時(shí)間段、日期,建立唯一組合索引,防止新增臟數(shù)據(jù),保證不會(huì)有兩條一樣的會(huì)議室預(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í)行會(huì)議預(yù)訂的事務(wù)腳本,如下,當(dāng)數(shù)據(jù)庫(kù)中存在一樣的會(huì)議室信息時(shí),會(huì)返回錯(cuò)誤(被占用)的狀態(tài)值。

1  BEGIN TRAN T_Add;  
2  DECLARE @code INT; DECLARE @occupyMeeing TABLE ( sMeetCode INT ); 
3  DECLARE @resutlTable TABLE ( lType TINYINT,/*返回類(lèi)型0為失敗類(lèi)型,1為成功類(lèi)型*/ resutlValue NVARCHAR(60)/*返回的信息*/ ); 
4  -- Todo 業(yè)務(wù)邏輯 寫(xiě)入數(shù)據(jù)庫(kù)操作,即會(huì)議號(hào)和占用的時(shí)間段標(biāo)識(shí)為聯(lián)合索引,不可重復(fù)插入,重復(fù)插入報(bào)錯(cuò) 
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;

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

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

5 總結(jié)

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

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

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

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

相關(guān)文章

  • 解析SpringSecurity+JWT認(rèn)證流程實(shí)現(xiàn)

    解析SpringSecurity+JWT認(rèn)證流程實(shí)現(xiàn)

    這篇文章主要介紹了解析SpringSecurity+JWT認(rèn)證流程實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • Java調(diào)用opencv實(shí)現(xiàn)圖片矯正功能

    Java調(diào)用opencv實(shí)現(xiàn)圖片矯正功能

    這篇文章主要為大家詳細(xì)介紹了Java如何調(diào)用opencv實(shí)現(xiàn)圖片矯正功能,文中的示例代碼簡(jiǎn)潔易懂,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-09-09
  • MapStruct處理Java中實(shí)體與模型間不匹配屬性轉(zhuǎn)換的方法

    MapStruct處理Java中實(shí)體與模型間不匹配屬性轉(zhuǎn)換的方法

    今天小編就為大家分享一篇關(guān)于MapStruct處理Java中實(shí)體與模型間不匹配屬性轉(zhuǎn)換的方法,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-03-03
  • IntelliJ IDEA的數(shù)據(jù)庫(kù)管理工具實(shí)在太方便了(推薦)

    IntelliJ IDEA的數(shù)據(jù)庫(kù)管理工具實(shí)在太方便了(推薦)

    這篇文章主要介紹了IntelliJ IDEA的數(shù)據(jù)庫(kù)管理工具實(shí)在太方便了,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-09-09
  • java替換url的域名和端口方法

    java替換url的域名和端口方法

    下面小編就為大家?guī)?lái)一篇java替換url的域名和端口方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-02-02
  • java樂(lè)觀鎖原理與實(shí)現(xiàn)案例分析

    java樂(lè)觀鎖原理與實(shí)現(xiàn)案例分析

    這篇文章主要介紹了java樂(lè)觀鎖原理與實(shí)現(xiàn),結(jié)合具體案例形式分析了樂(lè)觀鎖的原理及java使用樂(lè)觀鎖實(shí)現(xiàn)自動(dòng)派單功能的相關(guān)操作技巧,需要的朋友可以參考下
    2019-10-10
  • SparkSQL使用快速入門(mén)

    SparkSQL使用快速入門(mén)

    spark SQL是spark的一個(gè)模塊,主要用于進(jìn)行結(jié)構(gòu)化數(shù)據(jù)的處理。它提供的最核心的編程抽象就是DataFrame。這篇文章主要介紹了SparkSQL使用快速入門(mén),需要的朋友可以參考下
    2021-08-08
  • 使用idea搭建spring項(xiàng)目,利用xml文件的形式進(jìn)行配置方式

    使用idea搭建spring項(xiàng)目,利用xml文件的形式進(jìn)行配置方式

    本文介紹了如何使用SpringIOC和SpringDI的思想開(kāi)發(fā)一個(gè)打印機(jī)模擬程序,實(shí)現(xiàn)了靈活配置彩色墨盒或灰色墨盒以及打印頁(yè)面大小的功能,通過(guò)創(chuàng)建接口和實(shí)現(xiàn)類(lèi),并在配置文件中進(jìn)行依賴注入,實(shí)現(xiàn)了控制反轉(zhuǎn)
    2024-11-11
  • SpringBoot配置文件application.properties的使用

    SpringBoot配置文件application.properties的使用

    這篇文章主要介紹了SpringBoot配置文件application.properties的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05
  • 關(guān)于maven工程多模塊、項(xiàng)目打包問(wèn)題

    關(guān)于maven工程多模塊、項(xiàng)目打包問(wèn)題

    這篇文章主要介紹了關(guān)于maven工程多模塊、項(xiàng)目打包問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-03-03

最新評(píng)論

成都市| 开原市| 西昌市| 朝阳县| 长顺县| 卢龙县| 孟连| 铁岭市| 桦川县| 宁化县| 郸城县| 铜鼓县| 凤阳县| 磐安县| 满洲里市| 柘荣县| 龙南县| 浦东新区| 泰兴市| 漾濞| 揭阳市| 大田县| 探索| 婺源县| 鞍山市| 上思县| 桐城市| 黄龙县| 临武县| 榆中县| 公安县| 普宁市| 安塞县| 东阿县| 吉首市| 砚山县| 忻州市| 西平县| 镇雄县| 法库县| 长岭县|