偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

后端|一個(gè)分布式鎖「失效」的案例分析

開(kāi)發(fā) 前端
在日常的開(kāi)發(fā)過(guò)程中,如果涉及到并發(fā)和事務(wù),一定要多留幾個(gè)心眼,考慮周全,確認(rèn)以下要點(diǎn)是否都正確實(shí)現(xiàn)。

小猿最近很苦惱:明明加了分布式鎖,為什么并發(fā)還是會(huì)出問(wèn)題呢?

故事從接到需求開(kāi)始說(shuō)起。

接到需求

小猿前一陣接到一個(gè)小任務(wù),里面有一個(gè)功能對(duì)應(yīng)的場(chǎng)景如下:

  • 封裝一個(gè)對(duì)賬戶(hù)余額進(jìn)行加減操作的方法;
  • 所屬服務(wù)部署了多個(gè)實(shí)例;
  • 這個(gè)方法可能會(huì)有并發(fā)調(diào)用。

注:實(shí)際業(yè)務(wù)場(chǎng)景比較復(fù)雜,已做簡(jiǎn)化。

小猿略作思考,就抓住了關(guān)鍵點(diǎn):余額操作——要注意事務(wù),多實(shí)例——要注意并發(fā)。

小猿的原始代碼如下:

@Override
@Lock(key = "#accountNo")
@Transactional(rollbackFor = Exception.class)
public void updateBalance(String accountNo, AmountOperateParam param) {
    // do something
}

可以看到,這個(gè)方法上通過(guò)注解方式加了分布式鎖和事務(wù),鎖的 key 是 accountNo,也就是賬戶(hù)業(yè)務(wù)主鍵。

自測(cè)和測(cè)試也沒(méi)發(fā)現(xiàn)啥問(wèn)題,就高高興興發(fā)完版回家了。

出問(wèn)題了

第二天一早,就接到少量用戶(hù)反饋,說(shuō)自己的賬戶(hù)余額不對(duì)了。

小猿的第一反應(yīng)是:我這塊自測(cè)和測(cè)試都沒(méi)問(wèn)題,其它功能導(dǎo)致的吧?本地又是一通自測(cè),也沒(méi)有復(fù)現(xiàn)問(wèn)題。但謹(jǐn)慎起見(jiàn),還是往代碼里加了一些日志,來(lái)確認(rèn)是不是自己的方法引發(fā)的。

當(dāng)又有用戶(hù)反饋時(shí),小猿根據(jù)日志的情況確認(rèn)了:還真是自己方法的問(wèn)題,對(duì)同一個(gè)賬戶(hù)的余額操作,多個(gè)并發(fā)請(qǐng)求會(huì)同時(shí)執(zhí)行到方法體里面。

也就是說(shuō)……分布式鎖沒(méi)鎖住?

冥思苦想了好久,又在本地做了大量的測(cè)試,終于讓小猿找到了問(wèn)題所在:AOP 執(zhí)行順序問(wèn)題。

小猿設(shè)計(jì)的時(shí)序:

但實(shí)際的時(shí)序:

也就是說(shuō)期望是這樣的執(zhí)行順序:

但實(shí)際的執(zhí)行順序:

分布式鎖和事務(wù),都是通過(guò) AOP 來(lái)實(shí)現(xiàn)的,而 AOP 的執(zhí)行順序是根據(jù)切面的優(yōu)先級(jí)來(lái)的,而小猿的分布式鎖切面的優(yōu)先級(jí)比事務(wù)切面的優(yōu)先級(jí)低,所以就出現(xiàn)了上面的時(shí)序問(wèn)題。

于是通過(guò)給分布式鎖的切面指定 Order 的方式,讓它的優(yōu)先級(jí)高于事務(wù)切面(注:Order 值越小,執(zhí)行優(yōu)先級(jí)越高),驗(yàn)證完沒(méi)問(wèn)題后,就又高高興興地更新完版本,修復(fù)好歷史問(wèn)題數(shù)據(jù)后回家了。

還有問(wèn)題

誰(shuí)知道第二天一早,還是有極少量的用戶(hù)反饋賬戶(hù)余額不對(duì)的問(wèn)題。

這次小猿就有點(diǎn)懵了,為什么還會(huì)出現(xiàn)這種情況呢?

經(jīng)過(guò)一番艱苦卓絕的排查,終于找到了問(wèn)題所在:事務(wù)嵌套。

從前文中的示例代碼中可以看到,小猿的方法上加了事務(wù)注解 @Transactional(rollbackFor = Exception.class) 里,沒(méi)有指定事務(wù)的傳播行為,默認(rèn)是 Propagation.REQUIRED,也就是說(shuō)如果當(dāng)前沒(méi)有事務(wù),就新建一個(gè)事務(wù);如果當(dāng)前有事務(wù),就加入到當(dāng)前事務(wù)中。

小猿自己寫(xiě)的代碼里沒(méi)有在事務(wù)方法里嵌套調(diào)用這個(gè)方法的情況,但是同事寫(xiě)的代碼里有,這樣就會(huì)導(dǎo)致前文的時(shí)序問(wèn)題再次發(fā)生。

找到問(wèn)題就好辦了,小猿將自己的方法上的事務(wù)傳播行為改成了 Propagation.REQUIRES_NEW,也就是說(shuō)如果當(dāng)前沒(méi)有事務(wù),就新建一個(gè)事務(wù);如果當(dāng)前有事務(wù),就將當(dāng)前事務(wù)掛起,新建一個(gè)事務(wù)。

這次更新完版本后,小猿就再也沒(méi)有收到用戶(hù)反饋了,終于可以安心回家睡覺(jué)了。

小結(jié)

在日常的開(kāi)發(fā)過(guò)程中,如果涉及到并發(fā)和事務(wù),一定要多留幾個(gè)心眼,考慮周全,確認(rèn)以下要點(diǎn)是否都正確實(shí)現(xiàn):

  • 是否做了必要的并發(fā)控制?
  • 事務(wù)的傳播行為是否符合預(yù)期?
  • AOP 的執(zhí)行順序是否符合預(yù)期?
  • 對(duì)并發(fā)的場(chǎng)景是否做了充分的測(cè)試?
  • 對(duì)于比較關(guān)鍵的操作,是否打印了必要的日志?
責(zé)任編輯:趙寧寧 來(lái)源: 悶騷的程序員
相關(guān)推薦

2020-07-30 09:35:09

Redis分布式鎖數(shù)據(jù)庫(kù)

2022-04-14 07:56:30

公平鎖Java線程

2024-02-19 00:00:00

Redis分布式

2024-07-15 08:25:07

2023-03-06 08:14:48

MySQLRedis場(chǎng)景

2021-11-01 12:25:56

Redis分布式

2024-05-08 10:20:00

Redis分布式

2019-06-19 15:40:06

分布式鎖RedisJava

2022-11-11 08:19:03

redis分布式

2022-06-27 08:36:27

分布式事務(wù)XA規(guī)范

2022-09-29 08:28:57

SpringRedis分布式

2022-09-22 13:28:34

Redis分布式鎖

2022-12-18 20:07:55

Redis分布式

2017-10-24 11:28:23

Zookeeper分布式鎖架構(gòu)

2013-09-11 16:02:00

Spark分布式計(jì)算系統(tǒng)

2024-11-28 15:11:28

2018-07-17 08:14:22

分布式分布式鎖方位

2019-02-26 09:51:52

分布式鎖RedisZookeeper

2021-07-16 07:57:34

ZooKeeperCurator源碼

2022-08-04 08:45:50

Redisson分布式鎖工具
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)