0

[Microservices Series] Bài 8: Service Discovery – "Bản đồ sống" dò đường trong sương mù Microservices

Chào anh em, mình đây! Ở cuối bài 7, chúng ta đã dựng xong API Gateway làm người gác cổng vững chắc. Nhưng có một lỗ hổng logic rất lớn mà anh em tinh ý sẽ nhận ra: API Gateway làm sao biết IP của các service bên trong để mà forward request tới?

Trong thời đại của Monolith và máy chủ vật lý, anh em cứ mở file nginx.conf lên, hardcode cái IP 192.168.1.10 vào là xong, chạy 5 năm không đổi. Nhưng ở thế giới Microservices, đặc biệt là khi anh em chạy trên Docker Swarm hay Kubernetes, mọi thứ mong manh như trò chơi xếp hình.

Một container có thể "chết" bất đắc kỳ tử vì hết RAM, rồi một container mới toanh tự động được sinh ra để thay thế... với một địa chỉ IP hoàn toàn mới. Nếu Gateway vẫn mù quáng gửi request vào cái IP cũ, hệ thống sẽ trả về lỗi 502 Bad Gateway ngay lập tức.

Để giải quyết bài toán "IP động" này, chúng ta cần một công cụ mang tên: Service Discovery.

1. Service Discovery hoạt động như thế nào?

Anh em cứ tưởng tượng Service Discovery giống như một cuốn Danh bạ điện thoại sống (Service Registry) kết hợp với một ông tổng đài viên. Nó gồm 2 quá trình cốt lõi:

Bước 1: Báo danh (Service Registration) Khi một service mới được khởi động (ví dụ: Service Mua Vé chạy ở IP 10.0.0.5), việc đầu tiên nó làm không phải là phục vụ user, mà là chạy đến báo cáo với cuốn Danh bạ (Registry):

"Chào sếp, em là Service Mua Vé, em đang sống ở địa chỉ IP 10.0.0.5, port 8080".

Cuốn danh bạ ghi nhận lại. Và để chứng minh mình còn sống, cứ mỗi 5 giây, Service Mua Vé phải gửi một tín hiệu Heartbeat (Nhịp tim) lên danh bạ. Nếu quá 15 giây mà không thấy nhịp tim đập, danh bạ sẽ tự động gạch tên IP 10.0.0.5 ra khỏi danh sách vì mặc định container đó đã "tử nạn".

Bước 2: Tìm đường (Service Discovery) Bây giờ, API Gateway nhận được một request cần chuyển cho Service Mua Vé. Thay vì tìm IP tĩnh, Gateway sẽ hỏi cuốn Danh bạ:

"Cho xin danh sách các IP của Service Mua Vé đang còn sống!"

Danh bạ trả về một mảng: [10.0.0.5, 10.0.0.8, 10.0.0.9]. Gateway lúc này chỉ việc bốc đại một cái IP trong đó (thường áp dụng thuật toán Load Balancing như Round Robin) và forward request đi.

2. Thực chiến tại tuyến Metro số 1

Giả sử vào giờ cao điểm buổi sáng tại tuyến Metro, lượng khách đổ về các ga trung tâm tăng đột biến.

Hệ thống giám sát phát hiện Service Cổng Soát Vé (Gate) đang bị quá tải CPU. Ngay lập tức, cơ chế Auto-scaling tự động nhân bản (scale up) Gate Service từ 5 containers lên 20 containers để gồng gánh lượng khách.

  • Nếu không có Service Discovery: Mình hoặc anh em team vận hành sẽ phải hộc tốc lôi file config của Gateway ra, gõ tay thêm 15 cái IP mới vào, rồi reload lại Nginx. Tới lúc cấu hình xong thì chắc khách đã làm loạn ở nhà ga.

  • Khi có Service Discovery (như Consul hoặc Kubernetes Service): 15 containers Gate mới vừa boot lên thành công sẽ tự động "hét lên" và ghi danh vào Registry. API Gateway tự động nhận được danh sách IP mới cập nhật này trong tích tắc và bắt đầu chia đều traffic sang 20 containers một cách mượt mà.

Đến trưa, hết giờ cao điểm, 15 containers thừa bị kill đi. Chúng ngừng phát Heartbeat, Registry tự xóa tên, và Gateway tự động ngừng gửi request tới những IP đã chết. Mọi thứ diễn ra tự động hoàn toàn (Zero-touch).

Lời khuyên "xương máu"

  • Đừng tự code lại bánh xe: Hãy dùng các công cụ đã được thế giới kiểm chứng. Nếu anh em deploy bằng Docker/VM trần, hãy dùng HashiCorp Consul hoặc Netflix Eureka. Nếu anh em dùng Kubernetes, thì chúc mừng, K8s đã tích hợp sẵn cơ chế Service Discovery cực kỳ hoàn hảo ở tầng DNS (CoreDNS) rồi, anh em gần như không phải config gì phức tạp.

  • Health Check (Kiểm tra sức khỏe) là mạng sống: Đừng chỉ để Registry ping xem port của service có mở hay không. Hãy code một API /health đàng hoàng. Nhiều khi port vẫn mở (Network OK), nhưng Database chết khiến service bị treo. Nếu Health check không kiểm tra cả connection DB, Registry vẫn tưởng service đó khỏe mạnh và tống traffic vào, dẫn đến rớt toàn bộ request.

Tạm kết

Đến bài này, chúng ta đã có một kiến trúc mạng khá hoàn chỉnh: Các service biết cách gọi nhau (gRPC/Message Broker), biết cách tự bảo vệ (Circuit Breaker), có cửa ngõ an toàn (API Gateway) và có bản đồ tự động dò đường (Service Discovery).

Nhưng khoan đã, mọi thứ vẫn chỉ là bề nổi của request. Còn dữ liệu (Database) thì sao?

Trong Monolith, khi khách nạp tiền thẻ, anh em dùng DB::transaction() để update bảng số dư và ghi log giao dịch trong cùng 1 database, lỗi thì Rollback phát là xong. Nhưng ở Microservices, Service Wallet giữ database riêng, Service Transaction giữ database riêng. Lỡ Update Wallet thành công mà Transaction báo lỗi rớt mạng thì sao? Tiền của khách đi về đâu?

Ở bài tiếp theo (Bài 9), chúng ta sẽ bước vào vùng nước sâu nhất và đau đầu nhất của Microservices: Distributed Transactions & Saga Pattern – Bài toán giữ tính nhất quán dữ liệu phân tán.

Anh em đang dùng công cụ Service Discovery nào cho dự án hiện tại? Quá trình scale up hệ thống của team anh em đang là chạy tự động hay vẫn phải "chạy bằng cơm"? Cùng thảo luận dưới phần comment nhé!


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí