k碼特權(quán)中關(guān)于 Redis & MySQL DB 樂觀鎖應(yīng)用

1.【背景】


斐訊路由App 需要新增k碼特權(quán)模塊沐绒。

2.【需求】

1.已通過k碼激活狀態(tài)驗(yàn)證的用戶可免費(fèi)領(lǐng)取k碼特權(quán)商品
2.每個(gè)用戶每天只能領(lǐng)取一張k碼特權(quán)獎品

3.【應(yīng)用場景及難點(diǎn)分析】

1.接口數(shù)據(jù)安全性要求:

1.1 當(dāng)某k碼特權(quán)商品數(shù)據(jù)量為1,且高并發(fā)情況下储耐,
1.2 如何防止超賣(即多個(gè)用戶都搶到了剩余的一個(gè)商品)

2.接口性能要求:

斐訊路由App 現(xiàn)用戶量為300w+,日活4w+郑气,2/8原則分析(**指80%的業(yè)務(wù)量在20%的時(shí)間里完成**)怠堪。
經(jīng)驗(yàn)可知用戶使用斐訊路由App 的持續(xù)時(shí)間為12小時(shí),
所以2/8分析后雷逆,80%的日活在20%的時(shí)間內(nèi)完成弦讽。
即32000人免費(fèi)領(lǐng)取k碼特權(quán)商品要在2.4小時(shí)內(nèi)完成,
換算成每秒 完成請求數(shù)即 QPS = 3.7/s 关面。
即每個(gè)接口響應(yīng)請求時(shí)間至少要在 270ms 以內(nèi)坦袍。才算是高性能十厢。

4.問題分析:

1.讀多寫少

每個(gè)用戶每日只能領(lǐng)取一個(gè)k碼特權(quán)商品。即1個(gè)用戶加入請求免費(fèi)領(lǐng)取k碼特權(quán)接口多次捂齐,在k碼商品庫存量充足的情況下蛮放,只能領(lǐng)取到1個(gè)商品,其余請求都應(yīng)該返回“對不起奠宜,您今日已領(lǐng)取k碼特權(quán)商品”包颁。從這個(gè)方面來定義,其屬于讀多寫少的問題压真。

2.并發(fā)量低

以斐訊路由現(xiàn)在日活情況為4w+的數(shù)據(jù)量來估算娩嚼、接口并發(fā)能力 QPS = 3.7/s ,
屬于低并發(fā)滴肿,但在k碼特權(quán)模塊優(yōu)化程度達(dá)到一定量時(shí)岳悟,并發(fā)量是否會上升有待考察。
但總體來說屬于并發(fā)量不高的場景泼差。

也就是說k碼特權(quán)問題經(jīng)過模型抽象贵少,已經(jīng)變成了讀多寫少、并發(fā)量不大堆缘,但要保證性能滔灶,和數(shù)據(jù)安全性一致性的問題。

對于這類問題吼肥,樂觀鎖思想可以作為解決這類問題的指導(dǎo)思想录平。

5.樂觀鎖思想

網(wǎng)上文章對樂觀鎖理解的誤區(qū):


1.樂觀鎖是一種思想,并不是一種具體的技術(shù)實(shí)現(xiàn)缀皱。
2.樂觀鎖類似于CAS無鎖編程技術(shù)(其實(shí)也加鎖斗这,只不過在cpu層面)

即當(dāng)多個(gè)線程同時(shí)并發(fā)更新統(tǒng)一個(gè)變量,
采用先select再update的方式啤斗,select出當(dāng)前變量a的副本值b涝影,然后用新值c去更新,
更新時(shí)需要拿select 出來的變量值a的副本值b與當(dāng)前非副本變量a的值做對比争占,
若暫存副本值b與當(dāng)前變量a非副本值相同燃逻,則正常更新,
如果不同臂痕,則認(rèn)為在當(dāng)前線程更新之前已經(jīng)有一個(gè)值將a變量更新伯襟,
則更新失敗,在并發(fā)情況不大的情況下握童,
采用循環(huán)的方式去更新姆怪,總能更新成功,且循環(huán)更新次數(shù)不會太多。因此CAS也叫自旋鎖稽揭。

6.k碼特權(quán)-免費(fèi)領(lǐng)取解決方案


1.用戶每日成功領(lǐng)取k碼特權(quán)商品次數(shù)的限制

采用redis 數(shù)據(jù)結(jié)構(gòu) String俺附,記錄用戶每日免費(fèi)領(lǐng)取成功次數(shù)。并且可以輕松使用redis 緩存的過期 (expire) 機(jī)制做每日領(lǐng)次數(shù)的控制)溪掀,用戶每日成功領(lǐng)取k碼特權(quán)的次數(shù)次日凌晨清空事镣。
為什么不使用數(shù)據(jù)庫來進(jìn)行用戶成功領(lǐng)取k碼特權(quán)商品次數(shù)的控制。當(dāng)然建立好索引此問題也可以完美解決揪胃。
使用redis進(jìn)行用戶成功領(lǐng)取k碼特權(quán)商品次數(shù)的控制原因有兩個(gè):

