Bài viết được tham khảo từ nguồn: https://www.modb.pro/db/380587
Sau năm 2020, khi các thành phần Netflix trong Spring Cloud ngừng cập nhật, Spring Cloud đã phát triển hệ thống cân bằng tải mới. Bài viết này phân tích chi tiết hai thành phần tiêu biểu là Ribbon và LoadBalancer.
So Sánh Hiện Trạng
Ribbon:
- Ở trạng thái bảo trì, vẫn được sử dụng rộng rãi nhờ hiệu năng ổn định. Tuy nhiên, từ phiên bản Spring Cloud mới nhất đã loại bỏ phụ thuộc của Ribbon.
LoadBalancer:
- Đang được Spring Cloud tích hợp mạnh mẽ. Với sự hỗ trợ của Spring WebFlux, LoadBalancer cho phép cân bằng tải với client phản ứng (reactive client).
- Hỗ trợ chiến lược cân bằng tải ngẫu nhiên và sẽ dần thay thế hoàn toàn các giải pháp cũ.
Giới Thiệu & Thực Hành Ribbon
Khái niệm cơ bản:
- Ribbon là dự án mã nguồn mở của Netflix, cung cấp cơ chế cân bằng tải phía client với các tính năng cấu hình như timeout, retry.
- Quy trình hoạt động:
- Lấy danh sách service từ trung tâm đăng ký
- Áp dụng thuật toán (round-robin, random...) để chọn instance
- Gọi service qua Feign/OpenFeign
Chiến lược cân bằng tải:
- RoundRobinRule: Luân phiên
- RandomRule: Ngẫu nhiên
- RetryRule: Thử lại khi lỗi
- WeightedResponseTimeRule: Ưu tiên instance phản hồi nhanh
- BestAvailableRule: Chọn instance có độ trễ thấp nhất
- ZoneAvoidanceRule: Mặc định, cân nhắc vùng địa lý và độ sẵn sàng
Tùy chỉnh chiến lược:
- Lớp cấu hình cần đặt ở package ngoài phạm vi quét của @ComponentScan
- Ví dụ thay thế chiến lược mặc định bằng ngẫu nhiên:
@Configuration
public class CustomRule {
@Bean
public IRule customRule() {
return new RandomRule();
}
}
- Kích hoạt tại lớp khởi động:
@RibbonClient(name = "service-payment", configuration = CustomRule.class)
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Giới Thiệu & Thực Hành LoadBalancer
Ưu điểm nổi bật:
- Hỗ trợ RestTemplate tương tự Ribbon
- Cân bằng tải cho client phản ứng thông qua WebFlux (dựa trên Netty AIO)
Cấu hình phụ thuộc:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
Tắt Ribbon mặc định:
spring:
cloud:
loadbalancer:
ribbon:
enabled: false
Ví dụ sử dụng RestTemplate:
@Configuration
public class WebClientConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
@RestController
@RequestMapping("/api")
public class ServiceController {
@Value("${service.url}")
private String serviceUrl;
@Autowired
private RestTemplate restTemplate;
@GetMapping("/get/{id}")
public ResponseEntity<?> getService(@PathVariable Long id) {
return restTemplate.getForEntity(serviceUrl + "/data/" + id, String.class);
}
}
Cân bằng tải với WebClient:
@Configuration
public class WebClientConfig {
@Bean
@LoadBalanced
public WebClient.Builder webClientBuilder() {
return WebClient.builder();
}
}
@RestController
@RequestMapping("/api")
public class ServiceController {
@Value("${service.url}")
private String serviceUrl;
@Autowired
private WebClient.Builder webClientBuilder;
@GetMapping("/webclient/{id}")
public Mono<String> getServiceWebClient(@PathVariable Long id) {
return webClientBuilder.build()
.get().uri(serviceUrl + "/data/" + id)
.retrieve().bodyToMono(String.class);
}
}
Tùy chỉnh chiến lược LoadBalancer:
@Configuration
public class RandomConfig {
@Bean
public ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(
Environment env, LoadBalancerClientFactory factory) {
String name = env.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new RandomLoadBalancer(
factory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
}
}
@SpringBootApplication
@LoadBalancerClient(value = "service-payment", configuration = RandomConfig.class)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}