phần 1, chúng ta đã tìm hiểu về 3 trong số 11 thành phần quan trọng trong kiến trúc microservices bao gồm: Container & Orchestration, API Gateway, Service Discovery. Những thành phần còn lại là gì? Hãy cùng khám phá tiếp trong bài viết này.

Service Mesh

Thuật ngữ Service mesh xuất hiện trong bối cảnh cùng với cloud application, containers và microservices. Trong hệ thống microservices, khi có nhiều dịch vụ và instance runtime được sinh ra, việc kiểm soát communication giữa các dịch vụ trở nên rất khó khăn, nếu không có giải pháp hay công cụ hỗ trợ, nhà phát triển hoàn toàn phải kiểm soát communication bằng cách thủ công bắt đầu từ việc liệt kê connection giữa các dịch vụ. Các nhu cầu bao gồm kiểm soát connection giữa các dịch vụ, lượng traffic phát sinh, metric và monitoring… Service mesh sẽ giải quyết vấn đề này, nhà phát triển chỉ cần tập trung vào các vấn đề của business. Layer quản lý connection trong mạng lưới dịch vụ phân tán sẽ trở nên transparent với code business.

Service mesh sử dụng sidecar pattern, pattern này hoạt động với nguyên lý tạo ra một proxy-container bên cạnh các container instance của dịch vụ, proxy container này sẽ định tuyến traffic tới các proxy-container của dịch vụ khác, nhờ đó handle được các connection mà không can thiệp tới hoạt động của container chính.

Load Balancing

Số lượng request đến hệ thống có thể thay đổi theo lượng sử dụng của người dùng, ví dụ như: theo các ngày đặc biệt trong năm, chương trình khuyến mãi hay các sự kiện tập trung nhiều truy cập… Lúc này hệ thống có thể lựa chọn phương án tăng thêm tài nguyên CPU/RAM (Vertical scaling) hoặc sẽ tạo ra thêm các instance (horizontal scaling) để đáp ứng tải. Với phương án horizontal scaling, hệ thống cần một thành phần để điều phối request tới các instance của cùng một dịch vụ. Việc điều phối này cần phải linh hoạt theo nhiều tiêu chí để đáp ứng được các bài toán thực tế chứ không phải chỉ là lần lượt chia đều tải trên số lượng instance. Load balancer chính là thành phần này. Không chỉ giúp tối ưu hóa xử lý compute, tăng tính ổn định và tin cậy, giảm độ trễ của hệ thống, Load balancer có thể phân phối tải đều tới tất cả các instance trên các node đang được triển khai. Thuật ngữ load balancing không chỉ ở trong phạm vi công nghệ container mà với công nghệ Virtual Machine cũng tương tự, ở đây thay vì phân phối tải tới các container thì load balancer sẽ phân phối tải tới các máy VM trong cùng một group.

Circuit Breaker

Đây là cơ chế giúp ngăn ngừa các lỗi có thể xảy ra khi request gửi đến một instance mà ko có phản hồi hoặc có tín hiệu unavailable. Service client khi request tới một service khác nên gọi qua một proxy có chức năng tương tự như một cầu dao diện (circuit break). Khi số lượng request thất bại liên tục đạt tới một ngưỡng, kết nối sẽ bị ngắt hoàn toàn ngay từ proxy. Khi kết nối bị ngắt, các request tới dịch vụ đích sẽ bị từ chối ngay lập tức. Sau một khoảng thời gian, một số lượng request test nhất định được phép đi qua, nếu những request này thành công thì cầu dao sẽ được đóng lại và khôi phục kết nối, còn ngược lại, một chu kì lỗi timeout sẽ tiếp tục diễn ra. Quá trình này giúp tránh những trường hợp như dịch vụ vừa khôi phục đã phải nhận một lượng lớn request, dẫn đến hệ thống tiếp tục bị treo, không thể phục hồi hoàn toàn.

Pattern này tạo điều kiện cho dịch vụ tự khôi phục và không xảy ra quá nhiều lỗi trên dịch vụ đích. Quá trình hoạt động của circuit break được tóm tắt qua 3 trạng thái: Closed State (Trạng thái ngắt), Open state (Trạng thái mở), Half-Open State (Trạng thái test).

Centralized Logging

Logging luôn luôn là yêu cầu cần thiết cho bất cứ hệ thống nào, chức năng phục vụ cho tracing dữ liệu, debugging và troubleshooting ứng dụng. Nhưng với sự phức tạp của hệ thống microservices, log đến từ hàng chục đến hàng trăm instance với các định dạng log của các ngôn ngữ khác nhau, debugging trở nên thật sự khó khăn. Nhà phát triển không thể access vào console log của từng ứng dụng và kéo hàng nghìn dòng log để tìm kiếm thứ mình cần. Khó khăn còn đến từ multiple instance của mỗi dịch vụ, người dùng không thể biết exception vừa bắn ra từ hệ thống đến từ instance nào. Việc logging từ ứng dụng container cũng trở nên khó khăn hơn từ Máy chủ ảo do nguồn phát sinh log đã trở nên đa dạng và phức tạp hơn rất nhiều.

Ý tưởng cho việc logging cần dễ dàng cho việc truy cập, lưu được theo retention dài, da dạng các chỉ số index cho việc tìm kiếm từ log (xuất phát từ dịch vụ nào, thời gian, nội dung, token, session, URL…). Việc lưu trữ và truy xuất cũng cần tập trung thay vì rải rác trên các dịch vụ hoặc thành phần khác nhau. Các công cụ phổ biến như ELK, EFK hay Splunk là ý tưởng cho việc tìm kiếm, lọc và query log. Trước đó còn cần có bước chuẩn hóa định dạng log trước khi đẩy dữ liệu vào các công cụ tìm kiếm.

