负载均衡 #

一、负载均衡概述 #

1.1 什么是负载均衡 #

负载均衡是将请求分发到多个服务实例的机制,提高系统的吞吐量和可用性。

text
┌─────────────────────────────────────────────────────────────┐
│                    负载均衡架构                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   ┌─────────────┐                                          │
│   │   客户端    │                                          │
│   └──────┬──────┘                                          │
│          │                                                  │
│          ▼                                                  │
│   ┌─────────────────────────────────────────────────────┐  │
│   │              负载均衡器                               │  │
│   │                                                      │  │
│   │   ┌─────────┐  ┌─────────┐  ┌─────────┐            │  │
│   │   │ Round   │  │ Random  │  │ Weighted│            │  │
│   │   │ Robin   │  │         │  │         │            │  │
│   │   └─────────┘  └─────────┘  └─────────┘            │  │
│   │                                                      │  │
│   └─────────────────────────────────────────────────────┘  │
│          │                                                  │
│          ├──────────────────┬──────────────────┐           │
│          │                  │                  │           │
│          ▼                  ▼                  ▼           │
│   ┌─────────────┐   ┌─────────────┐   ┌─────────────┐     │
│   │  实例 1     │   │  实例 2     │   │  实例 3     │     │
│   │  :8001     │   │  :8002     │   │  :8003     │     │
│   └─────────────┘   └─────────────┘   └─────────────┘     │
│                                                             │
└─────────────────────────────────────────────────────────────┘

1.2 负载均衡分类 #

类型 说明 典型实现
服务端负载均衡 独立的负载均衡服务器 Nginx、F5、HAProxy
客户端负载均衡 客户端内置负载均衡 Ribbon、LoadBalancer

1.3 LoadBalancer vs Ribbon #

特性 LoadBalancer Ribbon
维护状态 活跃 维护模式
响应式 支持 不支持
缓存 支持 不支持
健康检查 支持 支持

二、基本使用 #

2.1 添加依赖 #

xml
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>

2.2 RestTemplate集成 #

java
@Configuration
public class RestTemplateConfig {

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

2.3 使用RestTemplate #

java
@Service
public class UserService {

    @Autowired
    private RestTemplate restTemplate;

    public User getUser(Long id) {
        String url = "http://user-service/users/" + id;
        return restTemplate.getForObject(url, User.class);
    }
}

2.4 WebClient集成 #

xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
java
@Configuration
public class WebClientConfig {

    @Bean
    @LoadBalanced
    public WebClient.Builder webClientBuilder() {
        return WebClient.builder();
    }
}
java
@Service
public class UserService {

    @Autowired
    private WebClient.Builder webClientBuilder;

    public Mono<User> getUser(Long id) {
        return webClientBuilder.build()
                .get()
                .uri("http://user-service/users/{id}", id)
                .retrieve()
                .bodyToMono(User.class);
    }
}

三、负载均衡策略 #

3.1 内置策略 #

策略 类名 说明
轮询 RoundRobinLoadBalancer 按顺序选择(默认)
随机 RandomLoadBalancer 随机选择

3.2 配置轮询策略(默认) #

yaml
spring:
  cloud:
    loadbalancer:
      ribbon:
        enabled: false

3.3 配置随机策略 #

java
@Configuration
public class LoadBalancerConfig {

    @Bean
    ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(
            Environment environment,
            LoadBalancerClientFactory factory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new RandomLoadBalancer(
            factory.getLazyProvider(name, ServiceInstanceListSupplier.class),
            name
        );
    }
}

3.4 自定义负载均衡策略 #

java
public class CustomLoadBalancer implements ReactorServiceInstanceLoadBalancer {

    private final String serviceId;
    private final ServiceInstanceListSupplier serviceInstanceListSupplier;

    public CustomLoadBalancer(String serviceId, ServiceInstanceListSupplier supplier) {
        this.serviceId = serviceId;
        this.serviceInstanceListSupplier = supplier;
    }

