Mặc dù kiến trúc cloud-native (điện toán đám mây nguyên bản) đang ngày càng phổ biến, nhưng không phải ai cũng sẵn sàng áp dụng nó. Một trong những nguyên nhân chính là những nhược điểm tiềm ẩn của microservices, một thành phần cốt lõi của kiến trúc cloud-native.
Hiện nay, các kiến trúc cloud-native sử dụng triển khai Docker và Kubernetes đang rất được ưa chuộng. Các nhóm chọn microservices có thể hưởng lợi từ một số ưu điểm như:
- Microservices cung cấp sự linh hoạt trong việc lựa chọn các kiến trúc, ngôn ngữ, quy trình và công cụ khác nhau.
- Chúng tuân theo các phương pháp hay nhất đã được thiết lập như thiết kế theo domain (domain-driven design) và kiến trúc theo sự kiện (event-driven architectures).
- Chúng hỗ trợ quá trình ra mắt sản phẩm linh hoạt và nhanh hơn.
- Các công nghệ như Docker và Kubernetes, hỗ trợ microservices trong thời gian chạy, và có thể chạy trên các phần cứng tiêu chuẩn.
Tuy nhiên, điều cần thiết đối với các nhóm phát triển ứng dụng là phải nhận ra những hạn chế của microservices. Trước khi chuyển đổi từ một monolith (kiến trúc nguyên khối) đáng tin cậy sang nhiều thành phần nhỏ hơn có chức năng giống nhau, bạn phải hiểu những thách thức liên quan đến kiến trúc microservices và cách giảm thiểu chúng - hoặc thích ứng với chúng.
Nhược điểm hàng đầu của microservices có thể được phân loại như sau:
- Độ phức tạp trong mạng topology.
- Yêu cầu triển khai tự động.
- Thách thức về tích hợp và quản lý phụ thuộc
- Thách thức về việc dịch và tương thích dữ liệu.
- Nguy cơ tắc nghẽn mạng.
- Giảm tổng thể hiệu suất
- Chi phí cao.
- Sự phức tạp trong việc kiểm tra, theo dõi và audit
- Khó khắc phục sự cố và gỡ lỗi
- Trở ngại quán tính tổ chức.
1. Độ phức tạp trong mạng topology
Khi một ứng dụng monolithic được chia thành một tập hợp con các microservice độc lập giao tiếp qua mạng, nó làm tăng đáng kể độ phức tạp của kiến trúc.
Ví dụ, hãy tưởng tượng bạn chia một ứng dụng monolithic thành 10 microservice. Điều này đòi hỏi việc cập nhật nhiều tác vụ khác nhau:
- Mở rộng: Bạn cần có khả năng mở rộng 10 ứng dụng thay vì chỉ một.
- Bảo mật: Bạn cần bảo mật 10 điểm cuối API thay vì chỉ một điểm cuối.
- Kiểm soát phiên bản: Thay vì một kho lưu trữ Git, giờ đây bạn cần quản lý 10 kho lưu trữ riêng cho từng microservice.
- Xây dựng: Bạn cần xây dựng 10 gói (package) thay vì chỉ một gói duy nhất.
- Triển khai: Thay vì triển khai một ứng dụng, bạn cần triển khai 10 artifact (thành phẩm) riêng biệt.
Việc quản lý nhiều chương trình nhỏ hơn rõ ràng phức tạp hơn so với một ứng dụng monolithic (đơn khối) thống nhất. Độ phức tạp này là một trong những hạn chế chính của kiến trúc microservices.
2. Yêu cầu triển khai tự động
Mặc dù kiến trúc microservices mang lại lợi ích đáng kể cho các ứng dụng web quy mô lớn, nhưng nó cũng đi kèm với những phức tạp trong việc kiểm tra, triển khai và bảo trì. Việc thực hiện thủ công là không khả thi; chính vì vậy, tự động hóa là bắt buộc do số lượng lớn dịch vụ trong các ứng dụng cấp doanh nghiệp.

