← Chương trước: Part 6: Lộ Trình Chuyển Đổi (Migration Playbook) – Hợp Nhất | Mục lục Series | Chương tiếp theo: Part 8: Ma Trận Case Study – Những Tượng Đài Của Modular Monolith →
Answer-first: Mô hình trích xuất định nghĩa 4 tiêu chí rõ ràng khi một module trong Monolith cần tách thành microservice độc lập: nhu cầu mở rộng tài nguyên đặc thù, yêu cầu đa ngôn ngữ polyglot, chu kỳ triển khai tách biệt hoặc bảo mật dữ liệu cấp cao.
Part 7: Mô Hình Trích Xuất (Extraction Pattern) – Khi Nào Nên Tách Microservices?
Việc ủng hộ kiến trúc Modular Monolith không đồng nghĩa với thái độ bảo thủ “Tất cả mọi thứ đều phải nằm chung một chỗ”. Trên thực tế, ngay cả những hệ thống Monolith vĩ đại nhất như Shopify, Sentry hay GitLab đều sở hữu một vài “vệ tinh” (Microservices) bay xung quanh khối lõi trung tâm.
Vấn đề cốt lõi là: Chúng ta chỉ trích xuất (extract) một tính năng thành Microservice khi nó thực sự xứng đáng, chứ không phải vì sở thích. Chuyên gia Sam Newman – tác giả cuốn Monolith to Microservices – đã nhấn mạnh rằng: Nếu bạn không thể chia tách Database Schema thành công bên trong một Monolith, thì bạn chắc chắn sẽ tạo ra một Microservice thảm họa.
Theo các báo cáo và kinh nghiệm thực tiễn tới năm 2026, việc trích xuất phải được thúc đẩy bởi “Nỗi đau có thể đo lường” (Demonstrable pain). Nếu bạn không thể chỉ ra cụ thể điểm nghẽn mà Monolith không thể giải quyết, thì việc giữ nguyên Modular Monolith luôn là lựa chọn rẻ và hiệu quả nhất.
Dưới đây là 4 tín hiệu cho thấy một Module đã “tốt nghiệp” và sẵn sàng để được tách ra khỏi Modular Monolith.
Tín Hiệu 1: Nhu Cầu Mở Rộng Độc Lập (Independent Scaling) Về Tài Nguyên
Đôi khi, ứng dụng của bạn có một tác vụ tiêu thụ tài nguyên hệ thống hoàn toàn khác biệt so với phần còn lại của nghiệp vụ (CRUD thông thường).
Case Study: Sentry và dịch vụ Snuba/Relay Sentry (nền tảng theo dõi lỗi phổ biến thế giới) được xây dựng cốt lõi bằng một Monolith khổng lồ chạy Python (Django). Tuy nhiên, họ đối mặt với một vấn đề: Tốc độ khách hàng gửi các gói tin báo lỗi (Events Ingestion) cao hơn gấp ngàn lần so với thao tác xem báo cáo trên web.
- Thay vì bắt hệ thống web (Django) phải gánh lượng traffic khổng lồ này, Sentry đã trích xuất riêng tầng tiếp nhận sự kiện thành một Microservice tên là Relay (được viết lại hoàn toàn bằng Rust để tối ưu hóa CPU và RAM).
- Đồng thời, khâu lưu trữ và tìm kiếm log lớn (High-cardinality data) được trích xuất ra một service riêng tên là Snuba (chạy trên ClickHouse DB). Phần còn lại của nghiệp vụ, từ thanh toán, quản lý tài khoản, đến logic phân tích lỗi vẫn tiếp tục nằm an toàn và gọn gàng trong khối Python Monolith.
Tín Hiệu 2: Yêu Cầu Chuyên Biệt Về Môi Trường & Ngôn Ngữ (Polyglot)
Đôi lúc, ngôn ngữ lập trình của Monolith không cung cấp thư viện hoặc hiệu suất tốt nhất cho một tính năng cụ thể.
Case Study: GitLab và Gitaly GitLab là một dự án Ruby on Rails Monolith cực lớn. Nhưng thao tác đọc/ghi trực tiếp vào hệ thống file (FileSystem) của Git repo bằng Ruby lại cực kỳ chậm và sinh ra các nút thắt cổ chai về ổ cứng (I/O Bottleneck) khi scale.
- GitLab đã quyết định tạo ra một dịch vụ chuyên biệt duy nhất để nói chuyện với các file Git trên ổ cứng, gọi là Gitaly.
- Gitaly được viết bằng Go (Golang) để xử lý đa luồng (Concurrency) và truy xuất I/O cấp thấp tốt hơn hẳn Ruby.
- Tuy nhiên, GitLab cực kỳ kỷ luật: Gitaly chỉ xử lý Git files. Toàn bộ tính năng phân quyền, quản lý tổ chức, merge request… vẫn không bị bứt ra khỏi lõi Rails. Đây là minh chứng tuyệt vời cho việc “Trích xuất công cụ, Giữ lại nghiệp vụ”.
Tín Hiệu 3: Tần Suất Triển Khai (Deployment Cadence) Đột Biến
Nếu toàn bộ khối Monolith của bạn thường được release 2 ngày một lần, nhưng có một module duy nhất (ví dụ: Module thuật toán AI gợi ý sản phẩm) cần được cập nhật cấu hình 15 phút một lần từ các Data Scientist.
Sự chênh lệch về tốc độ rủi ro (Risk cadence) này là lý do hợp lý để tách Module AI ra thành một Microservice độc lập. Điều này ngăn chặn việc cấu hình AI làm gián đoạn vòng đời CI/CD ổn định của toàn hệ thống cốt lõi.
Tín Hiệu 4: Yêu Cầu Về Tuân Thủ (Compliance) Và Ranh Giới Tổ Chức
Tại các tổ chức lớn, việc xử lý thông tin thẻ tín dụng (PCI-DSS) hoặc dữ liệu y tế sức khỏe (HIPAA) thường phải tuân theo các quy định kiểm toán bảo mật khắt khe.
Nếu toàn bộ Monolith đều chứa code xử lý thẻ tín dụng, bạn phải đưa hàng triệu dòng code qua các quy trình kiểm toán (Audit) đắt đỏ định kỳ. Tách module xử lý Thanh toán (Billing) ra thành một hệ thống nhỏ gọn, được vận hành bởi một team An ninh bảo mật chuyên trách (Dedicated Team) là một quyết định chiến lược (Organizational Boundary) khôn ngoan để tiết kiệm chi phí pháp lý.
Nguyên Tắc “Xé Rào” Database
Trước khi thực sự tạo mới một repository và viết Microservice:
- Bạn phải đảm bảo rằng Module đó trong Monolith đã có một Bounded Context chuẩn mực.
- Các bảng tính (Tables) của module đó tuyệt đối không bị dính dáng (JOIN) với các bảng của module khác.
Hãy trích xuất Cơ sở dữ liệu (Database Schema) trước khi trích xuất Code. Nếu DB không thể tách, Code cũng không bao giờ có thể chạy độc lập.
Như vậy, chúng ta đã đi qua toàn bộ lý thuyết và quy trình thiết kế. Ở Phần 8: Ma Trận Case Study (bài viết cuối cùng của chuỗi Playbook), chúng ta sẽ đối chiếu mọi lý luận bằng một bảng tổng hợp những con số biết nói từ Shopify, Stack Overflow, Target, Zulip, Notion và Basecamp.
🔗 Đọc thêm các chuyên đề liên quan:
- Kiến trúc Microservices Golang & DDD
- Triển khai Agentic AI Swarm trong Production với OpenClaw & LiteLLM
- Kiến trúc Microservices Golang gRPC: Protobuf, TLS & Middleware
← Chương trước: Part 6: Lộ Trình Chuyển Đổi (Migration Playbook) – Hợp Nhất | Mục lục Series | Chương tiếp theo: Part 8: Ma Trận Case Study – Những Tượng Đài Của Modular Monolith →
