第一步 思考面臨的問題和業務場景
秒殺系統面臨的問題: 短時間內并發非常高,如果按照秒殺的并發做相應的承載會造成大量資源的浪費。第二解決超賣的問題。
第二步 思考目前的處境和解決方案
因為秒殺系統屬于短時間內的高并發問題,我們不可能使用那么多的硬件資源去部署對應的承載。而且還有個問題,我們其實并賣不到那么多的商品,只是做一個商品促銷的噱頭吸引用戶到我們的平臺來,讓他們知道我們的平臺并記下我們的平臺。
那么也就是說其實大部分用戶買不到商品是正常行為,所以我們可以通過這個特性把大部分的用戶在服務的上游就過濾掉,而不是公平的競爭有限的商品。基于這個思想我們對我們的設計進行一些優化。
- 用戶在進行搶購前肯定是先打開頁面,這是第一步。那么我們為了避免服務器資源被短時間大量的請求壓垮,需要把頁面靜態化放到CDN上,減少服務器的壓力
- 用戶在到了秒殺的時間節點為了搶到商品肯定快速的點擊頁面,這個請求會使用到后臺的服務,我們為了減少用戶頻繁的請求,在前端代碼做一些控制,點擊按鈕后置灰不能多次的點擊請求后臺服務
- 用戶在點擊按鈕無反應的情況下,可能會重寫打開頁面再次發起請求,可以利用頁面緩存讓用戶在一段時間內打開的頁面是緩存頁面
- 用戶打開頁面時候,有些實時數據肯定是要最新的,要不然用戶發現是假數據或者是緩存在瀏覽器和CDN上的時候,用戶體驗很差。比如像剩余庫存這些數據,但是我們又不希望這些查詢請求落到數據庫,所以部分數據放在緩存中,減少數據庫的壓力(頁面緩存也可以但是需要緩存的時間短,不能太長
當我們做了上面的工作之后,還是會有大量的請求涌入到后臺服務。因為要解決超賣的問題,我們在買入操作的時候肯定是要給商品的數量加鎖。如果請求并發太高,會造成redis分布式鎖設置的失效時間失效,也會造成超賣的問題。
我們可以在購買商品,鎖庫存數量之前再過濾掉一部分請求。例如我們用不加鎖的緩存下商品數量,當涌入的人數超過一定數量的時候比如超過商品庫存的時候,或者商品庫存N倍的時候,后面的請求就不會再進入到后面的處理邏輯。
我們在一個用戶點擊購買時,就給用戶數量+1,超過一定數量就不讓后面的人進入。這個時候有個問題,就是我們的緩存并未加鎖,比如我商品庫存是100件,由于未加鎖,這個時候可能同時涌入300個用戶進入購買流程。其實這個問題很容易解決,我們在這300個人進入購買流程后再加分布式鎖,這個時候就能保證加鎖的redis不會處問題。
上面的思想基本上是基于把用戶進入到購買流程前盡量過濾掉,到真正購買的流程后其實沒有那么多的競爭壓力,對服務器的壓力也減小很多。上面我們用到了很多緩存策略,我們還需要考慮緩存穿透的問題,雪崩的問題等等。這些細節我們在后面的文章中再做討論,我們接著講后面的設計
第三 不怕一萬就怕萬一,我們對系統的可用性做到盡量的好
假如我們在秒殺系統中有一些關鍵的點沒考慮到,秒殺系統崩了。結果影響到其他正常的服務怎么辦?
我們的解決方案是隔離。把秒殺系統的服務和正常的服務隔離開。我們知道秒殺活動是需要商家參與的,當商家加入秒殺活動的時候,我們在秒殺服務建立和正常業務同樣的庫表結構,商家參與秒殺的商品數量等信息同步到秒殺系統的庫中,這樣可以做到完全的物理隔離,即時秒殺系統崩了,其他的業務也能正常運行。
以上是秒殺服務設計中比較重要的幾個點。具體的細節涉及到太多,我們不做深究。