Discovery pattern

Discovery pattern

Discovery Pattern là một mẫu thiết kế trong kiến trúc microservices giúp các service có thể tìm thấy và giao tiếp với nhau một cách động. Thay vì các service gọi nhau bằng địa chỉ IP cố định, Discovery Pattern cho phép các service đăng ký và tra cứu thông tin của nhau thông qua một Service Registry (cơ sở dữ liệu lưu trữ danh sách các service), giúp ứng dụng mở rộng linh hoạt mà không cần cập nhật thủ công địa chỉ của từng service.

Các thành phần trong Service Discovery

  1. Service Registry (Bộ đăng ký dịch vụ)

    • Là một cơ sở dữ liệu trung tâm chứa danh sách các service và địa chỉ của chúng.

    • Ví dụ: Eureka (Netflix), Consul (HashiCorp), Zookeeper (Apache)

  2. Service Provider (Dịch vụ cung cấp)

    • Khi một service khởi động, nó tự động đăng ký vào Service Registry.

    • Khi bị shutdown hoặc gặp lỗi, nó sẽ bị xóa khỏi registry.

  3. Service Consumer (Dịch vụ tiêu dùng)

    • Khi muốn gọi một service khác, nó tra cứu danh sách trong Service Registry để lấy địa chỉ dịch vụ.

Cơ chế hoạt động

Discovery Pattern hoạt động dựa trên các thành phần chính sau:

Service Registry (Đăng ký dịch vụ)

  • Là trung tâm lưu trữ danh sách các service, bao gồm tên service, địa chỉ IP, cổng (port)trạng thái.

  • Các service khi khởi động sẽ tự động đăng ký với registry này.

  • Ví dụ: Eureka Server (Spring Cloud), Consul, Zookeeper, etcd.

Service Registration (Dịch vụ đăng ký)

  • Mỗi microservice khi chạy lên sẽ gửi thông tin của nó đến Service Registry.

  • Khi tắt service, nó có thể tự xóa khỏi registry hoặc bị registry loại bỏ nếu không phản hồi trong một khoảng thời gian.

Service Discovery (Dịch vụ tìm kiếm)

  • Khi một service muốn gọi một service khác, nó sẽ tra cứu trong Service Registry để tìm địa chỉ của service mục tiêu.

  • Cách tra cứu có thể là Client-side Discovery hoặc Server-side Discovery.

Health Check (Kiểm tra sức khỏe)

  • Service Registry thường sẽ kiểm tra định kỳ (heartbeat) xem các service còn hoạt động không.

  • Nếu một service không phản hồi, nó sẽ bị xóa khỏi registry để tránh gọi vào các service bị lỗi.

Trường hợp sử dụng

Khi nào cần

  • Khi hệ thống có nhiều microservices động (có thể thay đổi số lượng instance theo thời gian).

  • Khi các service cần giao tiếp với nhau mà không có địa chỉ IP cố định.

  • Khi cần cân bằng tải (load balancing) động giữa các instance của một service.

  • Khi muốn có cơ chế tự động phát hiện lỗi và loại bỏ service bị lỗi.

Khi nào không cần

  • Nếu kiến trúc chỉ có 1-2 service cố định, có thể sử dụng địa chỉ IP tĩnh.

  • Nếu chỉ có một vài API Gateway làm trung gian, có thể sử dụng API Gateway thay vì Discovery Pattern.

  • Nếu dùng Kubernetes, có thể sử dụng Kubernetes Service thay vì triển khai riêng một Service Discovery.

Cách triển khai

Có 2 cách chính để triển khai Service Discovery trong microservices:

Client-side Service Discovery

Client trực tiếp truy vấn Service Registry để lấy danh sách các service khả dụng, sau đó chọn service để gửi request. Sau đó, client tự thực hiện Load Balancing và gửi request đến một instance phù hợp.

Công nghệ thường dùng:

  • Service Discovery (Eureka, Consul, Zookeeper)

  • Load Balancer trên client (Ribbon, Feign - Spring Cloud)

