1. Fault isolation (Cô lập lỗi)
Khi sử dụng kiến trúc microservices, việc cô lập lỗi trở nên dễ dàng hơn và hiệu quả hơn.
Khi xảy ra sự cố trong một service cụ thể, chúng ta chỉ cần tập trung khắc phục lỗi trong service đó, mà không cần phải rà soát toàn bộ codebase để tìm và sửa lỗi.
Khả năng giới hạn phạm vi ảnh hưởng của lỗi trong một microservice riêng biệt được gọi là fault isolation (cô lập lỗi).
2. Development team autonomy
Trong kiến trúc monolithic, khi số lượng lập trình viên và các nhóm cùng làm việc trên một codebase duy nhất vượt quá một ngưỡng nhất định, năng suất và tốc độ phát triển của các đội có thể bị suy giảm.
Trong tình huống này, việc quản lý trở nên phức tạp hơn. Khi kích thước codebase tăng, thời gian biên dịch và thời gian chạy test cũng tăng theo. Nguyên nhân là trong kiến trúc monolithic, toàn bộ codebase phải được biên dịch lại mỗi khi có thay đổi, thay vì chỉ biên dịch module đang được chỉnh sửa.
Một thay đổi mã nguồn do bất kỳ nhóm nào khác thực hiện trong codebase đều ảnh hưởng trực tiếp đến các tính năng mà nhóm chúng ta đang phát triển, thậm chí có thể làm hỏng chức năng của tính năng đó. Vì lý do này, kiểm thử hồi quy toàn diện là bắt buộc mỗi khi có code mới hoặc bản cập nhật được đẩy lên môi trường production.
Ngoài ra, khi code được triển khai lên production, tất cả các nhóm thường phải tạm dừng làm việc trên codebase cho đến khi quá trình triển khai hoàn tất.
Mã nguồn được đẩy lên bởi một nhóm cũng có thể cần sự phê duyệt từ các nhóm khác trong tổ chức đang làm việc trên cùng codebase. Quy trình này dễ trở thành nút thắt cổ chai (bottleneck) trong hệ thống phát triển.
Microservices và tính tự chủ của đội phát triển
Ngược lại, trong kiến trúc microservices, mỗi nhóm chuyên trách có toàn quyền sở hữu codebase của mình.
Họ có tính tự chủ hoàn toàn trong phát triển và triển khai module thông qua các pipeline triển khai độc lập. Việc quản lý mã nguồn trở nên đơn giản hơn, và việc scale từng service riêng lẻ dựa trên mô hình tải (traffic load patterns) cũng dễ dàng hơn.
Vì vậy, nếu mục tiêu là di chuyển nhanh, ra mắt nhiều tính năng trong thời gian ngắn và mở rộng quy mô linh hoạt, thì kiến trúc microservices là một lựa chọn đáng cân nhắc.
Chi phí đánh đổi của Microservices
Tuy nhiên, dù microservices nghe có vẻ hấp dẫn, chúng ta không thể bỏ qua sự gia tăng độ phức tạp mà kiến trúc này mang lại. Việc áp dụng microservices luôn đi kèm chi phí đánh đổi.
Với kiến trúc microservices, chúng ta cần thiết lập nhiều thành phần bổ sung, chẳng hạn như:
- Logging phân tán
- Giám sát (monitoring)
- Giao tiếp giữa các service
- Service discovery
- Cảnh báo (alerts)
- Tracing
- Pipeline build và release riêng biệt
- Health check
- v.v.
Trong nhiều trường hợp, đội ngũ còn phải tự xây dựng các công cụ tùy chỉnh từ đầu.
Có lẽ bạn đã hình dung được vấn đề. Luôn tồn tại sự đánh đổi, và không có kiến trúc nào là hoàn hảo tuyệt đối. Điều quan trọng là phải hiểu thật rõ use case và lựa chọn kiến trúc phù hợp nhất với nhu cầu.
3. Segment – From monolith to microservices and back again to the monolith
Segment là một nền tảng dữ liệu khách hàng (Customer Data Platform). Ban đầu, họ xây dựng hệ thống theo kiến trúc monolithic, sau đó tách ra thành microservices. Khi hoạt động kinh doanh phát triển mạnh, họ lại quyết định quay trở về kiến trúc monolithic.
Vì sao họ lại làm vậy?
Hãy cùng phân tích.
- Đội ngũ kỹ sư của Segment đã tách hệ thống monolith ban đầu thành các microservices với mục tiêu cô lập lỗi (fault isolation) và dễ dàng debug các sự cố trong hệ thống.
- Việc cô lập lỗi bằng microservices giúp họ giảm thiểu mức độ ảnh hưởng của sự cố. Khi một lỗi xảy ra, nó chỉ bị giới hạn trong một service cụ thể, thay vì ảnh hưởng – hoặc thậm chí làm sập – toàn bộ hệ thống.
- Trong khi đó, kiến trúc monolith ban đầu có chi phí quản lý thấp, nhưng lại tồn tại điểm lỗi đơn (single point of failure). Một lỗi nhỏ trong một chức năng có thể tác động đến toàn bộ hệ thống.
- Segment tích hợp dữ liệu từ rất nhiều nhà cung cấp dữ liệu khác nhau. Khi hoạt động kinh doanh mở rộng, họ tích hợp thêm ngày càng nhiều nhà cung cấp, và mỗi nhà cung cấp lại được triển khai dưới dạng một microservice riêng.
- Số lượng microservices tăng lên nhanh chóng đã dẫn đến độ phức tạp kiến trúc tăng mạnh, và điều này ảnh hưởng tiêu cực đến năng suất làm việc của đội ngũ.
- Các lỗi liên quan đến microservices bắt đầu gia tăng đáng kể. Họ phải có ba kỹ sư chỉ chuyên xử lý lỗi để giữ cho hệ thống hoạt động ổn định.
- Chi phí vận hành này trở nên rất tốn kém về nguồn lực và làm chậm tốc độ phát triển của toàn bộ tổ chức.
- Để giải quyết vấn đề, Segment đã đưa ra quyết định quay trở lại kiến trúc monolithic, chấp nhận từ bỏ khả năng cô lập lỗi và những lợi ích “đẹp đẽ” khác mà microservices mang lại.
- Cuối cùng, họ xây dựng một kiến trúc với một repository duy nhất có tên là Centrifuge, hệ thống này xử lý hàng tỷ message mỗi ngày, phân phối dữ liệu tới nhiều API khác nhau.
👉 Bài học rút ra
Microservices không phải lúc nào cũng là “chén thánh”.
Khi độ phức tạp vận hành vượt quá lợi ích mang lại, một monolith được thiết kế tốt đôi khi lại là lựa chọn hiệu quả hơn.
Chìa khóa nằm ở việc:
- Đánh giá đúng quy mô
- Tốc độ tăng trưởng
- Và năng lực vận hành của đội ngũ
trước khi quyết định kiến trúc.
Segment high-level architecture
- Hạ tầng dữ liệu của Segment tiếp nhận hàng trăm nghìn sự kiện mỗi giây. Các sự kiện này sau đó được định tuyến tới nhiều API và webhook khác nhau thông qua một hàng đợi thông điệp (message queue).
- Những API này còn được gọi là server-side destinations, và tại Segment có hơn một trăm destination như vậy.
- Khi mới bắt đầu với kiến trúc monolithic, Segment có một API duy nhất để tiếp nhận các sự kiện từ nhiều nguồn khác nhau. Sau khi tiếp nhận, các sự kiện này được đẩy vào một hệ thống message queue phân tán.
- Hàng đợi này sẽ tiếp tục chuyển payload của sự kiện tới các API đích (destination APIs) tương ứng, dựa trên cấu hình và các thiết lập đã được định nghĩa trước.

