一、什么是Feign
Feign是声明式Web服务客户端,它使编写Web服务客户端更加容易。Feign不做任何请求处理,通过处理注解相关信息生成Request,并对调用返回的数据进行解码,从而实现简化HTTP API的开发。
二、Feign和Openfeign的区别
Feign最早是由Netflix公司进行维护的,后来Netflix不再对其进行维护,最终Feign由社区进行维护,更名为Openfeign并将原项目迁移至新的仓库。
Feign集成了Ribbon、RestTemplate实现了负载均衡的执行Http调用,只不过对原有的方式(Ribbon+RestTemplate)进行了封装,开发者不必手动使用RestTemplate调服务,而是定义一个接口,在这个接口中标注一个注解即可完成服务调用,这样更加符合面向接口编程的宗旨,简化了开发。
三、常用负载均衡策略
随机(Random)算法:在实例列表中随机选择某个实例。
轮询(RoundRobin)算法:按顺序选择实例。
最少连接数(Least Connections)算法:每次取连接数最少的实例。
一致性哈希(Consistent Hashing)算法:基于一致性哈希算法总是将相同参数的请求落在同一个实例上。
权重随机(Weigthd Random):随机取一个数,根据这个数属于哪个范围选择对应的实例。
四、Openfeign如何负载均衡
一般而言,我们生产者注册多个服务,消费者调用时需要使用负载均衡从中选取一个健康并且可用的生产者服务。因为Openfeign内部集成Ribbon,所以也支持此特性。Openfeign默认的负载均衡策略是轮询调用。
五、Ribbon负载均衡原理
我们以前接触的nginx的负载均衡是服务端的负载均衡,而Ribbon为客户端提供负载均衡,其内部提供了一个负载均衡器ILoadBalance。
LoadBalancerClient在初始化的时候,会通过ILoadBalance向Eureka注册中心获取服务注册列表,并且每10s一次向EurekaClient发送“ping”,来判断服务的可用性,如果服务的可用性发生了改变或者服务数量和之前的不一致,则从注册中心更新或者重新拉取。LoadBalancerClient有了这些服务注册列表,就可以根据具体的IRule来进行负载均衡,来获取调用的服务。
六、Ribbon负载均衡方式
6.1 随机策略RandomRule
核心代码:
int index = rand.nextInt(serverCount); // 使用jdk内部的Random类随机获取索引值index
server = upList.get(index); // 得到服务器实例
6.2 RoundRobinRule轮询策略
表示每次都取下一个服务器,如果失败会继续向下尝试获取10次
6.3 WeightedResponseTimeRule加权策略
开始的时候还没有权重列表,采用父类的轮询方式,有一个默认每30秒更新一次权重列表的定时任务,该定时任务会根据实例的响应时间来更新权重列表,choose方法做的事情就是,用一个(0,1)的随机double数乘以最大的权重得到randomWeight,然后遍历权重列表,找出第一个比randomWeight大的实例下标,然后返回该实例。
6.4 BestAvailableRule策略用来选取最少并发量请求的服务器
七、Openfeign更改负载均衡策略(默认轮询)
7.1 方式一:使用已经提供的
@Bean
public IRule ribbonRule() {
return new BestAvailableRule();//最小请求数
}
7.2 方式二:使用自定义的
通过底层源码我们发现,这些策略都继承了AbstractLoadBalancerRule抽象类,所以我们写自定义负载均衡策略,只需要2步
第一步:编写类继承AbstractLoadBanlancerRule抽象类,实现choose方法。
第二步:注入类实例
@Bean
public IRule ribbonRule() {
return new 自定义的类();//自定义负载策略类
}
八、Openfeign网络通信方式
如果不做特殊配置,OpenFeign默认使用jdk自带的HttpURLConnection,我们知道HttpURLConnection没有连接池、性能和效率比较低,如果采用默认,很可能会遇到性能问题导致系统故障。因此我们可以将其改为okhttp或者httpclient。
8.1 Feign中http client
8.1.1 Apache HttpClient
可以采用Apache HttpClient,properties文件中增加下面配置
feign.httpclient.enabled=true
pom文件中增加依赖
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
<version>9.3.1</version>
</dependency>
8.1.2 OkHttpClient
也可以采用OkHttpClient,properties文件中增加下面配置
feign.okhttp.enabled=true
pom文件中增加依赖
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
<version>10.2.0</version>
</dependency>
8.2 Ribbon中的Http Client
通过OpenFeign作为注册中心的客户端时,默认使用Ribbon做负载均衡,Ribbon默认也是用jdk自带的HttpURLConnection,需要给Ribbon也设置一个Http client,比如使用okhttp,在properties文件中增加下面配置。
ribbon.okhttp.enabled=true
九、Openfeign日志级别
OpenFeign的日志级别有
NONE: 默认的,不显示任何日志。
BASIC: 仅记录请求方法、URL、响应状态码以及执行时间。
HEADERS:除了BASIC 中自定义的信息外,还有请求和响应的信息头。
FULL: 除了HEADERS中定义的信息外, 还有请求和响应的正文以及元数据。
自己写一个配置类
@Configuration
public class OpenFeignLogConfig {
@Bean
Logger.Level feignLoggerLeave(){
return Logger.Level.FULL;
}
}
配置文件
logging:
level:
*[feign日志以什么级别监控哪个接口]:
com.king.springcloud.service.OrderFeignService: debug
十、OpenFeign超时时间
10.1 全局超时时间
OpenFeign可以设置超时时间,简单粗暴,设置一个全局的超时时间,如下
feign.client.config.default.connectTimeout=2000
feign.client.config.default.readTimeout=60000
如果不配置超时时间,默认是连接超时10s,读超时60s,在源码feign.Request的内部类Options中定义。
10.2 单服务设置超时时间
需要对serviceC单独设置一个超时时间,代码如下
feign.client.config.serviceC.connectTimeout=2000
feign.client.config.serviceC.readTimeout=60000
这个时间会覆盖全局默认的超时时间。
十一、Ribbon超时时间
作为负载均衡,Ribbon超时时间也是可以配置的,可以在properties增加下面配置
ribbon.ConnectTimeout=2000
ribbon.ReadTimeout=11000
有文章讲ribbon配置的超时时间必须要满足接口响应时间,其实不然,配置feign的超时时间就足够了,因为它可以覆盖掉ribbon的超时时间。
十二、开启熔断
可以在properties增加下面配置
feign.hystrix.enabled=true
十三、开启重试
13.1 OpenFeign开启重试
OpenFeign默认是不支持重试的,可以在源代码FeignClientsConfiguration中feignRetryer中看出
@Bean
@ConditionalOnMissingBeanpublic
Retryer feignRetryer { return Retryer.NEVER_RETRY;}
要开启重试,我们可以自定义Retryer,比如下面这行代码
Retryer retryer = new Retryer.Default(100, 1000, 2);
表示每间隔100ms,最大间隔1000ms重试一次,最大重试次数是1,因为第三个参数包含了第一次请求。
13.2 Ribbon重试
13.2.1 拉取服务列表
Ribbon默认从服务端拉取列表的时间间隔是30s,这个对优雅发布很不友好,一般我们会把这个时间改短,如下改成3s
myService.ribbon.ServerListRefreshInterval=3
其中myService
是你的目的地微服务的名称
13.2.2 重试
Ribbon重试有不少需要注意的地方,这里分享4个。
1、同一实例最大重试次数,不包括首次调用,配置如下
serviceC.ribbon.MaxAutoRetries=1
这个次数不包括首次调用,配置了1,重试策略会先尝试在失败的实例上重试一次,如果失败,请求下一个实例。
2、同一个服务其他实例的最大重试次数,这里不包括第一次调用的实例。默认值为1
serviceC.ribbon.MaxAutoRetriesNextServer=1
3、是否对所有操作都重试,如果改为true,则对所有操作请求都进行重试,包括post,建议采用默认配置false
serviceC.ribbon.OkToRetryOnAllOperations=false
4、对指定的http状态码进行重试
serviceC.retryableStatusCodes=404,408,502,500
十四、使用OpenFeign做http客户端
即使不用注册中心,使用OpenFeign做普通http客户端也是很方便的,但是有三点需要注意:
- 不用配置ribbon相关参数。
- 使用RestTemplate调用时,不考虑负载均衡。
- 使用过程中OpenFeign要组装出自己的一套请求,跟直接使用http客户端比,会有一定开销。