CDN là gì? Câu trả lời ngắn: mạng máy chủ phân bố toàn cầu cache nội dung gần user. Bài này đi qua nguyên lý + cách config Cache-Control đúng để CDN làm việc thay anh.
Định nghĩa và lợi ích
CDN (Content Delivery Network) = origin server + nhiều edge POP (Point of Presence) trên thế giới. User Hà Nội request → router gần nhất serve từ Hong Kong/Singapore POP thay vì origin US. Latency giảm 5-10x cho asset cache hit.
Lợi ích chính:
- Tốc độ — TTFB < 50ms cho cache hit từ edge gần
- Giảm tải origin — 90% request không tới server gốc
- DDoS protection — hấp thụ flood ở edge
- HTTPS termination, HTTP/3, Brotli compression auto
- Geo routing, A/B testing ở edge
Luồng request qua CDN
User → DNS → CDN edge nearest → có cache?
├─ Yes → trả response ngay
└─ No → fetch origin → cache → trả user
Request thứ 2 từ user khác cùng region thường hit cache → nhanh hơn nhiều.
Cache-Control — header quan trọng nhất
Cache-Control: public, max-age=31536000, immutable
Cache-Control: public, max-age=60, stale-while-revalidate=86400
Cache-Control: private, no-cache
Cache-Control: no-store
| Directive | Nghĩa |
|---|---|
| public | CDN + browser cache |
| private | Chỉ browser, CDN không cache |
| max-age=N | Cache fresh trong N giây |
| immutable | Asset không bao giờ đổi (file versioned) |
| stale-while-revalidate=N | Sau hết hạn vẫn serve cache cũ + revalidate ngầm trong N giây |
| no-cache | Phải revalidate origin trước khi serve (vẫn cache) |
| no-store | Không cache đâu cả — dùng cho payment, secret |
Strategy theo loại asset
| Loại | Cache-Control | Lý do |
|---|---|---|
| JS/CSS versioned (app.abc.js) | public, max-age=31536000, immutable | URL khác mỗi deploy → cache 1 năm |
| Image static | public, max-age=2592000 | 30 ngày, có thể purge khi cần |
| HTML | public, max-age=0, s-maxage=60, swr=86400 | Browser luôn check, CDN cache 60s + swr |
| API GET (data ít đổi) | public, max-age=300, swr=60 | 5 phút fresh, swr 1 phút |
| API GET (per-user) | private, max-age=60 | Browser cache, CDN không |
| API mutation (POST) | no-store | Không cache POST |
| /me, /admin | private, no-cache | Cá nhân, revalidate mỗi lần |
stale-while-revalidate — bí mật của UX nhanh
swr cho phép serve cache cũ trong khi fetch mới ngầm. User không bao giờ chờ:
Cache-Control: max-age=60, stale-while-revalidate=86400
t=0: request 1 → fetch origin, cache 60s
t=30: request 2 → cache fresh, serve ngay
t=90: request 3 → cache stale (>60s), serve cũ + fetch ngầm + cache mới
t=91: request 4 → cache fresh (vừa update), serve ngay
User vẫn nhận response trong <50ms. Origin được hit nhẹ nhàng. Đây là pattern mạnh nhất cho HTML/API public.
Versioned filename + immutable
Webpack/Vite/Next.js auto bundle với hash: app.a3f8c2.js. Khi code đổi, hash đổi, URL đổi:
Build 1: /app.a3f8c2.js → cache 1 năm
Build 2: /app.b9e1d4.js → URL mới, cache 1 năm
HTML reference URL mới (không cache HTML lâu)
immutable directive bảo browser KHÔNG cần revalidate dù user nhấn F5. Tiết kiệm 1 round trip.
Purge cache
Versioned asset: không cần purge. HTML: cần purge khi deploy:
# Cloudflare API — purge URL cụ thể
curl -X POST \
"https://api.cloudflare.com/client/v4/zones/$ZONE_ID/purge_cache" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
--data '{"files":["https://alodev.vn/", "https://alodev.vn/blog"]}'
# Purge by tag (cần Enterprise hoặc Cloudflare Pro với cache tag)
--data '{"tags":["blog-list"]}'
# Purge everything (cẩn thận — origin bị spike)
--data '{"purge_everything":true}'
CI/CD chạy purge sau khi deploy. Đừng purge_everything trừ trường hợp bất khả kháng — origin bị flood request.
Vary header — pitfall thường gặp
Vary báo CDN cache riêng cho mỗi giá trị header:
Vary: Accept-Encoding ✓ Cache riêng gzip/br/identity
Vary: Accept-Language ✓ Cache riêng vi/en
Vary: User-Agent ⚠ Hàng nghìn user-agent → cache thracking
Vary: Authorization ✗ Mỗi user 1 cache → gần như tắt cache
Quy tắc: chỉ Vary những header có ít giá trị khác nhau.
Metric monitor
- Cache hit ratio — mục tiêu > 90% cho asset, > 70% cho HTML
- TTFB phân biệt edge vs origin — < 50ms edge, < 200ms origin
- Origin request rate — đột biến = cache invalidation accident
Kết luận
CDN là gì? Đó là một trong những đầu tư hạ tầng có ROI cao nhất. Setup đúng Cache-Control + versioned asset + swr, anh sẽ thấy TTFB từ vài trăm ms xuống vài chục ms — Web Vitals cải thiện rõ rệt. Tham khảo Web Vitals để đo impact thực tế lên SEO.