Spring Cloud LoadBalancer独立面试题
本页只保留标准回答、追问方向和精确原理跳转。完整源码、Demo、失败窗口和生产Runbook见LoadBalancer内部原理与生产治理。
1. 什么是客户端负载均衡
标准回答: 调用方进程自己持有服务实例列表,并在每次请求前选择一个ServiceInstance,再把逻辑服务名重写为真实host和port。Spring Cloud LoadBalancer属于客户端负载均衡;Nginx、云LB和Gateway作为统一转发入口时属于服务端负载均衡。
原理:客户端与服务端负载均衡
2. Nacos、LoadBalancer和HTTP Client分别做什么
标准回答: Nacos提供服务名和实例数据;ServiceInstanceListSupplier把Discovery数据缓存、过滤或变换;LoadBalancer算法从最终候选中选实例;HTTP Client负责连接池、TCP/TLS和HTTP收发。Nacos不转发业务请求,LoadBalancer也不建立网络连接。
原理:职责边界
3. Spring Cloud LoadBalancer的核心对象有哪些
标准回答: LoadBalancerClientFactory按serviceId提供专属上下文;ServiceInstanceListSupplier提供候选列表;ReactorServiceInstanceLoadBalancer执行选择;默认常见实现是RoundRobinLoadBalancer;BlockingLoadBalancerClient适配阻塞调用;Feign通过FeignBlockingLoadBalancerClient进入选址链。
原理:源码对象地图
4. 为什么每个服务要有一个LoadBalancer子上下文
标准回答: 不同下游可能需要不同Supplier、算法、zone、hint、健康和重试配置。LoadBalancerClientFactory继承NamedContextFactory,按serviceId创建命名子上下文并复用组件。专属配置类若被主应用扫描,可能污染成全局策略。
原理:命名子容器
5. 一次Feign负载均衡调用怎样执行
标准回答: Feign请求的host先是服务名;桥接Client提取serviceId并构造RequestDataContext;BlockingLoadBalancerClient从Factory取得服务专属LoadBalancer;Supplier链输出候选;算法选ServiceInstance;随后用实例重建URI并交给底层HTTP Client。
原理:运行时主链
6. ServiceInstanceListSupplier是什么
标准回答: 它是服务实例列表供应抽象,返回Flux<List<ServiceInstance>>。Discovery、缓存、健康、zone、hint、权重、subset等能力通过委托和装饰器逐层组合。它负责产生候选,不等于最终选择算法。
原理:Supplier装饰器链
7. Supplier Builder的调用顺序重要吗
标准回答: 重要。Builder先创建base supplier,再按调用顺序包装,最后添加的组件在最外层。discovery -> cache -> zone表示zone从缓存取原始列表后过滤;若把请求Header过滤结果放在缓存内层或外层错误位置,可能把某次请求结果污染给其他请求。
原理:Supplier装饰器链
8. LoadBalancer每次选择都会请求Nacos Server吗
标准回答: 通常不会。Nacos客户端本身维护本地服务信息,DiscoveryClient读取客户端可见数据;Spring Cloud LoadBalancer外面还可能使用CachingServiceInstanceListSupplier。因此一次选址一般基于调用方本地状态,而不是同步远程访问Nacos Server。
原理:Discovery Supplier、Nacos本地缓存
9. LoadBalancer缓存的默认TTL是多少
标准回答: 不能脱离版本回答。LoadBalancer 4.1.2源码样本的LoadBalancerCacheProperties默认TTL为35秒、capacity为256;项目若使用自定义Caffeine spec,会覆盖包括TTL在内的其他LB缓存设置。生产应查看最终绑定值和当前精确版本。
原理:缓存原理
10. 为什么服务下线后仍会被调用
标准回答: 下线有传播链:提供者Readiness和注销、注册中心更新、Discovery客户端感知、LoadBalancer缓存过期、网关缓存和存量请求排空不是同一瞬间。旧列表存在期间仍可能选中旧实例,必须先摘流并等待最大传播窗口,再停止进程。
11. RoundRobin的源码原理是什么
标准回答: 每个服务LoadBalancer对象持有本地AtomicInteger游标。每次多实例选择时递增并清除符号位,再对本次列表长度取模;空列表返回空响应,单实例直接返回且不推进游标。初始位置可使用随机种子,减少大量客户端同时从同一节点开始。
原理:RoundRobin源码
12. 轮询为什么不能保证全局绝对平均
标准回答: 每个调用方有独立游标,看到的列表版本和顺序也可能不同;zone、灰度、sticky和重试会改变候选;请求耗时和实例容量又不相同。因此轮询只在本地当前列表上轮转,不是全局调度器。判断均衡要同时看QPS、并发和P99。
13. RoundRobin和Random怎样选择
标准回答: RoundRobin使用本地游标按序取模,短期更可预测;Random从当前列表随机选择,长期概率趋近均匀但短窗口自然波动。两者都不感知实例实时CPU、队列或延迟,慢实例仍可能持续收到请求。
原理:算法边界
14. 权重负载均衡怎样工作
标准回答: 4.1.2样本的Weighted Supplier读取ServiceInstance metadata中的weight正整数,生成逻辑加权列表,再由算法选择;缺失、异常或非正值回退权重1。必须确认注册中心权重是否映射到该metadata键,以及Supplier配置确实启用weighted。
原理:Weighted
15. 权重为0是否一定能立即摘流
标准回答: 不能这样保证。样本Weighted实现对非正权重会回退默认权重1;注册中心的权重语义也未必直接映射成Spring Cloud metadata。真正摘流应使用Readiness、注册下线或明确过滤规则,并等待缓存传播,而不是依赖把weight设为0。
原理:Weighted边界、优雅下线
16. Zone Preference是严格同机房吗
标准回答: 不是。样本实现找到同zone实例时返回同zone列表;未配置zone或同zone为空时返回全部原始实例。这是可用性优先的偏好策略。数据合规要求绝不跨区时,必须自定义严格Supplier,空时明确失败。
原理:Zone与Hint回退
17. Hint路由找不到匹配实例会怎样
标准回答: 内置HintBased Supplier在有匹配时过滤;无匹配时回退全部原始实例,而不是返回空。这适合偏好路由,不适合v2请求绝不能进入v1的严格协议隔离。严格灰度要自定义失败或受控回退策略。
18. Same Instance Preference和Sticky Session有什么区别
标准回答: Same Instance Preference在Supplier内部记住上次选中实例,只要它仍存在就优先返回;Sticky Session根据请求Cookie中的实例ID偏好特定实例。二者都是亲和偏好,实例不存在时会回退候选,不能替代共享Session或无状态设计。
原理:算法和策略表
19. Subset解决什么问题
标准回答: 大规模调用方和提供方若彼此全连接,会产生连接、健康检查和缓存扇出。Subset使用调用方实例ID做确定性分桶,让每个调用方相对稳定地只访问一个提供方子集。它降低扇出,但子集过小会降低故障冗余,实例变化也可能重新分桶。
原理:Subset
20. LoadBalancer为什么仍会选到慢实例
标准回答: 默认轮询和随机只知道候选列表,不读取实例实时延迟。Full GC、线程池满或慢SQL期间,注册中心可能仍认为实例健康。需要实例级P99、慢调用熔断、Readiness摘流、权重治理或经过验证的P2C/EWMA扩展。
原理:慢实例
21. P2C和EWMA是Spring Cloud默认算法吗
标准回答: 不能把概念页等同于框架默认配置。Spring Cloud LoadBalancer 4.1.2样本默认常见算法是RoundRobin,也提供Random和多种Supplier策略;P2C、EWMA通常需要自定义实现和可靠的本地指标。算法不能同步依赖远程监控系统,否则观测故障会变成调用故障。
22. 客户端健康检查怎样工作
标准回答: HealthCheck Supplier从Discovery拿实例,周期调用每个实例健康端点,超时或异常时排除,并回放最近健康列表给选择算法。它可补充注册健康,但大规模场景会形成探测流量;健康端点过重或间隔过短还可能误摘全部实例。
原理:客户端健康检查
23. 注册中心已经健康检查,还要开启LB健康检查吗
标准回答: 不一定。若注册中心能及时提供可靠健康状态,调用方再次主动探测会增加N乘M流量和新的误判窗口;若某些固定服务或注册健康太粗,LB健康可补充。应根据实例规模、传播SLO和健康端点成本决定,不能默认全部开启。
原理:客户端健康检查
24. LoadBalancer重试一定会换实例吗
标准回答: 不一定。RetryAware Supplier会在上下文携带previous instance时尝试移除上次实例;若还有其他实例可换,才会选其他实例。只有一个实例或过滤后只剩原实例时,它会警告并返回原列表。因此还要检查候选数和重试上下文。
原理:RetryAware
25. LoadBalancer默认会重试一次吗
标准回答: 属性对象样本中retry.enabled=true、next instance次数为1,但这不证明所有调用入口实际装配了重试Client。阻塞Feign重试还依赖Spring Retry class、自动配置条件和最终Client类型;响应式链条件也不同。必须看条件报告和运行时对象,不能只背属性默认值。
26. 为什么写接口不应透明跨实例重试
标准回答: 第一个实例可能已经完成写事务,只是响应丢失;换第二个实例会重复创建、扣款或扣库存。写请求必须依赖稳定幂等键、状态查询和补偿,并把总尝试预算放在一个明确层,而不是Gateway、Feign、LoadBalancer和业务任务同时重试。
27. 怎样排查注册中心有实例但调用无实例
标准回答: 先确认实际serviceId和调用方namespace/group;再导出调用方DiscoveryClient原始列表;随后逐层记录LB缓存、health、zone、hint、version、subset后的数量;最后确认算法是否返回EmptyResponse。控制台截图不能替代调用方证据。
原理:无实例Runbook
28. 怎样排查负载不均
标准回答: 同时看每个调用方对各实例的选择次数,以及每个提供方实际QPS、并发、P99和错误率;再核对候选列表版本、过滤标签、sticky、实例规格、连接池每路由限制和重试。若请求数均匀但并发不均,通常是耗时或容量不同。
29. Ribbon和Spring Cloud LoadBalancer有什么区别
标准回答: 二者都做客户端负载均衡。Ribbon属于Netflix老生态,核心对象包括ServerList、ServerListFilter、IPing和IRule;Spring Cloud LoadBalancer属于当前Spring Cloud主线,使用ServiceInstance、Supplier装饰链和ReactorServiceInstanceLoadBalancer,更自然集成Gateway、WebClient和OpenFeign。
原理:Ribbon迁移对比
30. 怎样把自定义Ribbon IRule迁移到LoadBalancer
标准回答: 先拆分旧IRule到底做了什么:实例获取迁到Discovery Supplier,缓存迁到Caching Supplier,zone或版本过滤迁到自定义Supplier,最终选择算法迁到ReactorServiceInstanceLoadBalancer。不能只把类名替换,因为Ribbon规则常把获取、过滤和选择耦合在一个实现中。
原理:Ribbon迁移对比
31. 连接池为什么会影响负载均衡表现
标准回答: LoadBalancer只决定目标实例,HTTP Client还要按目标路由取得连接。每路由连接过小会让选中的实例请求在本地排队;HTTP/2复用、长连接和连接泄漏也会改变实际并发。排查要同时看选址次数和真正发送、连接池等待数据。
32. 线上负载均衡故障要保留什么证据
标准回答: 保存serviceId、调用方实例、原始Discovery列表、每层Supplier过滤数量、缓存列表年龄、算法和选中实例、重试previous instance、最终目标URL、HTTP阶段耗时以及下游是否收到请求。没有候选演变证据,很难判断是注册、缓存、过滤、算法还是网络问题。
33. 怎么保证每次请求都是最新可用实例
标准回答: 严格不能保证每次请求都拿到全局最新且绝对可用实例。LoadBalancer每次请求通常读取调用方本地快照,而不是同步访问注册中心;快照由Nacos推送、Eureka拉取、Consul Blocking Query、Kubernetes Watch或Mesh xDS在后台更新。工程上通过Readiness摘流、健康和metadata过滤、合理LB缓存TTL、连接池回收、短超时、有限重试、熔断隔离、幂等号和事实查询,保证“当前视角下尽量可用”。如果是强版本请求,metadata过滤后无实例应明确失败;如果是写请求,超时后必须先查业务事实,不能盲目换实例重试。
追问方向:
| 追问 | 回答要点 |
|---|---|
| 为什么不每次查注册中心 | 会增加RT、打爆注册中心、降低可用性,而且查完后实例仍可能故障 |
| 调到旧实例说明什么 | 可能是注册表未更新、客户端缓存未刷新、LB二级缓存未过期、过滤规则错误或连接池复用旧连接 |
| 强要求最新怎么办 | 只在低QPS治理接口做带超时的强刷新;高QPS业务仍用本地快照和失败治理 |
| 怎么证明选址过程 | 记录serviceId、候选数、过滤原因、目标IP、版本、快照年龄、attempt和traceId |
