Bỏ qua đến nội dung chính
microservicesmonolitharchitecturesystem designbackend

Microservices vs Monolith: Khi Nào Nên Tách Service?

Microservices vs monolith: tradeoff thực tế, khi nào tách dịch vụ, khi nào giữ monolith. Phân tích từ team 2 người tới 100+ engineer.

Xuất bản 9 phút đọc

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ạnhMonolithMicroservices
Deploy1 pipeline50 pipeline, deploy ordering
Logging1 file/serviceAggregate log 50 service (Loki/ELK)
TracingStack trace localDistributed tracing (Jaeger, Tempo)
Local devnpm run devDocker Compose 20 container
Bug debugĐặt breakpointTrace qua 5 service, log correlation ID
Schema change1 migrationBackwards compat 2-3 version
Data joinSQL JOINData composition ở app layer
Cost1 server lớn50 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:

  1. Deploy conflict: 2 team cùng deploy 5 lần/ngày, conflict liên tục → tách.
  2. Scale khác nhau: image processing kéo cả app down → tách worker riêng.
  3. Compliance: PCI scope phình to → tách payment service ra.
  4. 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

  1. Team < 10 engineer? → Modular monolith
  2. Domain chưa rõ? → Modular monolith
  3. Cần ship MVP < 6 tháng? → Modular monolith
  4. Đã có ≥3 team độc lập + đau vì conflict? → Tách service từng phần
  5. Compliance/legacy bắt buộc tách? → Tách phần đó
  6. "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.

Zalo