Spring Cloud LoadBalancer:负载均衡策略与自定义

注册中心提供了一份实例列表,但"选哪个实例发起调用"是另一件事。一个服务部署 3 个实例,流量如果总是打向同一个实例,扩容就失去了意义。负责在实例之间分配请求的组件就是负载均衡器。Spring Cloud 早期用 Netflix Ribbon,Ribbon 停止演进后,官方以 Spring Cloud LoadBalancer 取而代之并成为默认实现,与 OpenFeign、RestTemplate、Gateway 无缝配合。

客户端负载均衡的含义

Spring Cloud LoadBalancer 属于客户端负载均衡:选择逻辑运行在调用方进程内,实例列表来自注册中心(本地缓存),而非依赖 Nginx 之类的集中式入口。优点是每个服务可按自身策略选择、无单点、与注册中心联动紧密;代价是选择逻辑分散在各客户端,策略需要各服务自行维护一致。

默认策略与快速切换

不写任何配置时,LoadBalancer 采用轮询(Round Robin)策略,按顺序把请求分发给实例列表中的每个节点。想换成随机策略,Spring Cloud 提供了配置开关:

spring:
  cloud:
    loadbalancer:
      configurations: random   # 全局切到随机;默认是轮询

更多内置策略与属性开关请以官方文档为准。注意负载均衡是"按请求"分配:长连接(如数据库连接池)不属于这里讨论的 HTTP 调用范畴,不要在两者之间混淆。

实例列表从哪里来

负载均衡器本身不存注册表,它通过 ServiceInstanceListSupplier 获取服务实例:默认实现向注册中心(Nacos/Consul/Eureka)拉取并缓存,缓存有 TTL,可配置。正因有这层缓存,第 02 章提到的"下线延迟"在这里再次体现。使用 Nacos 时,Spring Cloud Alibaba 还会提供一个按实例权重选择的实现(NacosLoadBalancer),权重在 Nacos 控制台调整即可生效;想用哪种、如何切换,以 SCA 官方文档为准。

按服务定制:@LoadBalancerClients

不同服务可能需要不同策略:比如 user-service 用轮询、库存服务用自定义的最小并发策略。做法是把策略定义在独立的配置类里,再用 @LoadBalancerClients 挂到指定服务(旧注解 @LoadBalancerClient 在较新版本已标记废弃,写法以官方文档为准):

@Configuration
@LoadBalancerClients({
        @LoadBalancerClient(name = "user-service",
                configuration = UserServiceLbConfig.class)
})
public class LbConfig { }

UserServiceLbConfig 内提供一个返回 ReactorLoadBalancer 的 Bean 即可覆盖默认实现,LoadBalancer 会按 serviceId 找到对应配置。

自定义一个"最小并发优先"策略

负载均衡的核心接口是 ReactorLoadBalancer,自定义策略就是实现 choose 方法里的"选谁"逻辑:

public class LeastActiveBalancer implements ReactorLoadBalancer<ServiceInstance> {
    private final ObjectProvider<ServiceInstanceListSupplier> supplierProvider;
    private final String serviceId;

    @Override
    public Mono<Response<ServiceInstance>> choose(Request request) {
        return supplierProvider.getIfAvailable()
            .flatMap(supplier -> supplier.get(request))      // 取实例列表(含缓存)
            .map(instances -> chooseByLeastActive(instances)) // 自定义选择逻辑
            .map(instance -> new Response<>(instance));
    }
}

其中 chooseByLeastActive 需要结合连接数统计(如从 Actuator 或自建计数取数),示例从简。核心思想:实例列表由 supplier 提供,选择逻辑完全由你掌控,这为"按机房优先、按权重、按最小负载"等场景留出了充分空间。

与 OpenFeign / Gateway 的关系

OpenFeign 的 @FeignClient 声明了服务名,真正把服务名解析成"某一个实例的地址"并完成调用的正是 LoadBalancer;Gateway 中 lb:// 前缀的 URI 同样走它(第 08 章)。所以负载均衡调优一次,全链路受益。

小结

LoadBalancer 是 Spring Cloud 调用链路的"分配器":默认轮询开箱即用,按服务定制与自定义策略都围绕 ReactorLoadBalancer 与 ServiceInstanceListSupplier 两个扩展点展开。配置了它,OpenFeign、Gateway 按服务名调用才真正具备水平扩展能力。下一章进入流量入口——Spring Cloud Gateway。

笔记加载中…