1. 程式人生 > >高併發下介面的併發問題

高併發下介面的併發問題

事故

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

原因

領取會員流程:
    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服務,除去極其敏感性資料的操作,其它資料的介面基本都沒有做資料一致性控制。

其實做了控制也不能解決這個問題。再來說這個問題,高併發下因為執行緒a已經執行完啟用卡的操作,使用者的會員已經建立權益。但這時候執行緒a還沒有執行到2-5,還沒更新使用者的領取卡卷的狀態,這時候,又有一個這個使用者的領取卡卷請求過來。2-1的check 操作並不能阻止這個請求,同樣的再次領取卡卷並且啟用,導致執行緒a在的執行在2-1到2-5之間都會有其它的執行緒越過檢查。

解決

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

                優點                      缺點

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


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

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

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

實現:

        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