Các công ty chuyển sang kiến trúc microservices cần tích hợp các công nghệ tự động hóa như GitHub, Jenkins và Terraform. Ngoài ra, nhân viên cần thành thạo kỹ năng viết script.
Việc triển khai tự động hóa một cách thống nhất và toàn diện đòi hỏi đầu tư đáng kể về thời gian và tài nguyên. Tuy nhiên, khoản đầu tư này là cần thiết để các công ty gặt hái những lợi ích từ microservices.
3. Thách thức về tích hợp và quản lý phụ thuộc
Việc chuẩn hóa trao đổi dữ liệu giữa các dịch vụ microservices đòi hỏi nỗ lực đáng kể.
Các microservices được phát triển và triển khai độc lập trong các container cô lập. Trong thời gian chạy, những microservice cô lập và độc lập này phải giao tiếp với nhau, yêu cầu tăng cường tích hợp các điểm cuối RESTful và trao đổi file JSON hoặc XML được chuẩn hóa.
Hơn nữa, việc quản lý các dependency (thành phần phụ thuộc) giữa các microservices đặt ra một thách thức đáng kể. Các điểm cuối RESTful đặc biệt dễ bị tấn công, vì sự thay đổi trong một thành phần có thể dẫn đến hậu quả không mong muốn cho các thành phần khác.
Ngược lại, trong một ứng dụng monolithic, các thành phần tương tác trực tiếp thông qua các API dựa trên Java hoặc Python, loại bỏ nhu cầu về một định dạng trao đổi dữ liệu chung hoặc API RESTful. Ngoài ra, tất cả các tương tác được kiểm tra dữ liệu và xác thực tại thời điểm compile.
4. Thách thức về việc dịch và tương thích dữ liệu
Sẽ tốt nhất nếu tất cả các microservices sử dụng cấu trúc dữ liệu và protocol đồng nhất, nhưng điều này thường không xảy ra trong thực tế. Ví dụ, có thể gặp trường hợp một microservice REST cố gắng giao tiếp với một microservice gRPC, mỗi microservice sử dụng các giao thức HTTP khác nhau. Điều này tạo ra sự không tương thích.
Một cách để giải quyết sự không tương thích này là triển khai một cơ chế dịch chuyển, như một proxy.
Việc dịch thuật dữ liệu trong các microservices cũng đi kèm với những thách thức riêng. Điều này có thể được hiểu như một ZIP code trong dịch vụ này sẽ là postal code trong dịch vụ khác.

Việc dịch ngữ cảnh dữ liệu từ lâu đã là một mối quan ngại tồn tại trong nhiều thập kỷ. Các ứng dụng monolithic giảm thiểu vấn đề này bằng cách lưu trữ tất cả dữ liệu trong một cơ sở dữ liệu duy nhất. Tuy nhiên, kiến trúc microservices làm tăng thách thức này. Với hàng chục hoặc thậm chí hàng trăm microservices trong một ứng dụng, triển khai dịch nghĩa dữ liệu giữa chúng là một trở ngại lớn.
5. Nguy cơ tắc nghẽn mạng
Các microservice giao tiếp thông qua các API RESTful và trao đổi dữ liệu định dạng JSON và XML qua giao thức HTTP. Việc sử dụng microservices thường dẫn đến lưu lượng mạng tăng cao, gây ra tắc nghẽn mạng.
Tuy nhiên, hầu hết các giao tiếp giữa các microservices diễn ra trong các subnet (mạng con) cục bộ riêng tư, nơi băng thông mạng có thể dễ dàng được mở rộng. Tuy nhiên, lượng dữ liệu lớn từ XML và JSON trên mạng góp phần tạo ra một nhược điểm khác của microservices đó là: ảnh hưởng đến hiệu suất.
6. Giảm tổng thể hiệu suất
Kiến trúc microservices thường dẫn đến mức tiêu tốn tài nguyên cao hơn so với kiến trúc monolithic có cùng quy mô. Các microservice đòi hỏi nhiều bộ nhớ hơn, tốn nhiều chu kỳ CPU hơn và cần băng thông mạng lớn hơn.
Trong một ứng dụng monolithic, tất cả các thành phần hoạt động trong một tiến trình duy nhất, các tương tác diễn ra ở cấp độ phần cứng. Các thành phần tương tác với nhau thông qua các phương thức tiêu chuẩn, dẫn đến việc tăng chi phí hiệu suất. Ngoài ra, các thành phần cùng một tiến trình có thể truy cập ngay lập tức dữ liệu được chia sẻ vì nó nằm trong bộ nhớ, giúp giảm độ trễ.
So sánh Monolithic với Microservices:
Hãy tưởng tượng sự khác biệt giữa tương tác trong một ứng dụng monolithic và tương tác giữa các microservices:

