Microservices — Khái niệm, lợi ích & cạm bẫy (Building Microservices)

Phong

Mở đầu

Ảnh: K — Pexels

Microservices đã trở thành một trong những chủ đề được bàn luận nhiều nhất trong kiến trúc phần mềm hiện đại. Nhưng chính xác thì microservices là gì? Khác gì với SOA? Và quan trọng hơn — khi nào thì nên (và không nên) dùng chúng?

Chương 1 của cuốn "Building Microservices" (Sam Newman, ấn bản 2) mở đầu bằng cách định nghĩa rõ ràng về microservices, so sánh với monolithic architecture, và trình bày toàn diện về lợi ích lẫn cạm bẫy. Đây là nền tảng cho toàn bộ cuốn sách.

Microservices là gì?

Microservices là một cách tiếp cận kiến trúc trong đó một ứng dụng được chia thành nhiều dịch vụ nhỏ, độc lập, mỗi dịch vụ chạy trong tiến trình riêng và giao tiếp qua network (REST API, message queue, v.v.). Các dịch vụ này được tổ chức xoay quanh business domain, tự quản lý database của mình, và có thể deploy độc lập với nhau.

Điểm cốt lõi là information hiding — ẩn càng nhiều chi tiết triển khai bên trong service càng tốt, chỉ expose những gì thực sự cần qua interface bên ngoài. Nhờ đó, thay đổi bên trong một microservice không ảnh hưởng đến consumer upstream, miễn là interface network không thay đổi backward-incompatible.

SOA vs Microservices — Có gì khác?

Service-Oriented Architecture (SOA) là tiền đề của microservices, nhưng có khác biệt quan trọng. SOA về bản chất là ý tưởng đúng đắn — chia hệ thống thành nhiều service cộng tác với nhau. Tuy nhiên, SOA thường bị thất bại vì các lý do không liên quan đến ý tưởng: giao thức SOAP nặng nề, vendor middleware, thiếu hướng dẫn về granularity của service.

Sam Newman nhấn mạnh: "Hãy nghĩ về microservices như một cách tiếp cận cụ thể để làm SOA đúng — giống như Extreme Programming (XP) là một cách tiếp cận cụ thể để làm Agile." Microservices ra đời từ thực tiễn, tập trung vào independent deployability, bounded context từ domain-driven design, và tránh shared database.

Key Concepts của Microservices

Ảnh: Mikhail Nilov — Pexels

1. Independent Deployability (Quan trọng nhất)

Đây là nguyên tắc số một của microservices: bạn có thể thay đổi một service, deploy nó, và release thay đổi đó cho người dùng mà không cần deploy bất kỳ service nào khác. Sam Newman nói thẳng: "Nếu bạn chỉ nhớ một điều từ cuốn sách này, hãy nhớ independent deployability."

Để đạt được điều này, các service phải loosely coupled — có contract rõ ràng, ổn định giữa các service. Shared database là kẻ thù lớn nhất của independent deployability.

2. Modeled Around Business Domain

Thay vì chia theo tầng kỹ thuật (presentation, business logic, data), microservices được tổ chức xoay quanh business domain. Kiến trúc 3 tầng (three-tiered architecture) phổ biến vì nó phản ánh cách tổ chức team — nhưng đây lại là vấn đề.

Conway's Law giải thích: tổ chức sẽ tạo ra hệ thống phản ánh cấu trúc giao tiếp của chính nó. Nếu team được tổ chức theo chức năng kỹ thuật (DB team, backend team, frontend team), kiến trúc cũng sẽ phân tầng theo kỹ thuật. Microservices đảo ngược điều này: tổ chức team xoay quanh business capability, mỗi team chịu trách nhiệm end-to-end cho một business domain.

3. Owning Their Own State

Microservices nên tránh shared database. Nếu một service cần dữ liệu của service khác, nó phải gọi API của service đó — không query trực tiếp database. Điều này giống như encapsulation trong OOP: ẩn internal state, chỉ expose interface. Shared database phá hủy independent deployability và tăng coupling.

4. Size

"Microservice nên lớn cỡ nào?" — đây là câu hỏi thường gặp nhất. Câu trả lời của Sam Newman: đừng lo lắng về size. Tập trung vào (1) bạn có thể quản lý được bao nhiêu service, và (2) làm sao để định nghĩa boundary sao cho không trở thành mớ hỗn độn. Một service nên đủ nhỏ để một team có thể hiểu và maintain, nhưng không quá nhỏ để tạo ra distributed monolith.

