Sổ tay Kiến trúc Phần mềm
11 Phần II · Phong cách Chương 17 & 18

Microservices & Cách chọn phong cách

Microservices & Choosing the Right Style

Phong cách phân tán tới hạn của DDD: mỗi service một bounded context, sở hữu dữ liệu riêng, "share nothing". Và rồi câu hỏi gói trọn Phần II — chọn phong cách nào? Câu trả lời, như mọi khi, là "còn tùy".

01 Microservices là gì?

Lấy cảm hứng mạnh từ Bounded Context (DDD): mỗi service hạt mịn, một mục đích, triển khai độc lập, và sở hữu dữ liệu riêng. Là "hiện thân vật lý" của các khái niệm logic trong domain-driven design — đẩy domain partitioning tới cực hạn.

Microservices ưa trùng lặp hơn ghép nối — thà nhân bản dữ liệu còn hơn chia sẻ schema/lớp để rồi dính chặt vào nhau.

Triết lý "share nothing"

Nhớ Entity Trap (topic 04): đừng mô hình hoá service giống hệt từng bảng DB. Service là bounded context (luồng nghiệp vụ), không phải "Manager theo thực thể".

02 Bốn nguyên tắc cốt lõi

Distributed

mỗi service một process

Mỗi service chạy process riêng (máy ảo/container) → tách rời triệt để, hết tranh chấp tài nguyên. Đổi lại: network call chậm hơn method call → hiệu năng là điểm yếu.

Bounded Context

share nothing

Mỗi service mô hình một domain/subdomain; nội bộ gắn kết nhưng không ghép với schema/lớp của context khác.

Granularity

tính hạt — phần khó nhất

Hay mắc lỗi chia quá nhỏ rồi phải nối lại. Ba kim chỉ nam: Purpose (một trách nhiệm), Transactions (gom thực thể cần giao dịch chung), Choreography (gom nếu liên-service quá nhiều).

Data Isolation

database per service

Không DB/schema dùng chung làm điểm tích hợp. Mỗi đội tự chọn kho phù hợp nhất, đổi mà không ảnh hưởng đội khác.

03 Vận hành & giao tiếp

Tái sử dụng vận hành (không phải code)

Microservices tách domain khỏi vận hành: không tái dùng code nghiệp vụ, nhưng chia sẻ năng lực vận hành (logging, monitoring, circuit breaker) qua hạ tầng.

Sidecar

mối quan tâm vận hành

Tách phần vận hành chung thành một thành phần "đi kèm" trong mỗi service.

Service Mesh

service plane

Nối các sidecar thành một mặt phẳng điều khiển vận hành thống nhất toàn hệ.

Service Discovery

đàn hồi

Request đi qua công cụ khám phá → tự tìm & bung thêm thực thể service khi cần. Thường đặt ở API layer.

API layer là proxy/điểm khám phá tuỳ chọn giữa người dùng & service — không được làm mediator hay chứa logic nghiệp vụ (khác hẳn ESB của SOA). Frontend: một UI khối (monolithic) gọi qua API, hoặc micro-frontend khớp ranh giới service để một đội làm trọn domain từ UI đến dữ liệu.

Giao tiếp giữa các service

Đồng bộ

protocol-aware · heterogeneous

REST/gRPC; service phải biết (hoặc khám phá) giao thức gọi nhau. Hỗ trợ polyglot — mỗi service một stack công nghệ khác nhau.

Bất đồng bộ

event & message

Dùng sự kiện/tin nhắn khi cần hiệu năng & quy mô; nhúng tinh thần Event-Driven (topic 09).

Phối hợpChoreography (biên đạo)Orchestration (điều phối)
Cách làmService tự gọi nhau (như Broker, không nhạc trưởng)Tạo một mediator cục bộ cho một workflow
ƯuGiữ tách rời tối đa, nhanh, ít nút thắtDễ điều phối & xử lý lỗi cho luồng phức tạp
NhượcXử lý lỗi & điều phối phức tạpThêm chút ghép nối vào mediator

Transactional Saga: thay vì giao dịch phân tán, dùng giao dịch bù (compensating) — mỗi bước có "do" & "undo" để hoàn tác khi lỗi. Nhưng undo phức tạp gấp bội → sách khuyên dùng saga thật tiết kiệm; lạm dụng giao dịch xuyên service là đi ngược lý do chọn microservices.

04 Đánh giá đặc tính — Microservices

Vô địch về mở rộng, đàn hồi, tiến hoá, mô-đun, linh hoạt (5★); triển khai & kiểm thử rất cao nhờ tự động hoá (4½★). Đổi lại 1★ chi phí & đơn giản — không có DevOps thì không tồn tại. (½ = nửa chấm)

