在分布式場(chǎng)景下,我們經(jīng)常會(huì)有需要實(shí)現(xiàn)冪等的場(chǎng)景吏廉,冪等分為請(qǐng)求冪等和業(yè)務(wù)冪等。
請(qǐng)求冪等
下面將從以下三步來(lái)整理請(qǐng)求冪等的知識(shí)點(diǎn):
- 請(qǐng)求冪等的本質(zhì)
- 怎么做請(qǐng)求冪等
- 如何生成業(yè)務(wù)主鍵
1跛蛋、請(qǐng)求冪等的本質(zhì)
場(chǎng)景介紹:
用戶(hù)A給用戶(hù)B轉(zhuǎn)100W
1).用戶(hù)A請(qǐng)求超時(shí)
2).用戶(hù)A重試
請(qǐng)求冪等需保證:用戶(hù)A的同一個(gè)請(qǐng)求多次重試,最終只會(huì)轉(zhuǎn)賬一次拔第。
請(qǐng)求冪等本質(zhì)
保證請(qǐng)求重復(fù)執(zhí)行和執(zhí)行一次結(jié)果相同,用公式來(lái)表示的話就是:f...f(f(x)) = f(x)场钉。
請(qǐng)求分類(lèi)分析
1.讀:Read/Select蚊俺,讀請(qǐng)求是天然冪等的。
2.寫(xiě):涉及數(shù)據(jù)變更的請(qǐng)求逛万,分為:insert泳猬、update、delete宇植,寫(xiě)請(qǐng)求需要做冪等得封。
在哪里做請(qǐng)求冪等
假設(shè)系統(tǒng)架構(gòu)按如下分層:
- 反向代理(Nginx)
- 網(wǎng)關(guān)層
- 業(yè)務(wù)邏輯層
- 數(shù)據(jù)訪問(wèn)層
- 數(shù)據(jù)庫(kù)
從上述層次結(jié)構(gòu)中可以直到,請(qǐng)求冪等我們需要在數(shù)據(jù)訪問(wèn)層和數(shù)據(jù)庫(kù)來(lái)實(shí)現(xiàn)指郁,因?yàn)檎?qǐng)求重試不管在那一層都有可能出現(xiàn)呛每,因此我們只要保證對(duì)數(shù)據(jù)操作的這一層請(qǐng)求是冪等的即可。
2坡氯、怎么做請(qǐng)求冪等
下面我們?nèi)匀桓鶕?jù)請(qǐng)求的分類(lèi)來(lái)分析怎么實(shí)現(xiàn)請(qǐng)求冪等吧晨横。前面說(shuō)了讀請(qǐng)求時(shí)天然冪等的,所以就只需要看Insert箫柳、Update手形、Delete三種情況下面如何實(shí)現(xiàn)請(qǐng)求冪等。
Insert
針對(duì)Insert操作悯恍,有以下幾種情況:
1.主鍵為業(yè)務(wù)主鍵库糠,插入是冪等的,因?yàn)橥粋€(gè)請(qǐng)求業(yè)務(wù)主鍵肯定是一樣的(后續(xù)說(shuō)明如何生成業(yè)務(wù)主鍵)涮毫。
2.主鍵為自增主鍵且有唯一索引瞬欧,此時(shí)插入是冪等的,與第一點(diǎn)類(lèi)似罢防,借助的都是數(shù)據(jù)庫(kù)的唯一性來(lái)保證請(qǐng)求的冪等艘虎。
3.主鍵是自增主鍵且沒(méi)有唯一索引,此時(shí)插入不是冪等的咒吐,也就是說(shuō)同一個(gè)請(qǐng)求時(shí)可以多次插入的野建,最終導(dǎo)致數(shù)據(jù)錯(cuò)誤。
從以上三點(diǎn)可以看出恬叹,插入數(shù)據(jù)的冪等性重點(diǎn)在于主鍵是不是自增主鍵且沒(méi)有唯一索引候生。因此我們只需要保證主鍵是業(yè)務(wù)主鍵,或者包含唯一索引绽昼。
Update
對(duì)update的分析要從單線程還是多線程來(lái)分析:
1.單線程重發(fā)請(qǐng)求唯鸭,也就是說(shuō)請(qǐng)求的重發(fā)是同一個(gè)線程觸發(fā)的,此時(shí)線程的Update條件是一致的硅确,因此不管執(zhí)行一次還是多次結(jié)果都是一樣的目溉。因此此時(shí)修改是冪等的唠粥。
2.多線程重發(fā)請(qǐng)求,這時(shí)候會(huì)出現(xiàn)經(jīng)典的ABA問(wèn)題停做,比如以下SQL在多線程下面就會(huì)出現(xiàn)ABA問(wèn)題:
1). A:update user set sex=18 where uid = 66
2). B:update user set sex=19 where uid = 66
3). A:update user set sex=18 where uid = 66
這時(shí)候,因?yàn)锳BA問(wèn)題的存在大莫,Update操作請(qǐng)求就不是冪等的了蛉腌。
解決ABA問(wèn)題的最常見(jiàn)手段就是版本號(hào)了,也就是在條件中加上版本號(hào)來(lái)判斷是否已有其他線程操作過(guò)相同記錄只厘。比如上述SQL可以?xún)?yōu)化為:
1). A:update user set sex=18,v++ where uid = 66 and version = 1
2). B:update user set sex=19,v++ where uid = 66 and version = 1
3). A:update user set sex=18,v++ where uid = 66 and version = 1
通過(guò)使用版本號(hào)烙丛,我們就可以保證Update請(qǐng)求也是冪等的了。
Delete
Delete的冪等實(shí)現(xiàn)和Update是一樣的羔味,就不在詳細(xì)說(shuō)明了河咽。
3、如何生成業(yè)務(wù)主鍵
系統(tǒng)生成業(yè)務(wù)主鍵可以從以下三個(gè)步驟來(lái)實(shí)現(xiàn):
1.客戶(hù)端在發(fā)送業(yè)務(wù)請(qǐng)求前赋元,先獲得一個(gè)唯一請(qǐng)求ID忘蟹,該請(qǐng)求ID生成接口可獨(dú)立提供。
2.客戶(hù)端獲得請(qǐng)求唯一ID后搁凸,發(fā)送業(yè)務(wù)請(qǐng)求媚值。業(yè)務(wù)邏輯層生成業(yè)務(wù)ID,并在redis記錄請(qǐng)求唯一ID與業(yè)務(wù)唯一ID的映射關(guān)系护糖。
3.后續(xù)改請(qǐng)求重發(fā)過(guò)來(lái)到redis查詢(xún)對(duì)應(yīng)的業(yè)務(wù)唯一ID即可褥芒。
通過(guò)以上三步實(shí)現(xiàn)較為通用的業(yè)務(wù)主鍵生成功能。