    @Override
    public Mono<Response<ServiceInstance>> choose(Request request) {
        return serviceInstanceListSupplier.get()
                .next()
                .map(instances -> {
                    if (instances.isEmpty()) {
                        return new EmptyResponse();
                    }
                    
                    ServiceInstance instance = selectInstance(instances);
                    return new DefaultResponse(instance);
                });
    }

    private ServiceInstance selectInstance(List<ServiceInstance> instances) {
        return instances.get(0);
    }
}
java
@Configuration
public class LoadBalancerConfig {

    @Bean
    public ReactorLoadBalancer<ServiceInstance> customLoadBalancer(
            Environment environment,
            LoadBalancerClientFactory factory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new CustomLoadBalancer(name, 
            factory.getLazyProvider(name, ServiceInstanceListSupplier.class));
    }
}

四、服务实例选择器 #

4.1 自定义ServiceInstanceListSupplier #

java
public class CustomServiceInstanceListSupplier 
        extends DelegatingServiceInstanceListSupplier {

    public CustomServiceInstanceListSupplier(ServiceInstanceListSupplier delegate) {
        super(delegate);
    }

    @Override
    public Flux<List<ServiceInstance>> get() {
        return delegate.get()
                .map(instances -> {
                    return instances.stream()
                            .filter(this::isHealthy)
                            .collect(Collectors.toList());
                });
    }

    private boolean isHealthy(ServiceInstance instance) {
        Map<String, String> metadata = instance.getMetadata();
        String status = metadata.get("status");
        return "UP".equals(status);
    }
}
java
@Configuration
public class LoadBalancerConfig {

    @Bean
    public ServiceInstanceListSupplier serviceInstanceListSupplier(
            ConfigurableApplicationContext context) {
        return ServiceInstanceListSupplier.builder()
                .withDiscoveryClient()
                .withHealthChecks()
                .build(context);
    }
}

五、健康检查 #

5.1 开启健康检查 #

yaml
spring:
  cloud:
    loadbalancer:
      health-check:
        enabled: true
        initial-delay: 0
        interval: 25s
        path:
          default: /actuator/health

5.2 配置健康检查 #

java
@Configuration
public class LoadBalancerConfig {

    @Bean
    public ServiceInstanceListSupplier healthCheckServiceInstanceListSupplier(
            ConfigurableApplicationContext context) {
        return ServiceInstanceListSupplier.builder()
                .withDiscoveryClient()
                .withHealthChecks()
                .build(context);
    }
}

六、缓存配置 #

6.1 开启缓存 #

yaml
spring:
  cloud:
    loadbalancer:
      cache:
        enabled: true
        ttl: 35s
        capacity: 256

6.2 自定义缓存 #

java
@Configuration
public class LoadBalancerConfig {

    @Bean
    public LoadBalancerCacheFactory loadBalancerCacheFactory() {
        return new DefaultLoadBalancerCacheFactory(256, 35, true);
    }
}

七、重试机制 #

7.1 添加依赖 #

xml
<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>

7.2 配置重试 #

yaml
spring:
  cloud:
    loadbalancer:
      retry:
        enabled: true
        retry-on-all-operations: false
        max-retries-on-next-service-instance: 1
        max-retries-on-same-service-instance: 0

7.3 自定义重试策略 #

java
@Configuration
public class RetryConfig {

