@LoadBalanced 默认用什么策略?起点是随机的吗?后端挂了会不会自动摘掉?健康检查配了为什么全部请求都失败?新实例上线要多久才有流量?这篇用三个真实后端、一个可以随时改的 DiscoveryClient,在 Spring Boot 4.0.8、Spring Cloud 2025.1.3 上逐项实测。
ReactorLoadBalancer = RoundRobinLoadBalancer;ServiceInstanceListSupplier 链 = CachingServiceInstanceListSupplier → DiscoveryClientServiceInstanceListSupplier;LoadBalancerCacheManager = [DefaultLoadBalancerCacheManager] 连续 12 次调用:b3 b1 b2 b3 b1 b2 b3 b1 b2 b3 b1 b2 重启应用 5 次,每次第一个调用到的实例:b3 b1 b2 b1 b3
RoundRobinLoadBalancer,实例列表被 Caching 的 supplier 包着,起点随机。
ReactorLoadBalancer = RandomLoadBalancer;ServiceInstanceListSupplier 链 = CachingServiceInstanceListSupplier → DiscoveryClientServiceInstanceListSupplier;LoadBalancerCacheManager = [DefaultLoadBalancerCacheManager]
300 次调用的分布:{'b1': 111, 'b2': 97, 'b3': 92}
前 12 次:b2 b2 b1 b3 b3 b2 b3 b1 b3 b1 b3 b1
对照,默认(轮询)300 次的分布:{'b1': 100, 'b2': 100, 'b3': 100}声明 RandomLoadBalancer bean 即可,短期分布不均匀。
默认:30 次调用 {'b1': 10, 'b3': 10, '错误': 10}
一个错误的例子:ERR ResourceAccessException: I/O error on GET request for "http://orders/id": null
配了 health-check 但容器里没有 RestClient / RestTemplate bean:ServiceInstanceListSupplier = 没有(getInstance 返回 null)
6 次调用 {'错误': 6};一个错误的例子:ERR IllegalStateException: No instances available for orders
ReactorLoadBalancer = RoundRobinLoadBalancer;ServiceInstanceListSupplier 链 = HealthCheckServiceInstanceListSupplier → DiscoveryClientServiceInstanceListSupplier;LoadBalancerCacheManager = [DefaultLoadBalancerCacheManager]
加上一个 RestClient bean,health-check 1 秒一次:刚启动时的 6 次 b1 b1 b3 b1 b3 b1;3 秒后的 30 次 {'b1': 15, 'b3': 15}默认不摘除也不重试;health-check 要有 RestClient 或 RestTemplate bean。
[默认配置] ReactorLoadBalancer = RoundRobinLoadBalancer;LoadBalancerCacheManager = [DefaultLoadBalancerCacheManager] [默认配置] 把 b3 加进实例列表之后,过了 36 秒才第一次调用到 b3 [spring.cloud.loadbalancer.cache.ttl=3s] 把 b3 加进实例列表之后,过了 3 秒才第一次调用到 b3
默认约 35 秒缓存,cache.ttl 可以缩短。