高併發下接口的併發問題

事故

前些天上線的掃碼送會員活動。
場景:用戶登陸帳號以後,掃二維碼,送七天黃金會員,限制每一個賬號只能領取一個
有惡意用戶刷接口,在高併發下越過限制。redis

緣由



這個流程在通常環境下是沒有問題的,在高併發下就不行了。領取會員流程: 1.後端先生成卡卷,將卡號放到消息隊列中 2.用戶掃碼請求領取會員接口 2-1).先檢查用戶是否已經領取過該活動會員 2-2).領取過return 「該賬號已領取」的標示 2-3).沒領取從消息隊列中拿取一張卡號 2-4).激活卡 2-5).更新用戶本次活動爲已經激活
2-1)        2-2)        2-3)       2-4)      2-5)

    線程a                                                   -->

    線程b                                      -->

    線程c                                 -->

高併發下模擬幾個線程同時請求後端

如今的rpc服務,除去極其敏感性數據的操做,其它數據的接口基本都沒有作數據一致性控制。api

其實作了控制也不能解決這個問題。再來講這個問題,高併發下由於線程a已經執行完激活卡的操做,用戶的會員已經創建權益。但這時候線程a尚未執行到2-5,還沒更新用戶的領取卡卷的狀態,這時候,又有一個這個用戶的領取卡卷請求過來。2-1的check 操做並不能阻止這個請求,一樣的再次領取卡卷而且激活,致使線程a在的執行在2-1到2-5之間都會有其它的線程越過檢查。併發

解決

解決這種併發問題無非是兩種,悲觀鎖和樂觀鎖。
悲觀鎖阻塞,樂觀鎖快速響應失敗。高併發

優勢                      缺點

悲觀鎖     能夠響應重複請求,冪等         高併發下請求堆積


樂觀鎖     高併發下沒有大量線程阻塞        不可重複響應,不冪等

考慮併發量比較大,採用的樂觀鎖實現。對流程進行加鎖。.net

2種實現方式:redis和MySQL,考慮下在不修改原表的狀況下,使用redis的SETNX的api線程

實現:code

2-0).活動-賬號造成key,SETNX(key)成功返回1,失敗返回0
              只有返回1,才能進行後續流程,將併發控制交給redis,redis是線程模型沒有併發問題
        2-1).先檢查用戶是否已經領取過該活動會員
        2-2).領取過return 「該賬號已領取」的標示  
        2-3).沒領取從消息隊列中拿取一張卡號
        2-4).激活卡
        2-5).更新用戶本次活動爲已經激活
        2-6).將刪除活動-賬號造成的key


            2-0)    2-1)   2-2)     2-3)  2-4)  2-5)   2-6)

    線程a   ->1                                         

    線程b   ->0                                   
             <- 
    線程c  ->0                            
             <-

    只有線程a已經執行過2-6,才能線程b進入流程,可是這時候用戶已經爲領取過卡卷狀態           
    線程a                                                 ->

    線程b  ->1 用戶卡卷已經更新過

    線程c  ->0
相關文章
相關標籤/搜索