So với việc các thành phần "nói chuyện" trực tiếp trong monolithic, microservices tạo ra nhiều bước hơn, sử dụng mạng nhiều hơn, dẫn đến tăng chí phí và hiệu suất chậm hơn đáng kể.

Những nhược điểm về hiệu suất và sử dụng tài nguyên của microservices dẫn chúng ta đến bất lợi tiếp theo, đó là chi phí.
7. Chi phí cao
Khi phân rã một ứng dụng monolithic thành nhiều microservices, chúng ta sẽ gặp phải những điều sau:
- Tăng tổng dung lượng bộ nhớ.
- Tài nguyên bị trùng lặp khi sử dụng nhiều container hoặc máy ảo.
- Tiêu tốn băng thông khi gọi các dịch vụ web RESTful.
- Tăng vòng lặp CPU để gửi, phân tích, đọc và lắp ráp các tệp JSON.
Doanh nghiệp ngày nay phải trả tiền cho dịch vụ điện toán đám mây theo mức sử dụng thực tế (pay-as-you-go). Việc sử dụng CPU hoặc bộ nhớ nhiều hơn bởi một ứng dụng dẫn đến chi phí đám mây lớn hơn.
So với ứng dụng monolithic, kiến trúc microservices đòi hỏi nhiều tài nguyên hơn, dẫn đến chi phí vận hành cao hơn, đây là một nhược điểm đáng kể của microservices.
8. Sự phức tạp trong việc kiểm tra, theo dõi
Ứng dụng của cloud-native thường được triển khai trong các cụm Kubernetes nơi các container tạm thời cung cấp môi trường chạy microservices cần thiết. Tuy nhiên, tính tạm thời của microservices, đặc biệt là trên các mạng đa nút (multinode), khiến cho việc log, theo dõi và audit trở nên cực kỳ khó khăn.
Trong trường hợp container Docker chứa một microservice bị tắt, các file log sẽ bị mất ngay lập tức trừ khi một tiến trình daemon nền chuyển dữ liệu log từ container sang một vị trí lưu trữ đáng tin cậy khác. Mặc dù các công cụ như Fluentd mã nguồn mở giúp giảm thiểu vấn đề này, nhưng đây vẫn là một vấn đề đáng lo ngại.
Ngược lại, một kiến trúc monolithic thường có một thư mục duy nhất trên server để lưu trữ tất cả dữ liệu ghi log, theo dõi và audit, thường được đi kèm với cơ chế xoay vòng log tích hợp. Với một monolith, việc quản lý ghi log và theo dõi đơn giản hơn rất nhiều.
Sự nỗ lực bổ sung cần thiết để quản lý các file log, file tracing (theo dõi) và dữ liệu kiểm tra trên một cụm cloud-native là một trong những nhược điểm hàng đầu của các kiến trúc microservices.
9. Khó khắc phục sự cố và gỡ lỗi
Xác định và giải quyết các vấn đề trong kiến trúc microservices cũng phức tạp tương tự như việc tổng hợp các file theo dõi và log. Khi một yêu cầu thất bại đi qua nhiều microservice được lưu trữ trong các môi trường chạy riêng biệt, việc xác định chính xác vị trí và nguyên nhân của sự cố có thể rất khó khăn. Ngược lại, xử lý sự cố trong ứng dụng monolithic chỉ cần theo dõi đường đi của yêu cầu thất bại trên một máy chủ duy nhất.
Ngoài ra, việc sao chép lại chính xác đường đi của một yêu cầu thất bại có thể trở nên phức tạp, đặc biệt trong các môi trường mà các microservice được lưu trữ trong container thường xuyên được khởi chạy và tắt.

