Câu hỏi microservices vs monolith được đặt ra ở mọi dự án mới. Bài này không hype — đi qua trade-off thực tế từ team 2 người đến 100+ engineer, dựa trên kinh nghiệm Amazon, Stack Overflow, Shopify công khai.
Định nghĩa lại — đừng nhầm "monolith" với "spaghetti"
Mọi người hay nhầm:
- Monolith: 1 codebase, 1 deploy unit, 1 database. KHÔNG phải = spaghetti code.
- Modular monolith: monolith với module boundary rõ, schema DB riêng từng module, API contract nội bộ.
- Microservices: nhiều service độc lập, mỗi service có codebase + deploy + DB riêng, gọi nhau qua API.
- Distributed monolith: tệ nhất — nhiều service nhưng coupled chặt, deploy phải cùng nhau, fail cascading.
Khi nào monolith thắng?
Monolith mạnh khi:
- Team < 20 engineer
- Domain chưa rõ ràng — boundary còn đang khám phá
- Cần ship nhanh, đơn giản hoá vận hành
- Transaction across nhiều module là yêu cầu thật
- Latency-sensitive (mỗi network hop tốn 1-5ms)
Stack Overflow chạy monolith với .NET phục vụ >1B request/tháng. Shopify từng là Rails monolith trước khi tách dần. Basecamp 30+ năm vẫn monolith.
Khi nào microservices thắng?
- Team độc lập (team A không muốn block team B khi deploy)
- Scale yêu cầu khác nhau (auth service 10k QPS, analytics 100 QPS)
- Tech stack khác nhau (legacy Java + new Go cho real-time)
- Fault isolation (1 service crash không kéo cả hệ thống)
- Compliance (PCI scope nhỏ → tách payment service)
Netflix >700 microservices để 4000+ engineer làm việc song song. Uber tách hàng trăm service vì team địa lý phân tán.
Operational overhead — phần ai cũng underestimate
Microservices không miễn phí:
| Khía cạnh | Monolith | Microservices |
|---|---|---|
| Deploy | 1 pipeline | 50 pipeline, deploy ordering |
| Logging | 1 file/service | Aggregate log 50 service (Loki/ELK) |
| Tracing | Stack trace local | Distributed tracing (Jaeger, Tempo) |
| Local dev | npm run dev | Docker Compose 20 container |
| Bug debug | Đặt breakpoint | Trace qua 5 service, log correlation ID |
| Schema change | 1 migration | Backwards compat 2-3 version |
| Data join | SQL JOIN | Data composition ở app layer |
| Cost | 1 server lớn | 50 container nhỏ + service mesh + monitoring stack |
Một team 5 người chia 10 service sẽ tốn 30% thời gian cho operational thay vì feature.
Conway's Law: cấu trúc team quyết định kiến trúc
"Organizations design systems that mirror their communication structure" — Melvin Conway, 1968
Nếu anh tách service không khớp boundary team, anh sẽ có distributed monolith — 2 team cùng cần deploy 1 service. Heuristic:
- 1 service = 1 team chịu trách nhiệm 24/7
- 1 team chịu được 1-3 service liên quan chặt
- 2 team không bao giờ share code production của 1 service
Tách service khi nào và thế nào?
Quy tắc: tách khi PAIN cụ thể xuất hiện, không phải vì hype. Pain thường gặp:
- Deploy conflict: 2 team cùng deploy 5 lần/ngày, conflict liên tục → tách.
- Scale khác nhau: image processing kéo cả app down → tách worker riêng.
- Compliance: PCI scope phình to → tách payment service ra.
- Tech debt: legacy Python 2 không thể migrate cùng app → tách module legacy.
Cách tách an toàn: strangler fig pattern. Build service mới song song, dần route traffic, sau đó retire phần cũ.
Step 1: Monolith handle /users/* và /payments/*
Step 2: Tạo payment-service mới + nginx route /payments/* sang nó
Step 3: Backfill data, dual-write (cả monolith + service)
Step 4: Switch read traffic sang service
Step 5: Stop dual-write, monolith xoá payment module
Step 6: Done — payment-service độc lập
Distributed transaction: tránh hoặc dùng saga
SQL BEGIN ... COMMIT chỉ trong 1 DB. Microservices có nhiều DB → ACID classic không dùng được. Pattern thay thế:
Saga: chia transaction thành chuỗi step. Mỗi step có compensate (rollback logic).
Đặt hàng:
1. order-service: tạo order (state: pending) ← compensate: cancel order
2. payment-service: charge customer ← compensate: refund
3. inventory-service: reserve stock ← compensate: release stock
4. order-service: update state = confirmed
Nếu step 3 fail:
- compensate step 2: refund payment
- compensate step 1: cancel order
- notify user
Phức tạp hơn nhiều SQL transaction. Đó là cái giá của microservices.
Khung quyết định cho dự án mới
- Team < 10 engineer? → Modular monolith
- Domain chưa rõ? → Modular monolith
- Cần ship MVP < 6 tháng? → Modular monolith
- Đã có ≥3 team độc lập + đau vì conflict? → Tách service từng phần
- Compliance/legacy bắt buộc tách? → Tách phần đó
- "Vì AWS bài hay nói thế"? → Đừng tách
Kết luận
Microservices vs monolith không phải lựa chọn either/or. Modular monolith trước, tách dần khi có pain là chiến lược an toàn cho 95% dự án. Anh có thể đạt scale tốt với monolith được tổ chức kỹ. Nếu chọn microservices từ ngày đầu mà không có lý do cụ thể, anh đang trade-in 30% velocity để mua benefit chưa cần. Đọc thêm Observability để chuẩn bị nền tảng nếu sẽ tách service trong tương lai.