CAS解決數據一致性問題

什麼是CAS?“Compare And Set”(CAS),是一種常見的降低讀寫鎖衝突,保證數據一致性的方法。
數據一致性是我們開發時必須注意的問題,特別涉及到錢這塊。
這裏舉一個用戶購物的例子:
現有一個用戶信息表user_account,表中字段爲id,uid,amount。
表中現有用戶甲,餘額100元。
現在甲想購買一個價值10元(並打9折)的商品,那麼流程如下:
1.select amount from user_account where uid = $uid;
查詢出甲的餘額: $old_amount爲100元
2.業務邏輯計算

if ($old_amount >= 10 * 0.9 ){
     $new_amount = $old_amount - 10 * 0.9;
     //進行下一步
} else {
     return false;
}

3.update user_account set amount = $new_amount where uid = $uid

更新數據用戶餘額
以上這幾步在單機或者併發量低的情況下是沒有問題的,但是隨着系統流量數據變大,在高併發的分佈式環境下,這種“查詢+修改”的業務就容易引發一致性問題。
比如這種情況:
有兩個業務,一個業務A想購買一樣物品(20元打8折),一個業務B也想購買一樣物品(30元,打7折)
流程如下:
1.業務A,業務B同時去查數據庫,此時$old_amount都爲100元
2.業務A算出自己付款後餘額100-20 * 0.8=84,業務B算出自己付款後餘額100-30 * 0.7=79元
3.業務A更新數據庫amount=84,業務B更新數據庫amount=79
最終用戶數據庫餘額amount爲79,這肯定是不對的。
如何解決這種問題?
就要用到CAS了,我們在set寫入數據的時候,可以加上amount初始狀態的條件compare,只有amount不變時,才允許set寫入成功。
這裏我們將update user_account set amount = $new_amount where uid = $uid改爲update user_account set amount = $new_amount where uid = $uid and amount = $old_amount即可

在併發情況下
業務A執行 update user_account set amount = 84 where uid = $uid and amount=100
業務B執行 update user_account set amount = 79 where uid = $uid and amount=100
上述兩條sql是互斥的,只可能有一條執行成功
這裏引申出一個問題,系統如何知道哪個成功哪個失敗?
數據庫數據更新後,我們可以從數據庫那裏獲取到受影響的行數即affect rows,那麼affect rows爲1業務執行成功,affect rows爲0則執行失敗

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章