高並發下接口的並發問題
阿新 • • 發佈:2017-05-23
導致 2-0 font urn 請求 turn 是否 快速 ont
事故
前些天上線的掃碼送會員活動。
場景:用戶登錄賬號之後,掃二維碼,送七天黃金會員,限制每個帳號只能領取一個
有惡意用戶刷接口,在高並發下越過限制。
原因
領取會員流程: 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
高並發下接口的並發問題