并發(fā)扣款一致性優(yōu)化,CAS下ABA問題,這個(gè)話題還沒聊完?。。?/h1>
上一篇答星球水友提問,《并發(fā)扣款,如何保證數(shù)據(jù)的一致性?》中提到:用CAS樂觀鎖,可以在盡量不影響吞吐量的情況下,保證數(shù)據(jù)的一致性。
大家有非常多的留言,大概有這么幾類:
- 是否存在ABA問題?
- 為什么不能用:
- UPDATE t_yue SET moneymoney=money-$diff AND money>=$diff;
畫外音:請務(wù)必閱讀前序文章:《并發(fā)扣款,如何保證數(shù)據(jù)的一致性?》。
問題比較多,今天先聊第一個(gè)問題,ABA。
什么是ABA問題?
CAS樂觀鎖機(jī)制確實(shí)能夠提升吞吐,并保證一致性,但在極端情況下可能會(huì)出現(xiàn)ABA問題。
考慮如下操作:
- 并發(fā)1(上):獲取出數(shù)據(jù)的初始值是A,后續(xù)計(jì)劃實(shí)施CAS樂觀鎖,期望數(shù)據(jù)仍是A的時(shí)候,修改才能成功
- 并發(fā)2:將數(shù)據(jù)修改成B
- 并發(fā)3:將數(shù)據(jù)修改回A
- 并發(fā)1(下):CAS樂觀鎖,檢測發(fā)現(xiàn)初始值還是A,進(jìn)行數(shù)據(jù)修改
上述并發(fā)環(huán)境下,并發(fā)1在修改數(shù)據(jù)時(shí),雖然還是A,但已經(jīng)不是初始條件的A了,中間發(fā)生了A變B,B又變A的變化,此A已經(jīng)非彼A,數(shù)據(jù)卻成功修改,可能導(dǎo)致錯(cuò)誤,這就是CAS引發(fā)的所謂的ABA問題。
余額操作,出現(xiàn)ABA問題并不會(huì)對業(yè)務(wù)產(chǎn)生影響,因?yàn)閷τ?ldquo;余額”屬性來說,前一個(gè)A為100余額,與后一個(gè)A為100余額,本質(zhì)是相同的。
但其他場景未必是這樣,舉一個(gè)堆棧操作的例子:
并發(fā)1(上):讀取棧頂?shù)脑貫?ldquo;A1”
并發(fā)2:進(jìn)行了2次出棧
并發(fā)3:又進(jìn)行了1次出棧
并發(fā)1(下):實(shí)施CAS樂觀鎖,發(fā)現(xiàn)棧頂還是“A1”,于是修改為A2
此時(shí)會(huì)出現(xiàn)系統(tǒng)錯(cuò)誤,因?yàn)榇?ldquo;A1”非彼“A1”
ABA問題可以怎么優(yōu)化?
ABA問題導(dǎo)致的原因,是CAS過程中只簡單進(jìn)行了“值”的校驗(yàn),再有些情況下,“值”相同不會(huì)引入錯(cuò)誤的業(yè)務(wù)邏輯(例如余額),有些情況下,“值”雖然相同,卻已經(jīng)不是原來的數(shù)據(jù)了(例如堆棧)。
因此,CAS不能只比對“值”,還必須確保是原來的數(shù)據(jù),才能修改成功。
常見的實(shí)踐是,將“值”比對,升級為“版本號”的比對,一個(gè)數(shù)據(jù)一個(gè)版本,版本變化,即使值相同,也不應(yīng)該修改成功。
余額并發(fā)讀寫例子,引入版本號的具體實(shí)踐如下:
(1)余額表要升級。
- t_yue(uid, money)
升級為:
- t_yue(uid, money, version)
(2)查詢余額時(shí),同時(shí)查詢版本號。
- SELECT money FROM t_yue WHERE sid=$sid
升級為:
- SELECT money,version FROM t_yue WHERE sid=$sid
假設(shè)有并發(fā)操作,都會(huì)將版本號查詢出來。
(3)設(shè)置余額時(shí),必須版本號相同,并且版本號要修改。舊版本“值”比對:
- UPDATE t_yue SET money=38 WHERE uid=$uid AND money=100
升級為“版本號”比對:
- UPDATE t_yue SET money=38, version=$version_new WHERE uid=$uid AND version=$version_old
此時(shí)假設(shè)有并發(fā)操作,首先操作的請求會(huì)修改版本號,并發(fā)操作會(huì)執(zhí)行失敗。
畫外音:version通用,本例是強(qiáng)行用version舉例而已,實(shí)際上本例可以用余額“值”比對。
總結(jié)
- select&set業(yè)務(wù)場景,在并發(fā)時(shí)會(huì)出現(xiàn)一致性問題
- 基于“值”的CAS樂觀鎖,可能導(dǎo)致ABA問題
- CAS樂觀鎖,必須保證修改時(shí)的“此數(shù)據(jù)”就是“彼數(shù)據(jù)”,應(yīng)該由“值”比對,優(yōu)化為“版本號”比對
思路比結(jié)論重要。
【本文為51CTO專欄作者“58沈劍”原創(chuàng)稿件,轉(zhuǎn)載請聯(lián)系原作者】