CAS下ABA問題及優化方案|架構師之路

編程語言 Java SQL 科技 編程語言 Java SQL 科技 穩穩地幸福y 2017-06-27

一、併發業務場景

庫存業務,stock(sid, num),其中:

  • sid為庫存id

  • num為庫存值

CAS下ABA問題及優化方案|架構師之路

如上圖所示,兩個併發的查詢庫存操作,同時從數據庫都得到了庫存是5。

接下來用戶發生了併發的庫存扣減動作:

CAS下ABA問題及優化方案|架構師之路

如上圖所示:

  • 用戶1購買了3個庫存,於是庫存要設置為2

  • 用戶2購買了2個庫存,於是庫存要設置為3

這兩個設置庫存的接口併發執行,庫存會先變成2,再變成3,導致數據不一致(實際賣出了5件商品,但庫存只扣減了2,最後一次設置庫存會覆蓋和掩蓋前一次併發操作)

二、不一致原因分析

出現數據不一致的根本原因,是設置操作發生的時候,沒有檢查庫存與查詢出來的庫存有沒有變化,理論上:

  • 僅庫存為5的時候,用戶1的庫存設置2才能成功

  • 僅庫存為5的時候,用戶2的庫存設置3才能成功

實際執行的時候:

  • 庫存為5,用戶1的set stock 2確實應該成功

  • 庫存變為2了,用戶2的set stock 3應該失敗掉

三、CAS優化

大家常說的“Compare And Set”(CAS),是一種常見的降低讀寫鎖衝突,保證數據一致性的樂觀鎖機制。

針對上述庫存扣減的例子,CAS升級很容易,將庫存設置接口執行的SQL:

update stock set num=$num_new where sid=$sid

升級為:

update stock set num=$num_new where sid=$sid and num=$num_old

即可。

四、什麼是ABA問題

CAS樂觀鎖機制確實能夠提升吞吐,並保證一致性,但在極端情況下可能會出現ABA問題。

什麼是ABA問題?

考慮如下操作:

  • 併發1(上):獲取出數據的初始值是A,後續計劃實施CAS樂觀鎖,期望數據仍是A的時候,修改才能成功

  • 併發2:將數據修改成B

  • 併發3:將數據修改回A

  • 併發1(下):CAS樂觀鎖,檢測發現初始值還是A,進行數據修改

上述併發環境下,併發1在修改數據時,雖然還是A,但已經不是初始條件的A了,中間發生了A變B,B又變A的變化,此A已經非彼A,數據卻成功修改,可能導致錯誤,這就是CAS引發的所謂的ABA問題。

庫存操作,出現ABA問題並不會對業務產生影響。

再看一個堆棧操作的例子:

CAS下ABA問題及優化方案|架構師之路

併發1(上):讀取棧頂的元素為“A1”

CAS下ABA問題及優化方案|架構師之路

併發2:進行了2次出棧

CAS下ABA問題及優化方案|架構師之路

併發3:又進行了1次出棧

CAS下ABA問題及優化方案|架構師之路

併發1(下):實施CAS樂觀鎖,發現棧頂還是“A1”,於是修改為A2

CAS下ABA問題及優化方案|架構師之路

此時會出現系統錯誤,因為此“A1”非彼“A1”

五、ABA問題的優化

ABA問題導致的原因,是CAS過程中只簡單進行了“值”的校驗,再有些情況下,“值”相同不會引入錯誤的業務邏輯(例如庫存),有些情況下,“值”雖然相同,卻已經不是原來的數據了。

優化方向:CAS不能只比對“值”,還必須確保的是原來的數據,才能修改成功。

常見實踐:“版本號”的比對,一個數據一個版本,版本變化,即使值相同,也不應該修改成功。

庫存的併發讀寫例子,引入版本號的具體實踐如下:

(1)庫存表由

stock(sid, num)

升級為

stock(sid, num, version)

(2)查詢庫存時同時查詢版本號

select num from stock where sid=$sid

升級為

select num, version from stock where sid=$sid

CAS下ABA問題及優化方案|架構師之路

假設有併發操作,都會將版本號查詢出來

