
Trong năm năm qua, đội ngũ của chúng tôi đã đưa hơn năm mươi hệ thống microservices vào production trên nền Go và Kubernetes. Kiến trúc này đã trưởng thành từ "Docker container kèm vài shell script" thành một bộ công nghệ khá rõ chủ kiến mà giờ chúng tôi chọn mặc định. Bài viết đi qua các quyết định thiết kế, những đánh đổi chúng tôi chấp nhận và những mẫu thiết kế mà chúng tôi đã phải trả giá mới học được để tránh.
Ranh giới service
Quyết định quan trọng nhất trong bất kỳ hệ thống microservices nào là vạch ranh giới giữa các service ở đâu. Vạch sai thì không hạ tầng khéo léo nào cứu được bạn. Vạch đúng thì hầu hết các vấn đề còn lại đều trở nên giải quyết được.
Nguyên tắc kinh nghiệm của chúng tôi: một service nên sở hữu một năng lực nghiệp vụ có ranh giới rõ ràng và một data store. Nếu hai service cùng cần ghi vào một bảng, chúng thực chất là một service. Nếu một service ghi vào ba data store mà giữa chúng không có quan hệ giao dịch nào, nhiều khả năng đó là ba service.
Mẫu giao tiếp
Với các lời gọi đồng bộ giữa service, chúng tôi dùng gRPC. Với sự kiện bất đồng bộ, chúng tôi dùng Kafka. Chúng tôi chủ động tránh REST giữa các service nội bộ — không phải vì REST kém, mà vì gRPC cho sẵn schema có phiên bản, client sinh tự động từ code và ngữ nghĩa streaming rõ ràng.
Một lỗi thường gặp trong hệ thống microservices là fan-out đồng bộ không giới hạn. Service A gọi B, B gọi C, C gọi D. Khi D chậm lại, cả chuỗi phụ thuộc bị treo theo. Có hai mẫu giúp ích ở đây:
- Đặt deadline chặt phía client cho mọi lời gọi gRPC và truyền deadline đó xuyên suốt chuỗi.
- Đưa mọi bước không quan trọng ra khỏi luồng xử lý request và chuyển sang Kafka, với một consumer riêng có thể tự retry độc lập.
- Dùng circuit breaker ở mọi ranh giới service — chúng tôi dùng thư viện sony/gobreaker và chưa bao giờ hối tiếc.
- Cache mạnh tay cho các luồng đọc, với TTL đủ ngắn để dữ liệu cũ chấp nhận được.
Mô hình triển khai
Chúng tôi deploy trên Kubernetes, mỗi môi trường một namespace, mỗi microservice là một deployment riêng. Chúng tôi dè dặt với operator — hầu hết service chỉ cần các primitive chuẩn (Deployment, Service, ConfigMap, Secret, HPA), và chúng tôi kìm lại ý muốn thêm CRD tùy biến, trừ khi gánh nặng vận hành do KHÔNG có chúng đã được chứng minh là lớn.
Observability mang lại giá trị thật
Ba luồng dữ liệu đều quan trọng: metrics, logs và traces. Chúng tôi instrument mọi phương thức gRPC và mọi Kafka consumer bằng OpenTelemetry. Metrics đổ về Prometheus, traces về Grafana Tempo, logs về Loki. Góc nhìn tổng hợp trong Grafana cho phép kỹ sư theo dõi một request đi qua sáu service trên cùng một dòng thời gian.
Khoản đầu tư observability có tác động lớn nhất của chúng tôi là buộc mọi service phải mở một endpoint /healthz thực sự kiểm tra các phụ thuộc (ping database, độ trễ của Kafka consumer, ping gRPC downstream) thay vì chỉ trả về 200. Việc này đã kéo thời gian phát hiện sự cố trung bình của chúng tôi từ 14 phút xuống còn 3 phút.
Graceful degradation
Khi một service downstream hỏng, câu hỏi không phải là "làm sao để vẫn chạy như chưa có chuyện gì" — điều đó hiếm khi làm được — mà là "thất bại êm nhẹ nhỏ nhất mà chúng ta có thể đưa đến người dùng là gì".
Với trang chi tiết sản phẩm, đó có thể là hiển thị mọi thứ trừ mô-đun gợi ý cá nhân hóa khi service gợi ý đang ngừng hoạt động. Với luồng thanh toán, đó có thể là nhận đơn hàng khi bước kiểm tra gian lận bị trễ, rồi trả kết quả bất đồng bộ sau. Mỗi đội nên giữ một danh sách bằng văn bản về các chế độ suy giảm của từng service.
Distributed systems are not hard because the technology is hard. They are hard because the failure modes compound and most of them are invisible until they bite you. Plan for failure, observe everything, degrade gracefully.
Lời kết
Không có kiến trúc microservices "đúng" tuyệt đối. Chỉ có kiến trúc phù hợp với tổ chức, miền nghiệp vụ và mức độ trưởng thành vận hành của bạn. Các mẫu nêu trên đã phục vụ chúng tôi tốt với các khách hàng thương mại điện tử, fintech và logistics — nhưng điều quan trọng nhất chúng tôi rút ra là ranh giới phải đi theo nghiệp vụ, không phải theo công nghệ. Khi còn phân vân, hãy vạch ranh giới ở nơi các đội vốn đã vạch.
Cần hỗ trợ về chủ đề này?
Các dịch vụ của iPlus liên quan nhất đến bài viết.


