搶購系統
在一次搶購活動中,凌晨 00:00 一到,數十萬使用者同時按下「立即購買」。那一刻,不只是商品在被搶,你的伺服器資源也在被搶。CPU 飆滿、DB Connection Pool 撐爆、API Timeout、Error Rate 升高——這些都是典型的「高併發瞬間爆炸」現象。
如果把系統比喻成一條「城市水管」,平時水流穩定沒事,但一旦所有人同時打開水龍頭,就算是最大水管也會瞬間乾涸。這就是搶購系統
關鍵在於,系統能不能在高壓下「不垮」
「可控」與「分流」,我們希望把瞬間湧入的流量像導水渠一樣分散出去,讓「靜態內容走 CDN」、「個人化內容走限流」、「非關鍵功能可暫時關閉」。每個機制看似只是多加一層,但其實是為了在流量暴潮時,給系統一個喘息的空間

使用者打 API → 不是直接進 WebAPI 主機 → 而是先進 CloudFront,再由 CloudFront 轉給 Origin(真正伺服器)
- 加速 API 回應(雖然 API 通常是動態,但部分回應仍可快取)
- 防止主機直接暴露(安全)
- 可控流量與限流
- 統一流量進出口(方便監控)
現在 Referrer 發出的 API 請求會先打到 CDN,而 CDN(例如 d9c…cloudfront.net)會先判斷快取裡有資料則直接回應,否則轉發給 Origin
- ✅ Origin 流量下降
- ✅ 回應速度變快(CDN 靠近使用者)
- ✅ 減少跨區延遲與成本

操作庫存、下單也能「先走 CloudFront」嗎?
可以走 CloudFront,但概念要換:走它不是為了快取,而是為了入口治理,如果把「走 CloudFront」等同於「會被快取」,那下單/扣庫存一定讓人怕出事,但其實完全可以設定所有 POST/PUT/PATCH/DELETE 都不快取、只轉發,同時享受 CDN 當入口的好處(WAF、DDoS 防護、rate limit、統一網域、監控)

🔹 Resource ID
CloudFront 的唯一識別碼(例如 E10FW360Y04PQ3)。這是 AWS 為每個 CloudFront Distribution 分配的「ID」。在 AWS Console → CloudFront 裡面會看到這個欄位。這一欄是系統層級的「代號」,不是域名,這個 ID 的用途是讓 AWS 能精準指到「你這一組 CloudFront 設定」去套用規則與查紀錄,它不參與你的 API HTTP 傳輸內容
- 建立一個 CloudFront Distribution(包含:Origins、Behaviors、Cache policy、WAF、憑證、Logging…)
- AWS 給它一個唯一 Distribution ID(你說的 E10FW360Y04PQ3 這類)
- 使用者發出 API request 時,request 會用你的網域 / CloudFront domain name 進來
- AWS 在 CloudFront 的邊緣節點收到 request 後,內部會把這個 request 路由到對應的 Distribution 設定
- 套用該 Distribution 的行為(轉發規則、快取鍵、TTL、是否允許方法、是否擋掉、要不要記錄 log…)
- 產生結果(hit cache 就回,miss 就打 origin),並把 log/metrics 都歸到這個 Distribution
對外是 https://api.example.com/orders(CNAME 指到 CloudFront),而 CloudFront Distribution ID = E10FW360Y04PQ3、Origin = alb-webapi-prod-123.ap-northeast-1.elb.amazonaws.com
Client 發 request
1 | POST /orders HTTP/1.1 |
實際發生時,E10FW360Y04PQ3 做了什麼?
✅ CloudFront 收到 request 後,用這個 ID 找到「要套用哪一套設定」
- /orders 對應哪個 behavior
- POST 是否允許
- Cache policy:POST 不快取
- Origin request policy:Authorization 是否要轉發
- 是否有 WAF / rate limit 規則
- Access log 要寫到哪個 bucket
✅ 所有 log/監控都會標記在這個 Distribution 底下
- CloudFront access logs 裡會有 distribution 的欄位(用來識別是哪個 distribution 的流量)
- CloudWatch 指標也是以 distribution 為維度去看