(3)設置庫存時,必須版本號相同,並且版本號要修改

舊版本“值”比對CAS

update stock set num=$num_new where sid=$sid and num=$num_old

升級為“版本號”比對CAS

update stock set num=$num_new, version=$version_new

where sid=$sid and version=$version_old

CAS下ABA問題及優化方案|架構師之路

此時假設有併發操作,第一個操作,比對版本號成功,於是把庫存和版本號都進行了修改。

CAS下ABA問題及優化方案|架構師之路

同時存在的第二個併發操作,比對版本號發生了變化,也是庫存應該修改失敗。

六、總結

  • select&set業務場景,在併發時會出現一致性問題

  • 基於“值”的CAS樂觀鎖,可能導致ABA問題

  • CAS樂觀鎖,必須保證修改時的“此數據”就是“彼數據”,應該由“值”比對,優化為“版本號”比對

是否看了這下五張圖片,覺得自己還有很多沒有鞏固的知識呢。

1、具有1-5工作經驗的,面對目前流行的技術不知從何下手,需要突破技術瓶頸的可以加群。

2、在公司待久了,過得很安逸,但跳槽時面試碰壁。需要在短時間內進修、跳槽拿高薪的可以加群。

3、如果沒有工作經驗,但基礎非常紮實,對java工作機制,常用設計思想,常用java開發框架掌握熟練的,可以加群。

4、覺得自己很牛B,一般需求都能搞定。但是所學的知識點沒有系統化,很難在技術領域繼續突破的可以加群。

5. 群號:高級架構群 283943715 備註好信息!

6.阿里Java高級大牛直播講解知識點,分享知識,上面五大專題都是各位老師多年工作經驗的梳理和總結,帶著大家全面、科學地建立自己的技術體系和技術認知!

CAS下ABA問題及優化方案|架構師之路

高可用/可擴展

CAS下ABA問題及優化方案|架構師之路

性能優化

CAS下ABA問題及優化方案|架構師之路

高併發/高性能

CAS下ABA問題及優化方案|架構師之路

團隊協作效率專題

CAS下ABA問題及優化方案|架構師之路

源碼分析專題

一、併發業務場景

庫存業務,stock(sid, num),其中:

  • sid為庫存id

  • num為庫存值

CAS下ABA問題及優化方案|架構師之路

如上圖所示,兩個併發的查詢庫存操作,同時從數據庫都得到了庫存是5。

接下來用戶發生了併發的庫存扣減動作:

CAS下ABA問題及優化方案|架構師之路

如上圖所示:

  • 用戶1購買了3個庫存,於是庫存要設置為2

  • 用戶2購買了2個庫存,於是庫存要設置為3

這兩個設置庫存的接口併發執行,庫存會先變成2,再變成3,導致數據不一致(實際賣出了5件商品,但庫存只扣減了2,最後一次設置庫存會覆蓋和掩蓋前一次併發操作)

二、不一致原因分析

出現數據不一致的根本原因,是設置操作發生的時候,沒有檢查庫存與查詢出來的庫存有沒有變化,理論上:

  • 僅庫存為5的時候,用戶1的庫存設置2才能成功

  • 僅庫存為5的時候,用戶2的庫存設置3才能成功

實際執行的時候:

  • 庫存為5,用戶1的set stock 2確實應該成功

  • 庫存變為2了,用戶2的set stock 3應該失敗掉

三、CAS優化

大家常說的“Compare And Set”(CAS),是一種常見的降低讀寫鎖衝突,保證數據一致性的樂觀鎖機制。

針對上述庫存扣減的例子,CAS升級很容易,將庫存設置接口執行的SQL:

update stock set num=$num_new where sid=$sid

升級為:

update stock set num=$num_new where sid=$sid and num=$num_old

即可。

四、什麼是ABA問題

CAS樂觀鎖機制確實能夠提升吞吐,並保證一致性,但在極端情況下可能會出現ABA問題。

什麼是ABA問題?