Gỡ lỗi Phân tán:
Gỡ lỗi cho một ứng dụng microservices cũng là một thách thức. Để theo dõi đường đi của một yêu cầu xuyên qua kiến trúc có thể bao gồm hàng trăm microservice tương tác, mỗi microservice hoạt động trong container riêng của nó, đòi hỏi phương pháp giám sát toàn diện. Mặc dù ghi log cung cấp một số thông tin chi tiết về hoạt động bên trong của microservices, nhưng việc giám sát phải cung cấp một cái nhìn toàn diện về hệ thống.
Nhiều công cụ khác nhau, bao gồm các dự án mã nguồn mở như Jaeger và Zipkin, cũng như các sản phẩm thương mại như Datadog, Dynatrace và Wavefront, đều nhằm mục đích hỗ trợ gỡ lỗi bằng cách cung cấp khả năng theo dõi phân tán. Bất kể công cụ nào, một chiến lược giám sát mạnh mẽ là không thể thiếu để quan sát cả hoạt động bên trong và bên ngoài trong các microservice cấu thành ứng dụng.
10. Trở ngại do quán tính tổ chức
Một trong những thách thức đáng kể khi triển khai microservices trong doanh nghiệp là vượt qua quán tính tổ chức.
Chuyển đổi từ kiến trúc monolithic sang microservices đòi hỏi những cam kết như: sử dụng các công cụ mới, áp dụng phương pháp phát triển tiên tiến và trang bị thêm các kỹ năng mới. Nếu không có lý do thuyết phục để áp dụng các phương pháp “cloud-native” và tái cấu trúc các hệ thống monolithic, nhiều tổ chức thấy rằng việc tuân theo các thực tiễn đã có và duy trì hệ thống monolithic hiện tại đơn giản hơn.
Tuy nhiên, những lý lẽ thuyết phục có thể vượt qua quán tính tổ chức. Nếu bộ phận IT do dự chuyển đổi từ monolithic sang microservices, điều đó có thể cho thấy những nhược điểm của microservices vượt trội hơn lợi ích của chúng - và nó hoàn toàn chấp nhận được. Không phải mọi tổ chức đều sẵn sàng hoặc cần đến mô hình "cloud-native", và kiến trúc monolithic vẫn có vai trò quan trọng trong hệ thống CNTT hiện đại.
Kết luận
Việc sử dụng Microservices mang đến nhiều lợi ích quan trọng cho các ứng dụng web như tăng tính linh hoạt, khả năng mở rộng, tăng tính ổn định, hiệu suất và giảm thiểu sự phụ thuộc giữa các thành phần của ứng dụng. Tuy nhiên, cũng có một số thách thức mà doanh nghiệp cần phải cân nhắc như đồng bộ hóa và tích hợp các microservices, chi phí phát triển, vận hành và cách giải quyết những vấn đề khi bị quá tải.
Với VNG Cloud, doanh nghiệp hoàn toàn linh hoạt trong việc lựa chọn giải pháp công nghệ phù hợp nhất cho hệ thống, nhu cầu và ngân sách của từng doanh nghiệp. Để biết thêm chi tiết về các dịch vụ trong hệ sinh thái của VNG Cloud, vui lòng liên hệ số Hotline 19001549.