← Chương trước: Part 5: Observability Trong Bộ Nhớ – Khi Mọi Thứ Nằm Chung Một | Mục lục Series | Chương tiếp theo: Part 7: Mô Hình Trích Xuất (Extraction Pattern) – Khi Nào Nên →
Answer-first: Cẩm nang chuyển đổi từ microservices về Modular Monolith sử dụng mô hình Reverse Strangler Fig, kỹ thuật dual-write cơ sở dữ liệu và tái cấu trúc team theo Định luật Conway. Phương pháp đảm bảo quy trình hợp nhất diễn ra an toàn với zero-downtime.
Part 6: Lộ Trình Chuyển Đổi (Migration Playbook) – Hợp Nhất Microservices Về Monolith
Việc phá vỡ một khối Monolith thành nhiều Microservices thường được gọi là mô hình Strangler Fig Pattern (mô hình chuyển đổi từng phần). Quy trình hợp nhất (Consolidation) các Microservices phân tán về lại một hệ thống Monolith trung tâm sẽ tuân theo chiều ngược lại: Reverse Strangler Fig Pattern.
Mặc dù việc gộp code application có vẻ đơn giản, nhưng rủi ro cao nhất của quá trình này nằm ở Dữ liệu (Database) và Con người (Organization). Dưới đây là Playbook (lộ trình thực chiến) từng bước để hợp nhất kiến trúc một cách an toàn (zero-downtime).
1. Định Luật Conway: Chuẩn Bị Về Mặt Tổ Chức
Vào năm 1968, Melvin Conway đã phát biểu một định luật kinh điển (Conway’s Law):
“Bất kỳ tổ chức nào thiết kế một hệ thống… chắc chắn sẽ tạo ra một thiết kế mang cấu trúc bản sao của các luồng giao tiếp trong tổ chức đó.”
Bạn không thể chuyển đổi thành công từ Microservices sang Modular Monolith nếu tổ chức của bạn vẫn duy trì hàng chục team nhỏ hoạt động silo (độc lập, không giao tiếp). Hành động:
- Phải gom các team kỹ thuật (Engineering Teams) nhỏ lại thành các Domain Teams lớn hơn (Macro-teams).
- Quy định rõ ràng quy tắc đóng góp mã nguồn (Code Contribution) trên một kho lưu trữ chung (Monorepo codebase) trước khi viết dòng code hợp nhất đầu tiên.
Tiêu Chuẩn Tiền Đề (Tiêu Chuẩn 2026)
Theo các thực tiễn mới nhất từ ngành công nghiệp phần mềm:
- Observability (Khả năng quan sát): Việc áp dụng OpenTelemetry hoặc các giải pháp tracing phân tán (distributed tracing) là bắt buộc. Bạn không thể hợp nhất nếu không biết rõ traffic đang đi như thế nào giữa các service.
- Kiểm thử kiến trúc (Architecture Testing): Sử dụng các công cụ như ArchUnit (Java/.NET) để tự động hóa việc kiểm tra ranh giới giữa các module trong quá trình CI/CD. Nếu một module gọi trực tiếp các lớp nội bộ của module khác, CI phải báo lỗi (fail) ngay lập tức.
2. Reverse Strangler Fig Pattern: Gộp Code Không Downtime
Mục tiêu của mô hình này là đưa các tính năng từ Microservice bên ngoài vào trong lõi Monolith mà người dùng cuối không hề hay biết.
Bước 1: Tạo Module Mới Bên Trong Monolith
Thay vì viết mới hoàn toàn, bạn tạo một package/module mới (ví dụ: PaymentModule) nằm ngay bên trong Modular Monolith, áp dụng nghiêm ngặt các ranh giới Bounded Contexts (xem Phần 3). Import logic từ Microservice cũ sang Module này.
Bước 2: Xây Dựng Anti-Corruption Layer (Tùy chọn) Nếu cấu trúc dữ liệu của Microservice cũ quá khác biệt, hãy xây dựng một lớp chuyển đổi (Anti-corruption layer) để Module mới giao tiếp chuẩn mực với các Module khác trong Monolith.
Bước 3: Định Tuyến Tại API Gateway (Canary Routing) Sử dụng API Gateway hoặc Load Balancer (như NGINX, AWS ALB) để điều hướng traffic. Ban đầu, đẩy 95% traffic về Microservice cũ (Legacy), 5% traffic về API tương ứng trên hệ thống Modular Monolith (New). Kiểm tra lỗi kỹ lưỡng và tăng dần tỷ lệ lên 100%.
4. Ác Mộng Lớn Nhất: Hợp Nhất Dữ Liệu (Database Consolidation)
Dịch chuyển code không làm chết hệ thống, nhưng sai lầm khi dịch chuyển dữ liệu sẽ phá hủy doanh nghiệp. Quá trình di chuyển dữ liệu từ Database của Microservice về chung Schema của Modular Monolith phải thực hiện chiến lược Dual-Write (Ghi song song) để đảm bảo an toàn tuyệt đối.
Phase 1: Ghi Song Song (Dual-Write)
- Khi ứng dụng nhận một lệnh
CREATEhoặcUPDATE, nó sẽ ghi dữ liệu (write) vào cả 2 nơi: Database của Microservice cũ và Schema tương ứng trên Database của Monolith. - Lưu ý: Việc đọc (Read) vẫn hoàn toàn chỏ về Database của Microservice cũ.
Phase 2: Đồng Bộ Dữ Liệu Lịch Sử (Backfill)
- Viết các script bất đồng bộ (Asynchronous jobs) để copy các dữ liệu cũ (historical data) từ DB Microservice sang DB Monolith mà không gây nghẽn hệ thống đang chạy.
- So khớp (Verify) đảm bảo tổng lượng bản ghi ở cả hai bên trùng khớp hoàn toàn.
Phase 3: Đổi Nguồn Đọc (Switch Read)
- Khi cả hai Database đã đồng bộ 100%, bạn thay đổi logic hệ thống để bắt đầu Đọc (Read) từ Database của Monolith.
- Duy trì việc Dual-write trong vài tuần để làm kênh an toàn (Fallback/Rollback gate). Nếu có lỗi logic đọc dữ liệu mới, bạn vẫn có thể quay lại đọc từ DB cũ ngay lập tức.
Phase 4: Khai Tử Microservice (Decommission)
- Tắt tính năng Dual-write. Chỉ còn thao tác trực tiếp trên DB Monolith.
- Tắt (Shut down) server của Microservice cũ, xóa sổ kho chứa code (Repository), hoàn tất quá trình hợp nhất.
[!WARNING] Rủi Ro Dữ Liệu: Đừng bao giờ thực hiện di chuyển Database bằng cách “Dừng hệ thống, Export file SQL, Import vào DB mới, rồi Bật lại”. Downtime có thể kéo dài hàng giờ nếu import gặp sự cố. Mô hình Dual-write (hoặc kết hợp với Change Data Capture - CDC) là bắt buộc cho hệ thống Production.
Tổng Kết Playbook
Gộp Microservices về Modular Monolith là một dự án đòi hỏi sự tỉ mỉ. Nó làm giảm chi phí dài hạn (FinOps) nhưng sẽ tốn nỗ lực ngắn hạn của đội ngũ kỹ thuật.
Vậy, có khi nào chúng ta KHÔNG NÊN hợp nhất một dịch vụ vào Monolith, hoặc thậm chí phải TÁCH nó ra khỏi Monolith không? Tất nhiên là có. Việc theo đuổi Monolith một cách mù quáng cũng nguy hiểm không kém. Cùng tìm hiểu triết lý phân tách đúng đắn tại Phần 7: Mô Hình Trích Xuất (Extraction Pattern).
🔗 Đọ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 5: Observability Trong Bộ Nhớ – Khi Mọi Thứ Nằm Chung Một | Mục lục Series | Chương tiếp theo: Part 7: Mô Hình Trích Xuất (Extraction Pattern) – Khi Nào Nên →
