在 Java Spring Boot 微服务中,实现客户端负载平衡主要有以下几种方式,通常结合服务发现(如 Eureka)来动态获取服务实例,然后通过客户端(服务调用方)在多个实例间分发请求,从而实现负载均衡。
1. 通过 Ribbon 实现客户端负载均衡(传统方案)
-
Ribbon 是 ***flix 提供的客户端负载均衡器,集成在 Spring Cloud ***flix 生态中。
-
Ribbon 在客户端维护服务实例列表,从 Eureka 等注册中心获取服务实例。
-
调用方(客户端)在多个实例中选择一个(轮询、随机等策略),实现负载均衡。
典型用法:
@Bean
@LoadBalanced // 开启负载均衡
public RestTemplate restTemplate() {
return new RestTemplate();
}
然后通过 RestTemplate 访问时,URL 中用服务名代替具体地址:
restTemplate.getForObject("http://product-service/products/1", Product.class);
Ribbon 会自动根据服务名从 Eureka 获取实例,并负载均衡分发请求。
2. 通过 Spring Cloud LoadBalancer(Ribbon 继任者)
Spring Cloud LoadBalancer 是 Spring 官方推出的客户端负载均衡器,替代 Ribbon。
默认支持多种负载均衡策略,且更轻量,集成更好。
用法与 Ribbon 类似,注解 @LoadBalanced 一样支持。
示例:
@Bean
@LoadBalanced
public WebClient.Builder webClientBuilder() {
return WebClient.builder();
}
或者:
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
调用时同样用服务名:
webClientBuilder.build()
.get()
.uri("http://product-service/products/1")
.retrieve()
.bodyToMono(Product.class);
3. 使用 FeignClient 自带的负载均衡
Feign 是声明式 REST 客户端,集成 Ribbon 或 Spring Cloud LoadBalancer 实现负载均衡。
只需声明接口,自动根据服务名调用,自动负载均衡。
示例:
@FeignClient(name = "product-service")
public interface ProductClient {
@GetMapping("/products/{id}")
Product getProduct(@PathVariable("id") String id);
}
调用时,Feign 会自动从 Eureka 获取实例,负载均衡请求。
4. 负载均衡策略示例
Ribbon 和 Spring Cloud LoadBalancer 支持多种策略:
轮询(Round Robin) — 依次选择实例
随机(Random) — 随机选择实例
权重(Weighted) — 根据权重选择实例
响应时间(Response Time Weighted) — 根据实例响应速度调整权重
配置示例(application.yml):
product-service:
ribbon:
NFLoadBalancerRuleClassName: ***.***flix.loadbalancer.RandomRule
Spring Cloud LoadBalancer 也支持通过配置或自定义策略。
5. 总结
| 方案 | 说明 | 推荐程度 |
|---|---|---|
| Ribbon + Eureka | ***flix 经典方案,功能强大,但维护已减弱 | 传统项目仍常用 |
| Spring Cloud LoadBalancer | 官方推荐,轻量,未来趋势 | 新项目首选 |
| Feign + Ribbon/LoadBalancer | 声明式调用,集成负载均衡最简便 | 推荐,开发效率高 |
示例一:Spring Boot + Eureka + RestTemplate + Ribbon 负载均衡完整示例
1. RestTemplate 配置启用负载均衡
@Configuration
public class RestTemplateConfig {
@Bean
@LoadBalanced // Ribbon负载均衡开启
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
2. 服务调用示例(Order Service 调用 Product Service)
@Service
public class ProductClient {
private final RestTemplate restTemplate;
public ProductClient(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public Product getProductById(String id) {
// 这里用服务名,不用写具体IP和端口,Ribbon自动负载均衡
String url = "http://product-service/products/" + id;
return restTemplate.getForObject(url, Product.class);
}
}
3. application.yml 示例
spring:
application:
name: order-service
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
4. Ribbon 默认策略(轮询)
Ribbon 默认是轮询,可以用如下配置改成随机:
product-service:
ribbon:
NFLoadBalancerRuleClassName: ***.***flix.loadbalancer.RandomRule
示例二:Spring Boot + Eureka + OpenFeign + Spring Cloud LoadBalancer 负载均衡完整示例
1. 启用 Feign 和负载均衡
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
2. 定义 Feign Client
@FeignClient(name = "product-service")
public interface ProductClient {
@GetMapping("/products/{id}")
Product getProductById(@PathVariable("id") String id);
}
3. 服务调用示例
@Service
public class OrderService {
private final ProductClient productClient;
public OrderService(ProductClient productClient) {
this.productClient = productClient;
}
public Product getProduct(String id) {
return productClient.getProductById(id);
}
}
4. application.yml 示例
spring:
application:
name: order-service
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
5. Spring Cloud LoadBalancer 负载均衡策略配置示例(随机策略)
spring:
cloud:
loadbalancer:
ribbon:
enabled: false # 关闭 Ribbon
retry:
enabled: true
loadbalancer:
rule:
name: RandomLoadBalancer
总结
| 技术 | 负载均衡实现 | 适用场景 |
|---|---|---|
| RestTemplate | Ribbon + @LoadBalanced | 传统同步调用 |
| Feign Client | Spring Cloud LoadBalancer | 声明式接口调用,简洁且易扩展 |