Ưu điểm:

  • Giảm tải cho Load Balancer trung gian.

  • Tốc độ truy vấn nhanh hơn vì không có bottleneck.

  • Linh hoạt khi chọn thuật toán load balancing (Round-robin, Least Connections, v.v.).

Nhược điểm:

  • Client phức tạp hơn vì phải quản lý logic tìm kiếm service.

  • Cần có một cơ chế cập nhật danh sách service liên tục.

Ví dụ: Spring Cloud LoadBalancer với Eureka

Cấu hình Eureka Server (application.yml)

server:
  port: 8761

eureka:
  client:
    registerWithEureka: false
    fetchRegistry: false

Cấu hình service đăng ký vào Eureka:

spring:
  application:
    name: user-service

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

Tìm service bằng Eureka Client:

@LoadBalanced
@Bean
public RestTemplate restTemplate() {
    return new RestTemplate();
}

@Autowired
private RestTemplate restTemplate;

public String getUserData() {
    return restTemplate.getForObject("http://user-service/users", String.class);
}

Khi sử dụng RestTemplate hoặc WebClient hoặc FeignClient nó sẽ tự động lấy danh sách service từ Eureka để gọi API.

Server-side Service Discovery

Client không cần biết trực tiếp địa chỉ của service. Client sẽ gửi request đến một Load Balancer trung gian (ví dụ: AWS ELB, Nginx, HAProxy), Load Balancer sẽ truy vấn Service Registry và chuyển tiếp request đến một service backend.

Công nghệ thường dùng:

  • API Gateway (Kong, Traefik, Spring Cloud Gateway, Nginx)

  • Service Mesh (Istio, Linkerd)

Ưu điểm:

  • Client đơn giản hơn, không cần biết danh sách service, không cần xử lý logic tìm kiếm service.

  • Load Balancer trung gian chịu trách nhiệm phân phối tải và tìm kiếm service.

  • Dễ kiểm soát và mở rộng hơn so với Client-side Discovery.

Nhược điểm:

  • Cần một Load Balancer trung gian do đó tăng độ trễ vì phải qua một Load Balancer trung gian.

  • Load Balancer có thể trở thành bottleneck nếu không được cấu hình đúng.

Ví dụ: AWS Auto Scaling với ELB

  • AWS ELB tự động lấy danh sách service từ EC2 Auto Scaling hoặc ECS Service Discovery.

  • Khi có service mới, nó tự động thêm vào Load Balancer mà không cần client quan tâm.

Ví dụ: Server-side Discovery với Kubernetes Service

apiVersion: v1
kind: Service
metadata:
  name: user-service
spec:
  selector:
    app: user-service
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8080
  type: ClusterIP

Client chỉ cần gọi http://user-service mà không cần biết địa chỉ cụ thể của từng Pod.

Các công cụ Service Discovery phổ biến

Công cụKiểu DiscoveryĐặc điểm chínhƯu điểmNhược điểm
Eureka (Netflix)Client-sideDùng trong Spring Cloud, hỗ trợ tự động đăng ký/xóa serviceDễ dùng với Spring BootKhông hỗ trợ DNS-based discovery
Consul (HashiCorp)Cả haiHỗ trợ health check, key-value store, DNS-based discoveryHỗ trợ DNS & Key-Value StoreCấu hình phức tạp hơn Eureka
Zookeeper (Apache)Cả haiĐược Kafka, Hadoop, HBase sử dụng để quản lý clusterHỗ trợ phân tán mạnhQuản lý phức tạp, cần ZNode
Kubernetes Service DiscoveryServer-sideTự động tạo DNS records cho mỗi service trong clusterTích hợp sẵn trong KubernetesCấu hình security phức tạp hơn
etcdServer-sideHỗ trợ gRPC và KubernetesChỉ phù hợp với hệ thống chạy Kubernetes
AWS Route 53 + ECS Service DiscoveryServer-sideKết hợp DNS-based routing với ECS servicechưa dùng ko có đánh giáchưa dùng ko có đánh giá