🎯 什麼情境該想到我
當你「要辦一場開賣瞬間就湧入數百倍平時流量的限量搶購活動,又不想為了這幾秒鐘去養一整年用不到的伺服器、更不想把正常業務一起拖垮」的時候。
⚙️ 怎麼用(步驟 / 公式)
第一步:先把四個技術挑戰列出來(以「一件商品、預計 1 萬人參加、最大並發請求數 10,000」為基準)
- 對現有網站業務造成衝擊——秒殺是營銷附加活動,時間短、並發訪問量大,如果和原有應用部署在一起,稍有不慎可能導致整個網站癱瘓。
- 高並發下的應用、資料庫負載——使用者在秒殺開始前會不停刷新瀏覽器頁面以確保不錯過,這些請求若走一般架構去訪問應用伺服器、連資料庫,會對應用伺服器和資料庫伺服器造成極大負載壓力。
- 突然增加的網路及伺服器頻寬——假設商品頁面大小 200K(主要是商品圖片),需要的網路和伺服器頻寬就是 200K × 10,000 = 2G,這是活動新增的、超過平時使用的頻寬。
- 直接下單——遊戲規則是到了秒殺時間才能下單,但下單頁面也只是一個普通的 URL,拿到這個 URL 就可以不等活動開始直接下單。
第二步:套四項應對策略(一項對一個挑戰)
- 秒殺系統獨立部署——不與正常網站交易業務共用伺服器。如果需要,還可以使用獨立的域名,使其與網站完全隔離;即使秒殺系統崩潰了,也不會對網站造成任何影響。
- 秒殺商品頁面靜態化——重新設計頁面,不用原本的商品詳情頁,把商品描述、商品參數、成交記錄、使用者評價全部寫入一個靜態頁面。使用者請求不需經過應用伺服器的業務邏輯處理,也不需訪問資料庫,所以秒殺商品服務不需要部署動態的 Web 伺服器和資料庫伺服器。
- 租借秒殺活動網路頻寬——新增的頻寬必須和運營商重新購買或租借;並把秒殺商品頁面快取在 CDN,同樣要和 CDN 服務商臨時租借新增的出口頻寬。
- 動態生成隨機下單頁面 URL——在下單頁面 URL 加入由伺服器端生成的隨機數作為參數,秒殺開始的時候才能得到,讓即使是秒殺系統的開發者也無法在開始前訪問下單頁面 URL。
第三步:頁面與表單一律砍到最簡
- 商品頁面盡可能簡單(只有商品圖片、商品資訊、購買按鈕、商品描述)——參與者關心的是「怎麼快速刷新頁面、開始時搶先進入下單頁」,而不是商品詳情等體驗細節。購買按鈕只有在活動開始時才變亮,在此之前及商品賣出後都是灰色不可點擊。
- 下單表單盡可能簡單:購買數量只能是一個且不可修改;送貨地址與付款方式都用使用者預設設定,沒有預設也可以不填,允許等訂單提交後再修改;只有第一個提交的訂單發送給網站的訂單子系統,其餘使用者提交後只能看到秒殺結束頁面。
第四步:解掉兩個額外問題
- 問題一:怎麼控制購買按鈕的點亮?
頁面已被設計成靜態頁、快取在 CDN/反向代理伺服器甚至使用者瀏覽器上,秒殺開始時使用者刷新頁面,請求根本不會到達應用伺服器,所以不能靠伺服器端構造回應頁面來控制。
解法是用 JavaScript 腳本控制:在秒殺商品靜態頁面中加入一個 JavaScript 檔案引用,該檔案中放入「秒殺是否開始的標誌」與「下單頁面 URL 的隨機數參數」;秒殺開始的時候生成一個新的 JavaScript 檔案推送到 JavaScript 伺服器並被使用者瀏覽器載入,控制商品頁面的展示。
關鍵條件:這個 JavaScript 檔案使用隨機版本號,並且不被瀏覽器、CDN 和反向代理伺服器快取;因為檔案非常小,即使每次刷新都去訪問它,也不會對伺服器集群和網路頻寬造成太大壓力。 - 問題二:怎麼只讓第一個提交的訂單進到訂單子系統?
為了減輕下單頁面伺服器的負載壓力,控制進入下單頁面的入口,只有少數使用者能進入下單頁面,其他人直接進入秒殺結束頁面。
具體門檻:假設下單伺服器集群有 10 台伺服器,每台伺服器只接受最多 10 個下單請求。下單流程為——活動開始 → 點擊購買按鈕 → 請求發送至下單伺服器 → 下單伺服器檢查本機處理下單請求數目(已超過 10 → 顯示秒殺活動已結束頁面;未超過 10 → 放行)→ 使用者填寫訂單、點擊提交 → 檢查全域已提交訂單數目(已超過秒殺商品總數 → 顯示秒殺活動已結束頁面;未超過 → 提交到訂單子系統)。
第五步:照這份清單佈署(本書給出的整體架構)
- 網站機房秒殺伺服器集群:
- 秒殺商品伺服器集群:10 台 Apache 伺服器
- JavaScript 伺服器集群:5 台 Lighttpd 伺服器
- 定時任務伺服器:1 台 Linux 伺服器(秒殺開始前生成新的 JavaScript 檔案並推送到 JavaScript 伺服器)
- 全域計數器伺服器:1 台 Memcached 伺服器
- 下單伺服器集群:10 台 Jetty 伺服器
- 外圍:使用者瀏覽器 → CDN 伺服器(承接刷新秒殺商品頁面,每次刷新都會載入一次 JavaScript 檔案);下單伺服器把通過檢查的訂單提交到網站機房業務伺服器集群的訂單處理子系統。
🧪 我實際套用的紀錄
- (待填)
⚠️ 注意 / 什麼時候不適用
- 不要追求完美的公平。秒殺是對網站架構的極大考驗,在難以預計和控制的高並發訪問衝擊下稍有不慎,系統就會「被使用者秒殺」導致整個系統宕機、活動失敗、構成重大事故。因此在遵循秒殺活動遊戲規則的基礎上,為了保證系統的安全,保持適度的公平公正即可——上面「每台伺服器只收 10 個請求」這種做法本來就會篩掉絕大多數使用者,這是刻意的取捨。
- 故障也不准顯示錯誤頁。書中明講:即使系統出了故障,也不應該給使用者顯示出錯頁面,而是顯示秒殺活動結束頁面,避免不必要的困擾。
- 這套架構是為秒殺而設計的專用系統,不同於一般網購行為,不能拿正常的網站業務流程來套,也不能和正常的網站交易業務共用伺服器。
- 除了本卡列的架構設計,書中第 10 章提到的許多效能最佳化設計都可以用於秒殺系統的最佳化。
🔗 相關工具
- 工具-容量估算 —— 本卡的起點就是一次容量估算:1 萬人 → 10,000 並發 → 200K × 10,000 = 2G 頻寬,數字算出來才知道要租多少頻寬、佈幾台機器
- 工具-快取與資源優化 —— 頁面靜態化 + CDN 快取是秒殺的主力手段,而「JavaScript 檔案帶隨機版本號且不被快取」正是快取失效控制的典型應用
- 工具-透明多級分流 —— 秒殺把絕大多數請求擋在瀏覽器、CDN、反向代理這幾層,根本不讓它們到達應用伺服器與資料庫
- 工具-限流器設計 —— 「每台下單伺服器只接受最多 10 個請求」+「全域計數器檢查商品總數」就是一組本機加全域的兩層限流
- 工具-網站高可用與伸縮性設計 —— 秒殺系統獨立部署、獨立域名、與網站完全隔離,讓秒殺系統即使崩潰也不影響網站
- 大型網站技術架構 —— 來源書