跳到主要内容

负载均衡

负载均衡是分布式系统中保证系统高可用和扩展性的关键技术。在微服务架构中,每个服务可能有多个实例,负载均衡决定了请求应该发送到哪个服务实例。

为什么需要负载均衡?

单实例的问题

┌─────────────────┐
│ 用户请求 │
└────────┬────────┘


┌─────────────────┐
│ 单一服务实例 │ ← 单点故障
│ 192.168.1.10 │
└─────────────────┘

性能瓶颈

负载均衡的优势

┌─────────────────┐
│ 用户请求 │
└────────┬────────┘


┌─────────────────┐
│ 负载均衡器 │
└────────┬────────┘

┌────┼────┬────┐
▼ ▼ ▼ ▼
┌────┐┌────┐┌────┐┌────┐
│实例1││实例2││实例3││实例4│
│ 10% ││ 25% ││ 30% ││ 35% │
└────┘└────┘└────┘└────┘

负载均衡的优势:
1. 提高系统可用性:某实例故障不影响整体服务
2. 提高系统性能:分散请求压力
3. 可扩展性:轻松增加或减少实例

负载均衡的分类

1. 服务端负载均衡

┌─────────────────┐
│ 负载均衡器 │ ← 中间层
│ (Nginx/F5) │
└────────┬────────┘

┌────┼────┐
▼ ▼ ▼
┌────┐┌────┐┌────┐
│实例1││实例2││实例3│
└────┘└────┘└────┘

优点:客户端无需关心服务端实例
缺点:单点故障,增加一层网络开销

2. 客户端负载均衡

┌─────────────────┐
│ 客户端 │
│ ┌───────────┐ │
│ │ 负载均衡器 │ │
│ └─────┬─────┘ │
└────────┼────────┘

┌────┼────┐
▼ ▼ ▼
┌────┐┌────┐┌────┐
│实例1││实例2││实例3│
└────┘└────┘└────┘

优点:无单点故障,性能更好
缺点:客户端需要维护服务列表

Ribbon 客户端负载均衡

Ribbon 是 Netflix 开发的客户端负载均衡器,已集成到 Spring Cloud 中。

Ribbon 支持的负载均衡策略

策略类名描述
轮询RoundRobinRule依次选择每个服务器
随机RandomRule随机选择一个服务器
重试RetryRule按轮询获取失败后重试
最低并发BestAvailableRule选择并发数最小的
响应时间加权WeightedResponseTimeRule根据响应时间加权
可用性过滤AvailabilityFilteringRule过滤不可用的
区域感知ZoneAvoidanceRule优先选择同区域

使用 Ribbon

<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
</dependencies>
@Configuration
public class RibbonConfig {

@Bean
public IRule ribbonRule() {
// 改为随机策略
return new RandomRule();
}
}
// 在 RestTemplate 上使用 @LoadBalanced
@Configuration
public class RestTemplateConfig {

@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
// 调用服务
@RestController
public class OrderController {

@Autowired
private RestTemplate restTemplate;

@GetMapping("/order/{id}")
public Order getOrder(@PathVariable Long id) {
// 直接使用服务名,Ribbon 自动进行负载均衡
String url = "http://user-service/user/" + id;
User user = restTemplate.getForObject(url, User.class);

return new Order(id, user);
}
}

Spring Cloud Loadbalancer

Spring Cloud 官方推出的负载均衡器,用于替代 Ribbon。

为什么需要 Spring Cloud Loadbalancer?