    @Bean
    public LoadBalancedRetryFactory loadBalancedRetryFactory() {
        return new LoadBalancedRetryFactory() {
            @Override
            public RetryPolicy createRetryPolicy(String service, ServiceInstanceListSupplier serviceInstanceListSupplier) {
                return new SimpleRetryPolicy(3);
            }
        };
    }
}

八、提示机制 #

8.1 开启提示 #

yaml
spring:
  cloud:
    loadbalancer:
      hint:
        enabled: true

8.2 使用提示 #

java
@RestController
public class UserController {

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/users/{id}")
    public User getUser(@PathVariable Long id) {
        RequestData requestData = new RequestData(
            "GET",
            URI.create("http://user-service/users/" + id),
            new HttpHeaders(),
            null,
            new HashMap<>()
        );
        
        requestData.getHints().put("zone", "zone-1");
        
        return restTemplate.exchange(
            requestData.getRequest(),
            User.class
        ).getBody();
    }
}

九、配置详解 #

9.1 完整配置 #

yaml
spring:
  cloud:
    loadbalancer:
      enabled: true
      ribbon:
        enabled: false
      cache:
        enabled: true
        ttl: 35s
        capacity: 256
      health-check:
        enabled: true
        initial-delay: 0
        interval: 25s
        path:
          default: /actuator/health
          user-service: /health
      retry:
        enabled: true
        retry-on-all-operations: false
        max-retries-on-next-service-instance: 1
        max-retries-on-same-service-instance: 0
      hint:
        enabled: true
      zone: default

9.2 配置项说明 #

配置项 默认值 说明
enabled true 是否启用负载均衡
cache.enabled true 是否启用缓存
cache.ttl 35s 缓存过期时间
health-check.enabled false 是否启用健康检查
retry.enabled true 是否启用重试

十、加权负载均衡 #

10.1 基于元数据的权重 #

yaml
eureka:
  instance:
    metadata-map:
      weight: 100

10.2 自定义加权负载均衡 #

java
public class WeightedLoadBalancer implements ReactorServiceInstanceLoadBalancer {

    private final String serviceId;
    private final ServiceInstanceListSupplier serviceInstanceListSupplier;
    private final Random random = new Random();

    public WeightedLoadBalancer(String serviceId, ServiceInstanceListSupplier supplier) {
        this.serviceId = serviceId;
        this.serviceInstanceListSupplier = supplier;
    }

    @Override
    public Mono<Response<ServiceInstance>> choose(Request request) {
        return serviceInstanceListSupplier.get()
                .next()
                .map(instances -> {
                    if (instances.isEmpty()) {
                        return new EmptyResponse();
                    }
                    
                    ServiceInstance instance = selectByWeight(instances);
                    return new DefaultResponse(instance);
                });
    }

    private ServiceInstance selectByWeight(List<ServiceInstance> instances) {
        int totalWeight = instances.stream()
                .mapToInt(this::getWeight)
                .sum();
        
        int randomWeight = random.nextInt(totalWeight);
        int currentWeight = 0;
        
        for (ServiceInstance instance : instances) {
            currentWeight += getWeight(instance);
            if (randomWeight < currentWeight) {
                return instance;
            }
        }
        
        return instances.get(0);
    }

    private int getWeight(ServiceInstance instance) {
        String weight = instance.getMetadata().get("weight");
        return weight != null ? Integer.parseInt(weight) : 1;
    }
}

十一、最佳实践 #

11.1 生产环境配置 #

yaml
spring:
  cloud:
    loadbalancer:
      enabled: true
      ribbon:
        enabled: false
      cache:
        enabled: true
        ttl: 30s
        capacity: 512
      health-check:
        enabled: true
        initial-delay: 10s
        interval: 30s
      retry:
        enabled: true
        max-retries-on-next-service-instance: 2

11.2 注意事项 #

注意点 说明
缓存配置 合理设置缓存时间和容量
健康检查 生产环境建议开启
重试策略 避免无限重试
超时配置 与服务调用超时配合

十二、总结 #

12.1 核心要点 #

要点 说明
客户端负载均衡 LoadBalancer替代Ribbon
负载均衡策略 轮询、随机、自定义
健康检查 自动剔除不健康实例
缓存机制 提高服务发现性能
重试机制 提高调用成功率

12.2 下一步 #

现在你已经掌握了负载均衡的使用,接下来让我们学习 服务网关,了解Spring Cloud Gateway的核心功能!

最后更新:2026-03-28