- Trong kiến trúc monolithic, do tất cả các sự kiện đều được đẩy vào một message queue duy nhất, nên thường xuyên xảy ra tình trạng một số sự kiện không gửi được tới các destination và phải được queue retry lại sau các khoảng thời gian định sẵn.
- Điều này khiến cho queue chứa đồng thời cả các sự kiện mới và các sự kiện thất bại đang chờ retry. Hệ quả là queue dần bị quá tải (flooded), dẫn đến độ trễ ngày càng lớn trong việc phân phối sự kiện tới các destination.
- Để giải quyết vấn đề queue bị quá tải, đội ngũ kỹ sư của Segment đã tách hệ thống monolith thành các microservices, và tạo một microservice riêng cho mỗi destination.
- Khi đó, mỗi service có một distributed message queue độc lập của riêng nó. Cách tiếp cận này giúp giảm tải cho từng queue đơn lẻ, đồng thời cho phép hệ thống mở rộng tốt hơn và tăng throughput tổng thể.

- Trong kịch bản này, ngay cả khi một queue cụ thể bị quá tải, thì việc phân phối sự kiện của các service khác vẫn không bị ảnh hưởng. Đây chính là cách Segment tận dụng khả năng cô lập lỗi (fault isolation) trong kiến trúc microservices.
- Theo thời gian, khi quy mô kinh doanh mở rộng, nhiều destination mới được bổ sung. Mỗi destination tương ứng với một microservice và một queue riêng, khiến số lượng service tăng lên nhanh chóng, kéo theo độ phức tạp của kiến trúc cũng tăng theo.
- Mỗi service có throughput sự kiện và mô hình tải (traffic load pattern) khác nhau. Vì vậy, không thể áp dụng một chính sách scale chung cho tất cả các queue.
- Từng service và từng queue phải được scale riêng biệt dựa trên tải thực tế của nó, và quá trình này phần lớn phải thực hiện thủ công.
- Mặc dù autoscaling đã được triển khai trong hạ tầng, nhưng mỗi service lại có yêu cầu CPU và bộ nhớ khác nhau. Điều này đòi hỏi việc tinh chỉnh (manual tuning) hạ tầng liên tục, đồng nghĩa với chi phí vận hành và bảo trì tăng cao khi số lượng queue ngày càng nhiều.
- Để giải quyết vấn đề này, Segment cuối cùng đã quay trở lại kiến trúc monolithic, và gọi kiến trúc đó là Centrifuge – một dịch vụ monolith duy nhất, nơi tất cả các queue riêng lẻ của từng destination được hợp nhất lại.
4. Istio – The Move from Microservices to a Monolith
Istio là một service mesh mã nguồn mở, cho phép:
- Kết nối
- Bảo mật
- Kiểm soát
- Quan sát (observe) các microservices
Istio giúp điều phối cách các microservices giao tiếp và chia sẻ dữ liệu với nhau.
Gần đây, Istio đã chuyển từ kiến trúc microservices sang kiến trúc monolith. Theo đội ngũ Istio, kiến trúc monolith giúp họ:
- Mang lại giá trị tốt hơn
- Đạt được các mục tiêu đã đặt ra
Tài liệu khuyến nghị đọc
Istio is an example of when not to do microservices