Giao diện
Thực hành: Thiết kế Notification System
🎯 Mục tiêu
🎯 Sau bài thực hành này, bạn sẽ:
- Thiết kế notification đa kênh (push, email, SMS)
- Xây dựng priority queue và delivery tracking
- Giải quyết notification storm và rate limiting per user
Yêu cầu hệ thống
Functional: Gửi push/email/SMS, user chọn kênh, template, tracking, scheduled. Non-functional: 10M/day, OTP trong 5s, at-least-once, dễ thêm kênh mới.
Ước lượng
| Metric | Giá trị |
|---|---|
| Notifications/day | 10M (6M push + 3M email + 1M SMS) |
| Peak QPS | ~1,500 (burst) |
| SMS cost/day | ~10,000 USD |
Kiến trúc
Thiết kế chi tiết
Priority Levels
- P0 (Critical): OTP, security alerts → gửi ngay, bypass rate limit
- P1 (Normal): Social notifications → gửi trong 30s
- P2 (Low): Marketing → giờ thấp điểm, rate limit nghiêm ngặt
Delivery Tracking
State: CREATED → QUEUED → SENT → DELIVERED → READ. Retry tối đa 3 lần, backoff (1s, 4s, 16s).
🎯 Scenario Choice
Xử lý Notification Storm
Flash sale: 5M push + 100K OTP đồng thời. Storm làm chậm OTP delivery.
Giải pháp: (1) Tách queue — OTP → High Queue riêng, (2) Rate limit 5 notif/phút/user cho P1-P2, (3) Batch marketing 1000/batch qua FCM topic, (4) Backpressure tạm dừng P2 khi overload.
💡 Nhiều hệ thống sập vì OTP và marketing dùng chung queue. Tách queue theo priority là nguyên tắc cơ bản.
Trắc nghiệm
🧠 Quiz
Câu 1: Tại sao dùng message queue thay vì gọi API provider trực tiếp?
- [ ] A) Queue nhanh hơn
- [x] B) Decouple, retry khi lỗi, absorb spike không mất notification
- [ ] C) Provider không hỗ trợ gọi trực tiếp
- [ ] D) Queue chọn provider rẻ nhất
💡 Provider có thể timeout/down. Queue là buffer: lưu an toàn, retry tự động, không overwhelm khi spike.
🧠 Quiz
Câu 2: "At-least-once delivery" nghĩa là gì?
- [ ] A) Mỗi notification gửi đúng 1 lần
- [x] B) Có thể gửi trùng nhưng không mất — trùng ít nghiêm trọng hơn mất
- [ ] C) Gửi ít nhất 2 bản đảm bảo nhận
- [ ] D) Gửi qua ít nhất 1 kênh
💡 Exactly-once cực khó. At-least-once: không chắc đã gửi → gửi lại. Nhận trùng ít phiền hơn không nhận.
🧠 Quiz
Câu 3: Thiết kế nào giúp thêm kênh mới (Zalo) dễ nhất?
- [ ] A) Thêm if-else trong worker
- [ ] B) Worker riêng, hardcode logic
- [x] C) Channel Adapter — mỗi kênh implement chung interface, đăng ký vào Router
- [ ] D) Duplicate toàn bộ pipeline
💡 Open/Closed Principle: thêm kênh = implement interface + đăng ký, không sửa code existing.