  1. Ribbon 进入维护模式:Netflix 停止了对 Ribbon 的积极开发
  2. 更好的集成:与 Spring Cloud 生态更好集成
  3. 响应式支持:支持响应式编程

使用 Spring Cloud Loadbalancer

<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
</dependencies>
spring:
cloud:
loadbalancer:
configurations: default
# 禁用 Ribbon
ribbon:
enabled: false

自定义负载均衡策略

// 自定义负载均衡策略
public class MyLoadBalancerConfiguration {

@Bean
public ServiceInstanceListSupplier serviceInstanceListSupplier(
ConfigurableApplicationContext context) {
return ServiceInstanceListSupplier.builder()
.withDiscoveryClient()
.withZoneAndMeta()
.build(context);
}
}
// 使用自定义负载均衡
@Bean
public ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(
ServiceDiscovery(serviceDiscovery) {
String name = "user-service";
return new RandomLoadBalancer(
serviceDiscovery.getInstances(name), name);
}

负载均衡策略详解

1. 轮询策略(Round Robin)

// 轮询策略原理
// 实例列表:[A, B, C]
// 请求1 → A
// 请求2 → B
// 请求3 → C
// 请求4 → A
// ...

2. 随机策略(Random)

// 随机选择一个实例
public class RandomRule extends AbstractLoadBalancerRule {

public Server choose(ILoadBalancer lb, Object key) {
List<Server> servers = lb.getReachableServers();
int randomIndex = ThreadLocalRandom.current().nextInt(servers.size());
return servers.get(randomIndex);
}
}

3. 加权响应时间策略

根据服务器的响应时间分配权重,响应时间越短的服务器分配的请求越多:

响应时间与权重关系:
┌────────────┬────────────┬────────────┐
│ 服务器 │ 响应时间 │ 权重 │
├────────────┼────────────┼────────────┤
│ 实例A │ 10ms │ 100 │
│ 实例B │ 50ms │ 20 │
│ 实例C │ 100ms │ 10 │
└────────────┴────────────┴────────────┘

4. 区域感知策略

优先选择同区域的服务实例,减少网络延迟:

spring:
cloud:
loadbalancer:
zone: shanghai-zone

服务实例的动态感知

服务实例可能随时增加、减少或故障,负载均衡器需要实时感知这些变化。

服务变更监听

@Autowired
private DiscoveryClient discoveryClient;

@PostConstruct
public void init() {
// 监听服务变更事件
discoveryClient.getInstances("user-service")
.forEach(instance -> {
System.out.println("服务实例: " + instance.getUri());
});
}

使用 ServiceInstanceListSupplier

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

高级特性

1. 重试机制

spring:
cloud:
loadbalancer:
retry:
enabled: true
# Ribbon 重试配置
ribbon:
MaxAutoRetries: 1
MaxAutoRetriesNextServer: 2
OkToRetryOnAllOperations: true

2. 熔断与负载均衡结合

当某个服务实例频繁失败时,自动将其从服务列表中移除:

@Bean
public ReactorLoadBalancer<ServiceInstance> zoneAwareLoadBalancer(
ServiceDiscovery serviceDiscovery,
ConfigurableApplicationContext context) {
return new ZoneAwareLoadBalancer(
serviceDiscovery.getInstances("user-service"));
}

3. 限流与负载均衡

结合限流组件,控制进入系统的请求数量:

@Configuration
public class RateLimiterLoadBalancerConfig {

@Bean
public ReactorLoadBalancer<ServiceInstance> rateLimiterLoadBalancer(
ServiceDiscovery serviceDiscovery) {
return new RateLimiterLoadBalancer(
serviceDiscovery.getInstances("user-service"));
}
}

最佳实践

  1. 选择合适的策略

    • 同配置集群:轮询或随机
    • 异构集群:加权响应时间
    • 多区域部署:区域感知策略
  2. 健康检查

    • 确保及时发现故障实例
    • 合理配置检查间隔
  3. 超时配置

    • 避免请求长时间等待
    • 配合重试机制使用
  4. 监控

    • 监控各实例的请求量
    • 监控响应时间和错误率

小结

本章主要介绍了:

  1. 负载均衡的重要性:提高系统可用性和性能
  2. 服务端 vs 客户端负载均衡:两种架构的对比
  3. Ribbon:Netflix 开发的客户端负载均衡器
  4. Spring Cloud Loadbalancer:Spring 官方的负载均衡器
  5. 负载均衡策略:轮询、随机、加权等策略
  6. 高级特性:重试、熔断、限流等

负载均衡是微服务架构的核心组件,与服务注册发现、熔断器等组件配合,共同构建高可用的微服务系统。