1.因?yàn)閞edis 純粹的查詢快璃哟,減輕數(shù)據(jù)庫壓力!不用每次都通過數(shù)據(jù)庫二次索引喊递,從磁盤找到目標(biāo)記錄并讀入到內(nèi)存随闪。**
2.線上配置的redis使用量10%都不到,為了更好的利用硬件資源骚勘。**

2.用戶每日成功領(lǐng)取k碼特權(quán)次數(shù)的并發(fā)更改

從接口安全性考慮铐伴,若有用戶惡意領(lǐng)取、那么有可能產(chǎn)生一個(gè)用戶在一天之內(nèi)領(lǐng)取了多個(gè)k碼特權(quán)獎品俏讹,這個(gè)是業(yè)務(wù)需求所不允許的盛杰。
這里我們使用到了redis 提供的 事務(wù)(multi)與watch(樂觀鎖實(shí)現(xiàn)) 機(jī)制來控制 用戶每日成功領(lǐng)取k碼特權(quán)次數(shù)的并發(fā)更改。

watch機(jī)制:對鍵值進(jìn)行監(jiān)控藐石,當(dāng)被其他客戶端改變時(shí),
當(dāng)前的客戶端的所有操作將會失敗定拟,拋出錯(cuò)誤信息于微。

3.用戶并發(fā)更新同一k碼特權(quán)商品庫存、同一商品的具體某個(gè)item

上述問題青自,屬于對竟態(tài)資源的并發(fā)修改株依,在接口請求并發(fā)量不大、且讀多寫少的情況下延窜,采用數(shù)據(jù)庫樂觀鎖來解決問題恋腕。

數(shù)據(jù)庫樂觀鎖實(shí)現(xiàn)方式:
在競態(tài)資源(商品)記錄上添加一列,update_version逆瑞,表示更新次數(shù)荠藤。
數(shù)據(jù)庫樂觀鎖實(shí)現(xiàn)方式偽代碼:
for(;;){
    //獲取某k碼商品庫存,更新版本號 sql
    $getRewardStcokSql = 'select reward_stock,reward_update_version from fx_platform_reward_amount where reward_type_id = {$reward_type_id}';
    $getReardStockResult = $model->query($getRewardStcokSql);
    if(!$getReardStockResult ){
        die;
    } 
    $reward_stock = getReardStockResult['reward_stock'];
    $reward_update_version = getReardStockResult['reward_update_version'];
    //如果庫存量>0
    if($reward_stock>0){
      //更新k碼商品庫存获高,版本號需要進(jìn)行對比哈肖,其實(shí)本質(zhì)上是不再使用數(shù)據(jù)庫提供的排它鎖,而將排他控制的職責(zé)交給選擇某條需要更新記錄的過濾條件念秧。
        $updateRewardStockSql = 'update fx_platform_reward_amount set reward_stock = reward_stock-1 and reward_update_version = reward_update_version + 1 where reward_type_id = {$reward_type_id} reward_update_version = {$reward_update_version} ';
        $updateRewardStockResult = $model->excute($updateRewardStockSql);
    }
    //并發(fā)更新失敗淤井,表示在此用戶更新商品庫存之前已經(jīng)有用戶更新成功,需要重新嘗試更新。
    if(!$updateRewardStockResult){
        continue;
    }
}

7.測試結(jié)果


7.1 并發(fā)測試币狠,數(shù)據(jù)能保持一致性
7.2 用戶免費(fèi)領(lǐng)取k碼特權(quán)商品響應(yīng)時(shí)間均值為 110ms 左右游两,
      用戶當(dāng)日已領(lǐng)取過k碼特權(quán)獎品的接口響應(yīng)時(shí)間40-55ms左右。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末漩绵,一起剝皮案震驚了整個(gè)濱河市贱案,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌渐行,老刑警劉巖轰坊,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異祟印,居然都是意外死亡肴沫,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進(jìn)店門蕴忆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來颤芬,“玉大人,你說我怎么就攤上這事套鹅≌掘穑” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵卓鹿,是天一觀的道長菱魔。 經(jīng)常有香客問我,道長吟孙,這世上最難降的妖魔是什么澜倦? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮杰妓,結(jié)果婚禮上藻治,老公的妹妹穿的比我還像新娘。我一直安慰自己巷挥,他們只是感情好桩卵,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著倍宾,像睡著了一般雏节。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上高职,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天矾屯,我揣著相機(jī)與錄音,去河邊找鬼初厚。 笑死件蚕,一個(gè)胖子當(dāng)著我的面吹牛孙技,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播排作,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼牵啦,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了妄痪?” 一聲冷哼從身側(cè)響起哈雏,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎衫生,沒想到半個(gè)月后裳瘪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡罪针,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年彭羹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泪酱。...
    茶點(diǎn)故事閱讀 38,018評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡派殷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出墓阀,到底是詐尸還是另有隱情毡惜,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布斯撮,位于F島的核電站经伙,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏勿锅。R本人自食惡果不足惜帕膜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望粱甫。 院中可真熱鬧,春花似錦作瞄、人聲如沸茶宵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽乌庶。三九已至,卻和暖如春契耿,著一層夾襖步出監(jiān)牢的瞬間瞒大,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工搪桂, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留透敌,地道東北人盯滚。 一個(gè)月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像酗电,于是被迫代替她去往敵國和親昧捷。 傳聞我的和親對象是個(gè)殘疾皇子霉涨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容