Các loại Monolith

Ảnh: Tom Fisk — Pexels

Sam Newman phân biệt 3 loại monolith:

  • Single-process monolith: Tất cả code trong một process. Đơn giản, là default choice cho hầu hết tổ chức.
  • Modular monolith: Một process nhưng code được chia module rõ ràng. Shopify dùng pattern này rất thành công.
  • Distributed monolith: Nhiều service nhưng phải deploy cùng nhau — tệ nhất của cả 2 thế giới.

Quan trọng: monolith không phải là từ xấu. Đó là một lựa chọn kiến trúc hợp lệ. Sam Newman khẳng định: "Monolithic architecture là sensible default." Đừng chọn microservices trừ khi bạn có lý do chính đáng.

Lợi ích của Microservices

  • Technology Heterogeneity: Mỗi service có thể dùng tech stack khác nhau — chọn công cụ phù hợp cho từng bài toán.
  • Robustness: Service boundaries là bulkhead tự nhiên — một service fail không kéo sập toàn bộ hệ thống.
  • Scaling: Chỉ scale những service cần scale, không phải scale cả ứng dụng.
  • Ease of Deployment: Thay đổi 1 dòng code chỉ cần deploy 1 service, không phải toàn bộ.
  • Organizational Alignment: Team nhỏ, codebase nhỏ, ownership rõ ràng.
  • Composability: Functionality có thể được dùng lại và kết hợp theo nhiều cách khác nhau.

Cạm bẫy — Những gì dễ sai

Microservices không phải giải pháp vạn năng. Những pain points chính:

  • Developer Experience: Khó chạy toàn bộ hệ thống trên máy local, đặc biệt với JVM hay nhiều service.
  • Technology Overload: Cám dỗ dùng quá nhiều công nghệ mới cùng lúc — hãy giới thiệu từ từ, khi thực sự cần.
  • Cost: Nhiều service = nhiều process, nhiều máy, nhiều network. Chi phí tăng trong ngắn hạn.
  • Monitoring & Troubleshooting: Không còn binary up/down — cần log aggregation và distributed tracing.
  • Testing: End-to-end test phức tạp hơn nhiều, diminishing returns.
  • Data Consistency: Không có distributed transactions dễ dàng — cần sagas và eventual consistency.
  • Latency: Network calls chậm hơn in-process calls — cần design cẩn thận.

Khi nào nên (và không nên) dùng Microservices?

KHÔNG nên dùng: Startup mới, product đang iterate domain model, team nhỏ (< 10 người), product phải deploy tại chỗ khách hàng. Những trường hợp này, microservices tax (chi phí vận hành) sẽ giết chết năng suất.

Nên dùng: SaaS application cần 24/7 uptime + independent releases, team > 50 người cần tránh delivery contention, cần scale từng phần riêng lẻ, cần tích hợp nhiều channel (web, mobile, API).

Key Takeaways

  • Independent deployability là nguyên tắc quan trọng nhất — mọi thứ khác đều xoay quanh nó
  • Tránh shared database bằng mọi giá nếu muốn microservice thực sự
  • Monolithic architecture là default hợp lý — microservices cần được justify
  • Adopt incremental — turn the dial, không flip the switch
  • Log aggregation là prerequisite — đừng bắt đầu microservices nếu chưa có

📋 Phụ lục thuật ngữ

  • Information hiding — ẩn chi tiết triển khai bên trong component, chỉ expose interface bên ngoài
  • Independent deployability — khả năng deploy một service mà không cần deploy service khác
  • Conway's law — tổ chức tạo ra hệ thống phản ánh cấu trúc giao tiếp của chính nó
  • Bulkhead — ranh giới cách ly lỗi, ngăn failure cascade
  • Distributed monolith — nhiều service nhưng phải deploy cùng nhau, tệ nhất 2 thế giới
  • Information hiding — ẩn chi tiết triển khai, chỉ expose interface
  • Delivery contention — xung đột khi nhiều người/team cùng làm việc trên 1 codebase
  • Saga — pattern quản lý distributed transaction qua nhiều service
  • Eventual consistency — dữ liệu có thể không consistent ngay lập tức nhưng sẽ consistent theo thời gian