🔹 CNAME
是 CloudFront Distribution 綁定的「自訂網域」例如
1 | webapi.91mai.com |
意思是使用者實際打的 API 網域。CloudFront 會根據這個 CNAME 接住請求。CloudFront 原始域名長得像 d9cwh2l3co8h5.cloudfront.net,但我們會「綁一個自家網域」在前面(CNAME),讓 API 網域更一致、可控
CloudFront 的 xxxxxxxxxxxx.cloudfront.net
建立一個 CloudFront Distribution,AWS 會自動給一個 Distribution domain name:d123abc456def8.cloudfront.net,我們有兩種使用方式,第一個是直接用這個 domain name 呼叫:https://d123abc456def8.cloudfront.net/api/...,或者是用自己的網域(比較正常的做法):api.example.com,如果使用自己的網域,就在 DNS 做
api.example.com CNAME → d123abc456def8.cloudfront.net
之後使用者打 api.example.com,DNS 解析會導到 CloudFront 的預設入口網域,再進到你的 distribution 規則
🔹 原 Origin 設定
表示這個 CloudFront 背後實際對應的「原始伺服器」(Origin)
通常會是:
- WebAPI 主機(自有 API)
- AWS Load Balancer(ELB)
- S3 或 其他 CDN 節點
1 | 使用者/App |

🔹 Hit Rate 較低的 API 分析
Hit Rate 較低常是 Querystring 的影響導致例如
- /webapi/VIPMember/GetVipMemberCustomLinkSettings Hit Rate 低原因: 帶語系
- /WebAPI/Shop/GetShopAvailLanguages Hit Rate 低原因: 帶 APP 版本
| month_date | host_header | uri | query_string | result_type | requests |
|---|---|---|---|---|---|
| 2020-09-28 | d38tzu0atxk400.d38tzu0atxk400.cloudfront.net.net | /WebAPI/Shop/GetShopAvailLanguages | appVer=2.52.0&shopId=2131&lang=zh-TW | Hit | 15252 |

個人化資料 跟「某個使用者本人」有關、不能公開快取在 CDN 的資料(例:我的收藏、購物車、推薦清單、訂單紀錄、個人優惠)。因為這些請求不能像圖片/CSS 一樣丟給 CDN,通常都會直打你的 Origin(應用程式 + 資料庫)。一旦有人(或機器人)短時間狂打「個人化 API」,你的 DB、應用程式就會被拖垮。
而個人化資料限流(Rate Limiting) 的本質就是在入口處幫每個人裝一個「流量節流閥」,同一個使用者、同一個 API,在一段時間內最多只能打幾次,超過就回 429 Too Many Requests,或延遲、排隊。目標是保護核心系統、維持穩定、公平使用、降低成本、避免資料爭用。因為個人化不能靠 CDN 分擔,所以一定要靠限流 + 近源快取守住 Origin!

在請求一進來時,先確認「這個人是匿名訪客還是已登入的會員」,然後走不同的資料路線(Routing)與處理策略
🔹 未登入(Anonymous)
多半只需要公開內容(商品清單、首頁、分類、熱門榜…)。可以大膽用 CDN 快取、Server 端 Output Cache、Aggressive Cache-Control,走最便宜最快的路。
🔹 已登入(Authenticated)
需要個人化內容(購物車、收藏、我的優惠、個人推薦)。不能公開快取,必須進應用程式與資料庫,走安全但較貴的路,搭配細緻的 Rate Limiting、微快取(Redis / Memory)、權限驗證(Authorization)。把「可廣播的」與「只屬於你的」請求分開。速度更快(匿名端)、資料更安全(會員端)

在系統過載、異常、或流量高峰時,可以「局部關閉一些非關鍵功能」 來保護整體穩定,當系統快撐不住時,先讓使用者「買得到、看得到」比「紀錄得漂亮、推薦很準」重要,先把不影響成交的呼叫停掉,主流程才不會一起死
我們可以先把功能分成兩類
- 關鍵路徑:商品頁資料、價格、庫存、下單、付款
- 非關鍵:PageView 上報、收藏數量、購物車 badge 數量、推薦曝光紀錄
每個非關鍵功能都包一層「開關」,他可以是 config / feature flag / 熔斷器狀態,而服務端或前端發起請求前先判斷開關,關掉就直接略過,不打 API,而觸發斷路的條件是延遲飆高、錯誤率上升、依賴服務(DB/推薦/事件流)異常、流量尖峰,當需要時恢復策略是一段時間後半開(只放一小部分流量)觀察 OK 再全開

🔹 PageView
商品頁在載入時,會觸發的「行為追蹤、瀏覽記錄上報」功能,每次有人開「商品頁」,系統會去呼叫一個「記錄瀏覽事件」的 API,但這個 API 並不是用來顯示畫面的「主要功能」,它只是輔助性的「行為紀錄」或「推薦系統的資料來源」。
🔹 其他功能
例如關閉收藏清單數量、關閉購物車數量




