設計一個秒殺系統
設計一個秒殺系統
1 設計的架構原則
1.1 4要1不要
-
儘量減少請求數量
js,css等額外請求要少 合併請求
-
儘量減少請求資料
-
儘量減少請求路徑
使用者發出去請求到返回資料過程中,經過的中間節點數要少
-
請求依賴要儘量少
秒殺系統中的商品資訊和使用者資訊是關鍵資訊,優惠券列表,成交列表弱依賴
-
不要有單點
避免服務狀態華
1.2 不同場景的架構

秒殺系統架構1
商品購買增加定時上架-- 秒殺開始,才能看到按鈕 單獨部署不和其他業務衝突 熱點資料放到快取 增加秒殺答題,方式秒殺器搶單

秒殺系統架構2
頁面動靜分離 在服務端對秒殺少商品進行快取 增加系統限流保護
2 動靜分離的可選方案
2.1 為什麼要考慮動靜分離
提高了單次的請求效率
減少了沒必要的請求
2.2 怎麼區分動靜資料
動靜資料主要區別就是看頁面中輸出的資料是否和URL,瀏覽者,時間,地域相關,以及是否含有Cookie等私密資料。
靜態資料不是磁碟上的HTML內容,而是資料中是否有個性化的資料。
2.3 怎麼對靜態資料快取
-
把靜態資料快取到離使用者最近的地方,例如 瀏覽器裡,CDN,或者服務端的Cache。
-
靜態化改造就是要直接快取HTTP連線,WEB代理伺服器根據請求URL,直接取出對應的HTTP響應頭和響應體直接返回。
-
在系統那個部分做靜態快取?WEB伺服器由於Java語言。
2.4 怎麼進行動靜分離
怎麼分離動態內容:
-
URL唯一話,每個商品的URL是獨一無二的。
-
分離瀏覽者相關的因素,包括是否登入,以及登入身份,這些相關因素可以單獨拆分出來,通過動態請求來獲取。
-
分離時間因素,服務端輸出的時間也應該通過動態請求獲取。
-
非同步化地域因素,請求頁面上與地域相關的因素做非同步式獲取。
-
去掉Cookie。快取的靜態資料中不包含有Cookie.
動態內容處理通用的兩種方案:
-
ESI方案,在Web代理伺服器上做動態內容請求,並將請求插入靜態頁面中,當用戶拿到頁面的時候已經是一個完整的頁面。
-
CSI方案,單獨發起一個非同步的JavaScript請求,以向服務端獲取動態內容。
2.5 架構方案
2.5.1 實體機單機部署
採用一致性Hash分組的方式來提升命中率,這裡將Cache分成若干組,是希望能達到命中率和訪問率的平衡。
優點:
- 沒有網路瓶頸,而且能使用大記憶體。
- 既能提升命中率,又能減少Gzip壓縮。
- 減少Cache失效壓力,因為採用定時失效方式。
缺點:
運維複雜度高
2.5.2 統一Cache層
將單機的Cache統一分離出來,形成一個單獨的Cache叢集。
優點:
- 可以減少多個應用接入Cache的成本,只需關注自己的Java系統就好。
- 易於維護。
- 共享記憶體,最大化利用記憶體。不同系統之間的記憶體可以動態切換。
缺點:
- Cache層內部交換網路成為瓶頸。
- 快取伺服器的網絡卡也會成為瓶頸。
- 機器少,風險比較大,掛掉一臺會影響很大一部分快取資料。
2.5.3 上CDN
3 二八原則:有針對的處理好系統的熱點資料
3.1 熱點?
熱點請求會佔用大量伺服器資源。
熱點操作:
熱點資料:靜態熱點資料(提前預測的熱點資料,大資料分析熱點商品,歷史成交記錄,使用者購物車)+動態熱點資料()
3.2 發現熱點資料
3.2.1 發現靜態熱點資料
- 賣家報名的方式,然後給賣家的商品打tag,資料進行預處理,然後快取資料。
- 分析買家訪問的商品等,然後統計出TOP N的商品。
3.2.2 發現動態熱點資料
系統內部秒級自動發現熱點商品
3.3 如何處理熱點資料
- 優化:快取熱點資料,用佇列進行儲存,採用LRU淘汰演算法。
- 限制:作為一種保護機制,把熱點請求限制在一個請求佇列裡面。防止熱點資料佔用太多資源。
- 隔離:熱點資料隔離出來,不要讓1%的請求影響到另外的99%。業務隔離+系統隔離+資料隔離。
4 流量削峰
秒殺這個場景來說,最終搶到商品的人數是固定的,所以100人和10000人發起請求的結果都是一樣的,併發度越高,無效請求越多。
4.1 為什麼削峰
伺服器能處理的資源是恆定的,所以為了服務穩定,我們延緩使用者請求的發出,以便減少和過濾掉一些無效的請求。
4.2 削峰的思路
- 排隊
把一步操作,變成二步操作,其中增加一步操作用來起到緩衝的作用。
- 利用訊息佇列,把請求緩衝起來,然後消費端非同步處理請求。
- 利用執行緒池加鎖等待。
- 先進先出記憶體排隊演算法的實現方式。
- 把請求序列化到檔案中,然後順序的讀檔案來恢復請求操作。
- 答題
一方面防止買家使用秒殺器在參加秒殺的時候作弊。一方面延緩請求,起到流量削峰的作用。

image
- 分層過濾

image
- 大部分資料和流量在使用者瀏覽器或者CDN上獲取,這一層攔截大部分資料的讀取。
- 前臺系統的資料,儘量得走cache,過濾一些無效請求。
- 後臺系統,做資料的二次校驗,對系統做好保護和限流。
- DB資料層,完成資料的強一致性校驗。
基本原則:
- 將動態請求的讀資料快取在Web端,過濾掉無效請求讀。
- 對讀資料不做強一致性校驗,減少因為一致性校驗產生瓶頸的問題。
- 對寫資料進行基於時間的合理分片,過濾掉過期的失效請求。
- 對寫請求做限流保護,將超出系統承載能力的請求過濾掉。
- 對寫資料進行強一致性校驗,只保留最後有效的資料。
5 提升系統性能
5.1 影響效能的因素
響應時間:
每秒請求數:(Query Per Second)
CPU的執行時間+執行緒數
執行緒數=2*cpu+1
執行緒數=[(執行緒等待時間+執行緒CPU時間)/執行緒CPU時間]*CPU數量
5.2 如何發現瓶頸
CPU診斷工具:Jprofiler+Yourkit工具+jstack定時地列印呼叫棧,
QPS達到極限時候,CPU的使用率是不是超過95%,如果沒有超過,那麼CPU還有提升的空間。
5.3 如何優化系統
- 減少編碼:
- 減少序列化
- Java極致優化 直接使用Servlet處理請求,直接輸出流資料。
- 併發讀優化 不變的資訊,快取系統記憶體裡面,變化的資訊,採用失效時間,失效之後拉取最新資料。
6 秒殺系統 減庫存設計
6.1 減庫存的幾種方式
- 下單減庫存 :有些人下單之後不會付款。
- 付款減庫存 :買家下單之後,不能發起付款。
- 預扣庫存 :買家下單之後,庫存為其保留一定時間,超過這個時間,庫存自動釋放。在買家付款之前,系統會校驗該訂單的庫存是否保留,如果沒有保留,則再次嘗試預扣,如果預扣失敗,則不允許繼續付款。