OpenFeign 调用与负载均衡的原理是什么?

结论先行:OpenFeign 把 HTTP 调用声明成接口:启动时为每个 @FeignClient 生成代理,方法调用被翻译成 HTTP 请求模板(方法签名→URL/参数/头)后执行。服务名路由不落地 IP:代理把逻辑服务名交给 Spring Cloud LoadBalancer,由它从注册中心缓存的服务列表中按策略选出一个实例再发起请求。

一、Feign 客户端如何工作

@FeignClient(name = "order-service") // name=注册中心的服务名
public interface OrderClient {
    @GetMapping("/order/{id}")
    Order getById(@PathVariable("id") Long id);
}
// 启动类
@EnableFeignClients(basePackages = "com.demo.client")
环节机制
接口代理FeignClientFactoryBean 为接口生成 JDK 代理
方法解析Contract 把 Spring MVC 注解翻译成请求模板
参数编码Encoder 序列化(Jackson)
结果解码Decoder 反序列化,ErrorDecoder 处理异常
拦截器RequestInterceptor 统一加头(traceId、token)

二、与 LoadBalancer 的协作

  • 服务名解析:代理不直接连 IP,把逻辑名交给 LoadBalancerClient(spring-cloud-starter-loadbalancer);
  • 实例来源:LoadBalancer 从 ServiceInstanceListSupplier 取实例(内部对接 DiscoveryClient → Nacos/Eureka 缓存);
  • 选实例策略:默认轮询(RoundRobin),可自定义 ReactiveLoadBalancer/ServiceInstanceListSupplier 实现权重、区域优先;
  • Ribbon 现状:Spring Cloud 2020.0 起 Ribbon 退役,官方默认走 spring-cloud-loadbalancer;
  • 失败处理:Feign 支持重试器(Retryer)与超时配置,但需显式设置,避免默认策略叠加导致超时放大。

三、工程要点

  1. 超时:connectTimeout/readTimeout 按上游响应时间设(yml:spring.cloud.openfeign.client.config.xxx.read-timeout);
  2. 熔断:开启 circuit breaker 后可用 fallback 类兜底,避免调用方雪崩;
  3. 上下文传递:token/traceId 通过 RequestInterceptor 透传;
  4. 别把 Feign 接口当 DTO 仓库:接口归属消费方,公共模型放共享模块或独立 DTO。

常见追问 / 记忆点

  • 追问:Feign 和 RestTemplate 有何区别?答:Feign 声明式+负载均衡集成更好,RestTemplate 更底层、需自己拼 URL 与重试。
  • 追问:服务没注册上会怎样?答:LoadBalancer 拿不到实例抛 503/无可用实例异常,需先查注册中心实例是否在线。
  • 记忆点:代理翻译请求 + LoadBalancer 选实例;超时/重试/熔断三件套显式配。
笔记加载中…