Monitoring and Alert

Các thành phần hạ tầng của một hệ thống bao gồm CPU, RAM, Storage và Bandwidth

Thành phần này thường không được chú trọng trong thời gian đầu phát triển hệ thống, nhưng khi hệ thống đã đi vào hoạt động thì lại thực sự cần thiết. Monitoring là tính năng cho phép quản trị viên và nhà phát triển có thể theo dõi sức khỏe hệ thống realtime hoặc tổng hợp lại theo các khoảng thời gian (giờ, ngày, tháng, năm), từ đó có thể tracing các issue của hệ thống như bị tấn công, các function chưa tối ưu, thiếu tài nguyên (CPU/Ram/Storage/Bandwidth).

Alert cho phép người dùng cài đặt các mức cảnh báo hoặc các cài đặt về healthcheck sau đó gửi cảnh báo đến người dùng (Email, Slack, Discord…) cho phép người dùng nhận biết được sớm các vấn đề mà hệ thống đang gặp phải, từ đó đưa ra các quyết định phù hợp để giữ hệ thống hoạt động ổn định.

Tránh gặp phải các tính trạng như hệ thống bị treo do hết ram/cpu hoặc quá nhiều người truy cập dẫn đến bottle neck hay database lưu trữ hết dung lượng khiến hệ thống gặp lỗi…

Các giải pháp phục vụ cho Monitoring và Alert có thể kể đến: Prometheus, Grafana

Messaging System

Messaging phục vụ nhu cầu giao tiếp giữa các dịch vụ. Do kiến trúc microservices dựa trên sự phân tán, giao tiếp point to point sẽ gặp một số issue: các request có thể bị mất do lỗi logic code, network latency, service downtime… Bạn có thể đã từng nghe đến Message Queue và Message Broker.

Message Queue đảm bảo dữ liệu sẽ không bị mất trong các trường hợp kể trên, ngoài ra chức năng cơ bản nhất của Message Queue là vận chuyển dữ liệu đến các client/consumer đúng thứ tự như khi chúng được ghi vào queue (FIFO).

Message Broker được thiết kế để duy trì message cho đến khi consumer/subscribe có thể nhận được dữ liệu. Điều đó có nghĩa là Messaging system giúp giảm effort rất nhiều cho nhà phát triển khi không phải xử lý các vấn đề như message translation, message validation, topic/channel ACL, routing message từ producer đến consummer, đảm bảo tính persistence, vận chuyển và streaming dữ liệu… mà chỉ cần tập trung vào code business. Ngay cả với các hệ thống không dựa trên kiến trúc microservices thì Message Broker cũng là một thành phần phổ biến và có nhiều tác dụng.

Các giải pháp cho Messaging trong hệ thống microservice: Kakfa, RabbitMP, Active MQ

Single Page Application

Single Page Application ít được chú ý nhưng cũng rất phổ biến trong kiến trúc microservices. Đây là thành phần thuộc lớp ứng dụng frontend. Giống như sự tương thích giữa Container với microservices, SPA cũng phát triển và phù hợp với hệ sinh thái microservices. Thay vì render tất cả HTML DOM từ phía server như các công nghệ đã có từ lâu (Spring MVC, PHP, Java Servlet, ASP.NET MVC…), SPA chỉ trả về các resource và code logic, hầu hết được đóng gói trong các file .js, từ đó kết hợp với các dữ liệu để render ra HTML theo behavior của người dùng ngay trên client browser (client side rendering).

SPA được xây dựng dựa trên các component, vừa tăng tính tái sử dụng code, từ đó tăng tốc độ phát triển ứng dụng. Đi cùng với SPA thường là Rest API giúp giao tiếp với phía server. Với SPA, người dùng sẽ có trải nghiệm ứng dụng mượt mà, giảm thời gian tải trang giữa các lần truy cập và cũng giảm tải cho phía server. SPA cũng giúp tách riêng việc phát triển UI ứng dụng và xử lý logic backend phía sau, tăng tốc phát triển của dự án.

Các công nghệ SPA phổ biến: Angular, React, Vue.js

Configuration Server

Một hệ thống microservices chạy trên rất nhiều container, các container này lại cần rất nhiều cấu hình để phục vụ CI/CD hoặc runtime. Configuration server sẽ có tác dụng lưu trữ tập trung các dữ liệu cấu hình và có thể được truy cập từ các service hoặc các thành phần khác của hệ thống. Giải pháp lưu trữ tập trung cấu hình ngoài việc đảm bảo việc dễ dàng truy cập dữ liệu từ các service còn giải quyết những vấn đề xung quanh như ACL, Versioning dữ liệu, grouping by project/environment…

Kết

Bài viết đã đề cập đến các thành phần của kiến trúc Microservices và tầm quan trọng của mỗi thành phần. Nhìn nhận ở một góc độ khác, hầu hết các thành phần của hệ thống phân tán lại có chức năng quản lý tập trung và kết nối các dịch vụ, đây chính là điểm khác biệt giúp bù đắp lại những issue của kiến trúc microservices so với monolithic. Chúng ta sẽ đi sâu vào mỗi thành phần và cách sử dụng các thành phần trên lý thuyết và cả thực tế ở những bài viết sau.