什麼是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 ) else
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則執行失敗
巧用CAS解決資料併發一致性問題
緣起 在高併發的分布式環境下,對於資料的查詢與修改容易引發一致性問題,本文將分享一種非常簡單但有效的優化方法。一 業務場景 業務場景為,購買商品的過程要對餘額進行查詢與修改,大致的業務流程如下 1 從資料庫查詢使用者現有餘額 select money from t yue where uid uid...
sqoop 匯出時資料一致性問題
sqoop 底層執行的其實是map 任務,預設4個map 如果4個map中有兩個map失敗了,但是另外兩個是成功的。這個時候匯入進mysql中的資料是不正確的,重新再導一次全部任務都成功,這兩次的資料會不一致。為了保證匯出的時候資料是一致的sqoop有兩個引數配合使用 sqoop 匯出時並不會自動建...
kafka學習七 資料一致性問題
這樣乙個場景 leader寫了10條資料 follower1同步了8條 follower2同步了9條 假如leader掛了,follower1或follower2任意乙個當選為leader,則會出現資料不一致的情況。為了解決這個問題,kafka維護了leo和hw兩個資料 如果沒有hw這個概念,假如消...