在微服务中,经常会有服务间调用的场景,项目中一般会采用feign框架来进行调用。最近粗读了下feign的源码,先简单的记录下大致阅读思路,后续再进行补充修错。
feign主要包含服务发现、httpClient、负载均衡(ribbon)、请求重试、熔断降级(hystrix)几块内容的实现,具体调用请求时使用了rxjava观察者相关的内容。
调用示例
@FeignClient(value = "user-service", contextId = "user",path = "/api/v1/",fallback = UserClientFallback.class)
public interface UserClient {
@RequestMapping(value="user/info", method = RequestMethod.GET)
String getUserInfo(@RequestParam("userId") Integer userId);
}
断点调试发现@FeignClient注解的类会通过springIOC注入为一个动态代理对象,根据 feign.hystrix.enabled 配置确定由FeignInvocationHandler类或HystrixInvocationHandler类进行增强;由于hystrix的具体实现还不了解,所以先从FeignInvocationHandler类的实现读起。
动态代理
由以下两个类实现,主要查看该类中的invoke()方法;
HystrixInvocationHandler
feign.hystrix.enabled=true
添加如上配置时feign会引用hystrix组件来处理熔断降级相关的情况。
FeignInvocationHandler
未配置熔断器的情况,没有降级处理,调用失败直接抛出异常。
服务发现
在进行远程调用时,程序需要知道具体的服务器ip、端口、请求路由,才能进行请求的发送;feign根据微服务注册中心的不同包含nacos和eureka两种实现;在DynamicServerListLoadBalancer类的构造方法中层层调用服务发现方法ServerList#getUpdatedListOfServers(),并在nacos和eureka的依赖包中对方法进行实现。
nacos
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-nacos-discovery</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
通过NacosServerList类实现ServerList接口,向下追踪代码发现最终通过ScheduledExecutorService线程池来定时调用nacos的api进行serverList的维护;
eureka
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
通过DiscoveryEnabledNIWSServerList类来实现;
HttpClient
包括LoadBalancerFeignClient、OkHttpClient、ApacheHttpClient、Client.Default这几种实现方式;如果配置了OkHttpClient或ApacheHttpClient,会通过LoadBalancerFeignClient类的delegate包装相应的client;LoadBalancerFeignClient的构造方法如下;
public LoadBalancerFeignClient(Client delegate,
CachingSpringLoadBalancerFactory lbClientFactory,
SpringClientFactory clientFactory) {
this.delegate = delegate;
this.lbClientFactory = lbClientFactory;
this.clientFactory = clientFactory;
}
配置方式
feign.httpclient.enabled=false
feign.okhttp.enabled=true
负载均衡
LoadBalancerFeignClient在执行execute()时会通过负载均衡配置来获取server,并进行请求;负载均衡的配置主要通过继承ribbon包下的IRule接口来实现;
IRule
配置方式
@Bean
public IRule getRule(){
//轮询
return new RandomRule();
}
RoundRobinRule
轮询
RandomRule
随机
AvailabilityFilteringRule
会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,还有并发的连接数超过阈值的服务,然后对剩余的服务列表进行轮询
WeightedResponseTimeRule
权重 根据平均响应时间计算所有服务的权重,响应时间越快服务权重越大被选中的概率越高。刚启动时,如果统计信息不足,则使用轮询策略,等信息足够,切换到 WeightedResponseTimeRule
RetryRule
重试 先按照轮询策略获取服务,如果获取失败则在指定时间内重试,获取可用服务
BestAvailableRule
选过滤掉多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
ZoneAvoidanceRule
符合判断server所在区域的性能和server的可用性选择服务
请求重试
feign、httpClient、ribbon分别有自己的重试机制;
ribbon配置:
ribbon.MaxAutoRetriesNextServer=2
ribbon.MaxAutoRetries=2
RequestInterceptor拦截器
主要对请求头进行处理,包含以下几种实现类:
- BaseRequestInterceptor
- BasicAuthRequestInterceptor
- FeignAcceptGzipEncodingInterceptor
- FeignContentGzipEncodingInterceptor
待补充
hystrix熔断降级原理
rxjava相关