Cân Bằng Tải Client-Side Với Ribbon Trong Spring Cloud

Ribbon là một thư viện cân bằng tải phía máy khách mạnh mẽ, cung cấp khả năng kiểm soát toàn diện đối với hành vi của các máy khách HTTP và TCP. Trong môi trường Spring Cloud, Ribbon đóng vai trò cốt yếu trong việc phân phối yêu cầu giữa nhiều phiên bản của một dịch vụ. Bài viết này sẽ hướng dẫn cách tích hợp và cấu hình Ribbon để cân bằng tải cho các dịch vụ được gọi thông qua Feign.

Cấu hình Dịch vụ Cung cấp (Service Provider)

Để minh họa khả năng cân bằng tải của Ribbon, chúng ta cần có ít nhất hai phiên bản của cùng một dịch vụ cung cấp. Các phiên bản này sẽ có cùng tên ứng dụng (spring.application.name) nhưng hoạt động trên các cổng khác nhau.

Thêm Dependency Maven

Thêm dependency spring-cloud-starter-netflix-ribbon vào tệp pom.xml của dịch vụ cung cấp:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>

Thiết lập Cấu hình Ribbon

Để tùy chỉnh chiến lược cân bằng tải của Ribbon, chúng ta có thể định nghĩa một lớp cấu hình riêng. Trong ví dụ này, chúng ta sẽ sử dụng RoundRobinRule để luân phiên chọn máy chủ, thay vì RandomRule như mặc định hoặc các chiến lược khác.

Tạo một lớp cấu hình, ví dụ LoadBalancerConfiguration, và sử dụng annotation @RibbonClient trên lớp ứng dụng chính để liên kết nó:

@EnableEurekaClient
@RibbonClient(name = "resource-service", configuration = LoadBalancerConfiguration.class)
@SpringBootApplication
public class ResourceServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(ResourceServiceApplication.class, args);
    }
}

@Configuration
class LoadBalancerConfiguration {

    @Bean
    public IRule loadBalancingRule(){
        return new RoundRobinRule(); // Chiến lược: Chọn máy chủ theo cơ chế luân phiên
        // return new RandomRule(); // Chiến lược: Chọn ngẫu nhiên một máy chủ
        // return new BestAvailableRule(); // Chiến lược: Chọn máy chủ có ít yêu cầu đồng thời nhất
        // return new WeightedResponseTimeRule(); // Chiến lược: Chọn máy chủ dựa trên thời gian phản hồi
        // return new ZoneAvoidanceRule(); // Chiến lược: Chọn máy chủ dựa trên hiệu suất khu vực và tính khả dụng
        // return new RetryRule(); // Chiến lược: Thêm cơ chế thử lại cho chiến lược cân bằng tải đã chọn
    }

    @Bean
    public IPing servicePingStrategy() {
        return new PingUrl(); // Cơ chế kiểm tra sức khỏe dịch vụ bằng cách ping URL
    }

    @Bean
    public ServerListSubsetFilter instanceListFilter() {
        return new ServerListSubsetFilter(); // Lọc danh sách máy chủ khả dụng
    }
}

Lưu ý: Nếu bạn gặp lỗi xung đột tên bean (ví dụ: với các thư viện khác), hãy đổi tên phương thức bean của bạn (ví dụ: từ ribbonRule thành loadBalancingRule) để tránh vấn đề.

Tạo Endpoint API Dịch vụ

Thêm một API đơn giản vào dịch vụ cung cấp để kiểm tra. API này sẽ trả về thông tin về cổng mà nó đang hoạt động, giúp chúng ta dễ dàng quan sát hiệu quả cân bằng tải.

@RestController
@RequestMapping("/api/resource")
public class ResourceController {

    @GetMapping("/info")
    public String getServiceInfo() {
        return "Dịch vụ tài nguyên - Cổng hoạt động: " + System.getProperty("server.port");
    }
}

Đảm bảo rằng bạn khởi chạy nhiều phiên bản của dịch vụ này với cùng tên ứng dụng (ví dụ: resource-service) nhưng trên các cổng khác nhau (ví dụ: 8081, 8082).

Cấu hình Dịch vụ Tiêu thụ (Service Consumer)

Khi sử dụng Feign client, việc cân bằng tải với Ribbon diễn ra một cách minh bạch. Feign đã tích hợp sẵn Ribbon, nên bạn không cần thực hiện thêm bất kỳ cấu hình Ribbon cụ thể nào trên phía dịch vụ tiêu thụ.

Định nghĩa Feign Client

Tạo một interface Feign client để gọi dịch vụ tài nguyên. Đảm bảo tên dịch vụ trong @FeignClient khớp với tên ứng dụng của dịch vụ cung cấp (resource-service).

@FeignClient(name = "resource-service", path = "/api/resource")
public interface ResourceServiceProxy {

    @GetMapping("/info")
    String getResourceInfo();
}

Gọi Dịch vụ Từ Consumer Controller

Sử dụng Feign client này trong một controller của dịch vụ tiêu thụ:

@RestController
@RequestMapping("/api/consumer")
public class ConsumerController {

    private final ResourceServiceProxy resourceServiceProxy;

    public ConsumerController(ResourceServiceProxy resourceServiceProxy) {
        this.resourceServiceProxy = resourceServiceProxy;
    }

    /**
     * Gọi dịch vụ tài nguyên thông qua Feign (sử dụng Ribbon để cân bằng tải)
     */
    @GetMapping("/loadbalance/info")
    public String retrieveLoadBalancedInfo(){
        return resourceServiceProxy.getResourceInfo();
    }
}

Kiểm tra và Xác nhận Kết quả

Sau khi khởi chạy tất cả các dịch vụ (Eureka Server, nhiều phiên bản của resource-service, và consumer-service), hãy liên tục gửi yêu cầu đến endpoint /api/consumer/loadbalance/info của dịch vụ tiêu thụ. Bạn sẽ quan sát thấy rằng các phản hồi trả về từ dịch vụ cung cấp sẽ luân phiên hiển thị các cổng khác nhau (ví dụ: 8081, 8082, 8081, 8082...), chứng tỏ rằng Ribbon đang hoạt động hiệu quả trong việc phân phối yêu cầu giữa các phiên bản dịch vụ.

Thẻ: Spring Cloud ribbon Load Balancing Feign Microservices

Đăng vào ngày 22 tháng 7 lúc 01:31