考慮如下操作:

  • 併發1(上):獲取出數據的初始值是A,後續計劃實施CAS樂觀鎖,期望數據仍是A的時候,修改才能成功

  • 併發2:將數據修改成B

  • 併發3:將數據修改回A

  • 併發1(下):CAS樂觀鎖,檢測發現初始值還是A,進行數據修改

上述併發環境下,併發1在修改數據時,雖然還是A,但已經不是初始條件的A了,中間發生了A變B,B又變A的變化,此A已經非彼A,數據卻成功修改,可能導致錯誤,這就是CAS引發的所謂的ABA問題。

庫存操作,出現ABA問題並不會對業務產生影響。

再看一個堆棧操作的例子:

CAS下ABA問題及優化方案|架構師之路

併發1(上):讀取棧頂的元素為“A1”

CAS下ABA問題及優化方案|架構師之路

併發2:進行了2次出棧

CAS下ABA問題及優化方案|架構師之路

併發3:又進行了1次出棧

CAS下ABA問題及優化方案|架構師之路

併發1(下):實施CAS樂觀鎖,發現棧頂還是“A1”,於是修改為A2

CAS下ABA問題及優化方案|架構師之路

此時會出現系統錯誤,因為此“A1”非彼“A1”

五、ABA問題的優化

ABA問題導致的原因,是CAS過程中只簡單進行了“值”的校驗,再有些情況下,“值”相同不會引入錯誤的業務邏輯(例如庫存),有些情況下,“值”雖然相同,卻已經不是原來的數據了。

優化方向:CAS不能只比對“值”,還必須確保的是原來的數據,才能修改成功。

常見實踐:“版本號”的比對,一個數據一個版本,版本變化,即使值相同,也不應該修改成功。

庫存的併發讀寫例子,引入版本號的具體實踐如下:

(1)庫存表由

stock(sid, num)

升級為

stock(sid, num, version)

(2)查詢庫存時同時查詢版本號

select num from stock where sid=$sid

升級為

select num, version from stock where sid=$sid

CAS下ABA問題及優化方案|架構師之路

假設有併發操作,都會將版本號查詢出來

(3)設置庫存時,必須版本號相同,並且版本號要修改

舊版本“值”比對CAS

update stock set num=$num_new where sid=$sid and num=$num_old

升級為“版本號”比對CAS

update stock set num=$num_new, version=$version_new

where sid=$sid and version=$version_old

CAS下ABA問題及優化方案|架構師之路

此時假設有併發操作,第一個操作,比對版本號成功,於是把庫存和版本號都進行了修改。

CAS下ABA問題及優化方案|架構師之路

同時存在的第二個併發操作,比對版本號發生了變化,也是庫存應該修改失敗。

六、總結

  • select&set業務場景,在併發時會出現一致性問題

  • 基於“值”的CAS樂觀鎖,可能導致ABA問題

  • CAS樂觀鎖,必須保證修改時的“此數據”就是“彼數據”,應該由“值”比對,優化為“版本號”比對

是否看了這下五張圖片,覺得自己還有很多沒有鞏固的知識呢。

1、具有1-5工作經驗的,面對目前流行的技術不知從何下手,需要突破技術瓶頸的可以加群。

2、在公司待久了,過得很安逸,但跳槽時面試碰壁。需要在短時間內進修、跳槽拿高薪的可以加群。

3、如果沒有工作經驗,但基礎非常紮實,對java工作機制,常用設計思想,常用java開發框架掌握熟練的,可以加群。

4、覺得自己很牛B,一般需求都能搞定。但是所學的知識點沒有系統化,很難在技術領域繼續突破的可以加群。

5. 群號:高級架構群 283943715 備註好信息!

6.阿里Java高級大牛直播講解知識點,分享知識,上面五大專題都是各位老師多年工作經驗的梳理和總結,帶著大家全面、科學地建立自己的技術體系和技術認知!

CAS下ABA問題及優化方案|架構師之路

高可用/可擴展

CAS下ABA問題及優化方案|架構師之路

性能優化

CAS下ABA問題及優化方案|架構師之路

高併發/高性能

CAS下ABA問題及優化方案|架構師之路

團隊協作效率專題

CAS下ABA問題及優化方案|架構師之路

源碼分析專題

相關推薦

推薦中...