成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

并發扣款,如何保證數據的一致性?

開發 開發工具 前端
沈老師,我們有個業務,同一個用戶在并發“查詢,邏輯計算,扣款”的情況下,余額可能出現不一致,請問有什么優化方法么?

繼續解答星球水友提問。

沈老師,我們有個業務,同一個用戶在并發“查詢,邏輯計算,扣款”的情況下,余額可能出現不一致,請問有什么優化方法么?

扣款的業務場景是怎樣的?

用戶購買商品的過程中,要對余額進行查詢與修改,大致的業務流程如下:第一步,從數據庫查詢用戶現有余額:

  1. SELECT money FROM t_yue WHERE uid=$uid; 

不妨設查詢出來的$old_money=100元。

第二步,業務層實施業務邏輯計算,比如:

  • 先查詢購買商品的價格,例如是80元;
  • 再查詢產品是否有活動,以及活動折扣,例如是9折;
  • 比對余額是否足夠,足夠時才往下走;
  1. if($old_money> 80*0.9){ 
  2.     $new_money=$old_money-80*0.9=28 
  3. } else { 
  4.     return "Not enough minerals"; 

第三步,將數據庫中的余額進行修改。

  1. UPDATE t_yue SET money=$new_money WHERE uid=$uid; 

在并發量低的情況下,這個流程沒有任何問題,原有金額100元,購買了80元的九折商品(72元),剩余28元。

同一個用戶,并發扣款可能出現什么問題?

在分布式環境中,如果并發量很大,這種“查詢+修改”的業務有一定概率出現數據不一致。

極限情況下,可能出現這樣的異常流程:

步驟一,業務1和業務2并發查詢余額,是100元。

畫外音:這些并發查詢,是在不同的站點實例/服務實例上完成的,進程內互斥鎖肯定解決不了。

步驟二,業務1和業務2并發進行邏輯計算,算出各自業務的余額,假設業務1算出的余額是28元,業務2算出的余額是38元。

步驟三,業務1對數據庫中的余額先進行修改,設置成28元。業務2對數據庫中的余額后進行修改,設置成38元。

此時異常出現了,原有金額100元,業務1扣除了72元,業務2扣除了62元,最后剩余38元。

畫外音:假設業務1先寫回余額,業務2再寫回余額。

常見的解決方案?

對于此案例,同一個用戶,并發扣款時,有小概率會出現異常,可以對每一個用戶進行分布式鎖互斥,例如:在redis/zk里搶到一個key才能繼續操作,否則禁止操作。

這種悲觀鎖方案確實可行,但要引入額外的組件(redis/zk),并且會降低吞吐量。

對于小概率的不一致,有沒有樂觀鎖的方案呢?

對并發扣款進行進一步的分析發現:

(1) 業務1寫回時,舊余額100,這是一個初始狀態;新余額28,這是一個結束狀態。理論上只有在舊余額為100時,新余額才應該寫回成功。

而業務1并發寫回時,舊余額確實是100,理應寫回成功。

(2) 業務2寫回時,舊余額100,這是一個初始狀態;新余額28,這是一個結束狀態。理論上只有在舊余額為100時,新余額才應該寫回成功。

可實際上,這個時候數據庫中的金額已經變為28了,所以業務2的并發寫回,不應該成功。

如何低成本實施樂觀鎖?

在set寫回的時候,加上初始狀態的條件compare,只有初始狀態不變時,才允許set寫回成功,Compare And Set(CAS),是一種常見的降低讀寫鎖沖突,保證數據一致性的方法。

此時業務要怎么改?

使用CAS解決高并發時數據一致性問題,只需要在進行set操作時,compare初始值,如果初始值變換,不允許set成功。

具體到這個case,只需要將:

  1. UPDATE t_yue SET money=$new_money WHERE uid=$uid; 
  2. 升級為: 
  3. UPDATE t_yue SET money=$new_money WHERE uid=$uid AND money=$old_money; 

即可。

并發操作發生時:業務1執行:

  1. UPDATE t_yue SET money=28 WHERE uid=$uid AND money=100

業務2執行:

  1. UPDATE t_yue SET money=38 WHERE uid=$uid AND money=100

這兩個操作同時進行時,只可能有一個執行成功。

怎么判斷哪個并發執行成功,哪個并發執行失敗呢?

set操作,其實無所謂成功或者失敗,業務能通過affect rows來判斷:

  • 寫回成功的,affect rows為1
  • 寫回失敗的,affect rows為0

總結

高并發“查詢并修改”的場景,可以用CAS(Compare and Set)的方式解決數據一致性問題。對應到業務,即在set的時候,加上初始條件的比對即可。

優化不難,只改了半行SQL,但確實能解決問題。

但希望大家有收獲,思路比結論重要。

【本文為51CTO專欄作者“58沈劍”原創稿件,轉載請聯系原作者】

戳這里,看該作者更多好文

 

責任編輯:趙寧寧 來源: 架構師之路
相關推薦

2022-10-19 12:22:53

并發扣款一致性

2024-01-10 08:01:55

高并發場景悲觀鎖

2025-03-27 08:20:54

2024-12-26 15:01:29

2023-09-07 08:11:24

Redis管道機制

2021-03-04 06:49:53

RocketMQ事務

2020-08-05 08:46:10

NFS網絡文件系統

2023-05-26 07:34:50

RedisMySQL緩存

2024-08-20 16:13:52

2021-12-14 07:15:57

MySQLRedis數據

2022-03-29 10:39:10

緩存數據庫數據

2024-10-28 12:41:25

2024-10-16 09:53:07

2023-12-11 12:27:31

并發Zookeeper數據

2022-04-06 15:19:32

數據庫MySQL一致性

2024-01-22 08:52:00

AQS雙異步數據一致性

2019-09-08 22:45:48

并發扣款一致性冪等性

2024-07-04 12:36:50

2020-04-01 15:50:17

TiDBMySQL數據庫

2020-06-01 22:09:48

緩存緩存同步緩存誤用
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 欧美日韩中文字幕在线播放 | 国产精品99久久久久久久久久久久 | 日韩欧美中文字幕在线观看 | 日韩精品在线免费观看视频 | 亚洲国产精品一区二区久久 | 视频在线一区二区 | 亚洲国产精品人人爽夜夜爽 | 精品综合在线 | 色视频www在线播放国产人成 | 色伊人久久 | 久久久av| 国产精品久久久久久久久久免费看 | 观看av| 三a毛片 | 羞羞免费网站 | 国产精品s色 | 久久久.com| www.久久精品 | 成人3d动漫一区二区三区91 | av网站免费 | 国产精品久久久久国产a级 欧美日韩国产免费 | 波多野吉衣久久 | 精品欧美一区二区三区精品久久 | 中文在线一区 | 日韩欧美一区二区三区免费观看 | 精品一区二区视频 | 91视频大全 | 91精品国产综合久久久久久丝袜 | 国产xxxx搡xxxxx搡麻豆 | 日本精品久久 | av在线电影网 | 国产欧美一区二区三区免费 | 精品一区二区在线观看 | 成人h动漫精品一区二区器材 | 伦理片97| 久久机热| 日韩一级免费电影 | 国产一区 | 国内精品久久精品 | 成人小视频在线观看 | 久久久成人精品 |