Khả năng mở rộng Scalability
Tính đàn hồi Elasticity
Khả năng tiến hóa Evolutionary
Tính mô-đun Modularity
Sự linh hoạt Agility
Khả năng triển khai Deployability
Khả năng kiểm thử Testability
Khả năng chịu lỗi Fault tolerance
Độ tin cậy Reliability
Hiệu suất Performance
Chi phí tổng thể Overall cost
Tính đơn giản Simplicity

05 Chọn phong cách phù hợp (Chương 18)

Không có phong cách "đúng" — chỉ có phong cách ít tệ nhất cho ngữ cảnh này. "Thời trang" kiến trúc luôn dịch chuyển theo hệ sinh thái (Docker, Kubernetes…), bài học quá khứ, năng lực mới. KTS quyết theo ba bước:

Monolith hay Distributed?

Dựa trên architecture quantum: một bộ đặc tính cho cả hệ → monolith; các phần cần đặc tính khác nhau → phân tán.

Dữ liệu sống ở đâu?

Monolith: một (vài) DB quan hệ. Phân tán: service nào sở hữu dữ liệu gì, và dữ liệu chảy thế nào qua các workflow.

Giao tiếp đồng bộ hay bất đồng bộ?

Mặc định đồng bộ (đơn giản, dễ debug); chỉ dùng bất đồng bộ khi cần hiệu năng/quy mô, chấp nhận rắc rối đồng bộ dữ liệu, deadlock, race.

Use synchronous by default, asynchronous when necessary. Đầu ra của quá trình này: topology + ADR (cho phần tốn công nhất) + fitness function (bảo vệ nguyên lý & đặc tính vận hành quan trọng).

Bản đồ chọn phong cách (tổng kết Phần II)

Khi nhu cầu chính là…Nghiêng về phong cáchNhóm
Đơn giản, rẻ, nhỏ, đội chưa thuần AgileLayered (06)Monolith
Dòng xử lý dữ liệu tuần tự (ETL/EDI)Pipeline (07)Monolith
Sản phẩm nặng tùy biến / plug-inMicrokernel (07)Monolith
Phân tán thực dụng: vài service + 1 DBService-Based (08)Distributed
Throughput cao, phản ứng sự kiện, tách rờiEvent-Driven (09)Distributed
Mở rộng cực hạn, tải biến động khó lườngSpace-Based (10)Distributed
Agility, đội độc lập, tiến hoá nhanh, đặc tính khác nhau theo phầnMicroservices (11)Distributed

Ví dụ · Silicon Sandwiches

→ Monolith

Đơn giản, một quantum, ngân sách thấp → modular monolith (hoặc microkernel). Tách bảng theo domain để sau dễ "tách" thành phân tán nếu cần.

Ví dụ · Going, Going, Gone

→ Microservices

Đấu giá: bidder / auctioneer / streamer cần đặc tính khác nhau, scale & performance cao → microservices (hợp hơn event-driven vì tách theo đặc tính vận hành).

RAG  Chọn style cho hệ "Hỏi–đáp tài liệu": Một quantum hay nhiều? Với RAG nội bộ tải vừa, ingest & query có đặc tính khá khác (nền/đồng bộ) nhưng chưa tới mức cần đội độc lập → Service-Based thường "ít tệ nhất". Dữ liệu sống ở đâu: vector store là system of record. Giao tiếp: query đồng bộ (PHP↔Python) mặc định, ingest bất đồng bộ khi cần chịu tải. Chỉ leo lên Microservices khi nhiều đội, nhiều vendor model, và phần truy hồi cần scale độc lập với phần sinh câu trả lời.

06 Ghi nhớ nhanh

Microservices = bounded context + share nothing — fine-grained, database per service, ưa trùng lặp hơn ghép nối.

Tái dùng vận hành, không tái dùng code — sidecar + service mesh + service discovery; API layer là proxy, KHÔNG phải mediator.

Choreography mặc định, saga tiết kiệm — tránh giao dịch phân tán; lạm dụng là phản bội lý do chọn MSA.

Chọn style theo 3 bước — quantum (mono/distributed) → dữ liệu sống ở đâu → đồng bộ (mặc định) vs bất đồng bộ (khi cần).

"It depends" — luôn là đánh đổi — không nhắm phong cách tốt nhất, nhắm phong cách ít tệ nhất cho bài toán & ngữ cảnh hiện tại.

NguồnChương 17 (Microservices Architecture) & Chương 18 (Choosing the Appropriate Architecture Style), Fundamentals of Software Architecture — Mark Richards & Neal Ford, O'Reilly 2020.