1. 程式人生 > 其它 >高併發下如何設計秒殺系統?

高併發下如何設計秒殺系統?

高併發下如何設計秒殺系統?

設計一個秒殺系統,需要考慮這些問題:

如何解決這些問題呢?

  • 頁面靜態化
  • 按鈕至灰控制
  • 服務單一職責
  • 秒殺連結加鹽
  • 限流
  • 分散式鎖
  • MQ非同步處理
  • 限流&降級&熔斷

頁面靜態化

秒殺活動的頁面,大多數內容都是固定不變的,如商品名稱,商品圖片等等,可以對活動頁面做靜態化處理,減少訪問服務端的請求。秒殺使用者會分佈在全國各地,有的在上海,有的在深圳,地域相差很遠,網速也各不相同。為了讓使用者最快訪問到活動頁面,可以使用CDN(Content Delivery Network,內容分發網路)。CDN可以讓使用者就近獲取所需內容。

按鈕至灰控制

秒殺活動開始前,按鈕一般需要置灰的。只有時間到了,才能變得可以點選。這是防止,秒殺使用者在時間快到的前幾秒,瘋狂請求伺服器,然後秒殺時間點還沒到,伺服器就自己掛了。

服務單一職責

我們都知道微服務設計思想,也就是把各個功能模組拆分,功能那個類似的放一起,再用分散式的部署方式。

★如使用者登入相關的,就設計個使用者服務,訂單相關的就搞個訂單服務,再到禮物相關的就搞個禮物服務等等。那麼,秒殺相關的業務邏輯也可以放到一起,搞個秒殺服務,單獨給它搞個秒殺資料庫。”服務單一職責有個好處:如果秒殺沒抗住高併發的壓力,秒殺庫崩了,服務掛了,也不會影響到系統的其他服務。

秒殺連結加鹽

連結如果明文暴露的話,會有人獲取到請求Url,提前秒殺了。因此,需要給秒殺連結加鹽。可以把URL動態化,如通過MD5加密演算法加密隨機的字串去做url。

限流

一般有兩種方式限流:nginx限流和redis限流。

  • 為了防止某個使用者請求過於頻繁,我們可以對同一使用者限流
  • 為了防止黃牛模擬幾個使用者請求,我們可以對某個IP進行限流
  • 為了防止有人使用代理,每次請求都更換IP請求,我們可以對介面進行限流
  • 為了防止瞬時過大的流量壓垮系統,還可以使用阿里的Sentinel、Hystrix元件進行限流。

分散式鎖

可以使用redis分散式鎖解決超賣問題。使用Redis的SET EX PX NX + 校驗唯一隨機值,再刪除釋放鎖。

if(jedis.set(key_resource_id,uni_request_id,"NX","EX",100s)==1){//加鎖
try{
dosomething//業務處理
}catch(){
}
finally{
//判斷是不是當前執行緒加的鎖,是才釋放
if(uni_request_id.equals(jedis.get(key_resource_id))){
jedis.del(lockKey);//釋放鎖
}
}
}

在這裡,判斷是不是當前執行緒加的鎖和釋放鎖不是一個原子操作。如果呼叫jedis.del()釋放鎖的時候,可能這把鎖已經不屬於當前客戶端,會解除他人加的鎖。為了更嚴謹,一般也是用lua指令碼代替。lua指令碼如下:

ifredis.call('get',KEYS[1])==ARGV[1]then
returnredis.call('del',KEYS[1])
else
return0
end;

MQ非同步處理

如果瞬間流量特別大,可以使用訊息佇列削峰,非同步處理。使用者請求過來的時候,先放到訊息佇列,再拿出來消費。

限流&降級&熔斷

  • 限流,就是限制請求,防止過大的請求壓垮伺服器;
  • 降級,就是秒殺服務有問題了,就降級處理,不要影響別的服務;
  • 熔斷,服務有問題就熔斷,一般熔斷降級是一起出現。