原文网址:Spring Cloud Feign--常用的配置_IT利刃出鞘的博客-CSDN博客
简介
本文介绍Feign的配置方式。包括:@FeignClient、Hystrix、客户端类型、开启日志
@FeignClient
法1:使用 configuration = xxx.class属性
此法只会让加了此属性的FeignClient生效,不加的不会使用xxx.class配置。
法2:使用@Configuration写一个配置类
此法是全局配置,所有的FeignClient都会使用这个配置。
如:
package com.example.product.config;
import feign.Logger;
import feign.form.spring.SpringFormEncoder;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignConfiguration {
@Autowired
private ObjectFactory<HttpMessageConverters> messageConverters;
@Bean
public SpringFormEncoder feignFormEncoder() {
return new SpringFormEncoder(new SpringEncoder(messageConverters));
}
@Bean
public Logger.Level logger() {
// 为了方便问题排查,把http的请求和响应全部打印出来
return Logger.Level.FULL;
}
}
Hystrix
官网文档:Configuration · Netflix/Hystrix Wiki · GitHub
启用Hystrix
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
所有Feign都开启hystrix
修改application.yml:
feign:
hystrix:
enabled: true
部分Feign开启hystrix
调用方的@RequstMapping对应的方法上添加:@HystrixCommand
其属性 fallbackMethod 可以指定降级方法
部分Feign关闭hystrix
// Configuration1表示feign的自定义配置类
@FeignClient(name = "microservice-provider-user", configuration = Configuration1.class)
@Configuration
public class Configuration1 {
//禁用当前配置的hystrix,局部禁用
@Bean
@Scope("prototype")
public Feign.Builder feignBuilder() {
return Feign.builder();
}
}
Command Properties
Command属性主要用来控制HystrixCommand命令的行为,配置前缀为:hystrix.command.default,它主要分下面的类别:
1、Execution(控制HystrixCommand.run()的执行)
execution.isolation.strategy:该属性用来设置HystrixCommand.run()执行的隔离策略。默认为THREAD。
execution.isolation.thread.timeoutInMilliseconds:该属性用来配置HystrixCommand执行的超时时间,单位为毫秒。
execution.timeout.enabled:该属性用来配置HystrixCommand.run()的执行是否启用超时时间。默认为true。
execution.isolation.thread.interruptOnTimeout:该属性用来配置当HystrixCommand.run()执行超时的时候是否要它中断。
execution.isolation.thread.interruptOnCancel:该属性用来配置当HystrixCommand.run()执行取消时是否要它中断。
execution.isolation.semaphore.maxConcurrentRequests:当HystrixCommand命令的隔离策略使用信号量时,该属性用来配置信号量的大小。当最大并发请求达到该设置值时,后续的请求将被拒绝。
execution.isolation.strategy
请求@HystrixCommand注释修饰的一个服务时,HystrixCommand的运行逻辑有可能是在该请求的主线程上一并执行,也有可能是单独起一个线程来执行,这取决于我们如何设置Hystrix线程的隔离策略。
execution.isolation.strategy属性就是用来设置HystrixCommand.run()执行的隔离策略的,有两种隔离策略,分别是线程隔离和信号量隔离,即“THREAD”和“SEMAPHORE”,系统默认为“THREAD”。
它们的含义是:
- THREAD(线程隔离):使用该方式,HystrixCommand将会在单独的线程上执行,并发请求受线程池中线程数量的限制。
- SEMAPHORE(信号量隔离):使用该方式,HystrixCommand将会在调用线程上执行,开销相对较小,并发请求受到信号量个数的限制。
Hystrix中默认并且推荐使用线程隔离(THREAD),因为这种方式有一个除网络超时以外的额外保护。
一般来说,只有当调用负载异常高时(例如每个实例每秒调用数百次)才需要信号量隔离,因为这种场景下使用THREAD开销会比较高。信号量隔离一般仅适用于非网络调用的隔离。
正常情况下,默认为线程隔离, 保持默认即可。
如果发生找不到上下文运行时异常,则需要使用相同的线程(因为请求是一个线程,@HystrixCommand是另一个隔离的线程),可考虑将隔离策略设置为SEMAPHORE。
2、Fallback(控制HystrixCommand.getFallback()的执行)
fallback.isolation.semaphore.maxConcurrentRequests:该属性用来设置从调用线程中允许HystrixCommand.getFallback()方法执行的最大并发请求数。当达到最大并发请求时,后续的请求将会被拒绝并抛出异常。
fallback.enabled:该属性用来设置服务降级策略是否启用,默认是true。如果设置为false,当请求失败或者拒绝发生时,将不会调用HystrixCommand.getFallback()来执行服务降级逻辑。
3、Circuit Breaker(控制HystrixCircuitBreaker的行为)
circuitBreaker.enabled:确定当服务请求命令失败时,是否使用断路器来跟踪其健康指标和熔断请求。默认为true。
circuitBreaker.requestVolumeThreshold:用来设置在滚动时间窗中,断路器熔断的最小请求数。例如,默认该值为20的时候,如果滚动时间窗(默认10秒)内仅收到19个请求,即使这19个请求都失败了,断路器也不会打开。
circuitBreaker.sleepWindowInMilliseconds:用来设置当断路器打开之后的休眠时间窗。休眠时间窗结束之后,会将断路器设置为“半开”状态,尝试熔断的请求命令,如果依然时候就将断路器继续设置为“打开”状态,如果成功,就设置为“关闭”状态。
circuitBreaker.errorThresholdPercentage:该属性用来设置断路器打开的错误百分比条件。默认值为50,表示在滚动时间窗中,在请求值超过requestVolumeThreshold阈值的前提下,如果错误请求数百分比超过50,就把断路器设置为“打开”状态,否则就设置为“关闭”状态。
circuitBreaker.forceOpen:该属性默认为false。如果该属性设置为true,断路器将强制进入“打开”状态,它会拒绝所有请求。该属性优于forceClosed属性。
circuitBreaker.forceClosed:该属性默认为false。如果该属性设置为true,断路器强制进入“关闭”状态,它会接收所有请求。如果forceOpen属性为true,该属性不生效。
4、Metrics(该属性与HystrixCommand和HystrixObservableCommand执行中捕获的指标相关)
metrics.rollingStats.timeInMilliseconds:该属性用来设置滚动时间窗的长度,单位为毫秒。该时间用于断路器判断健康度时需要收集信息的持续时间。断路器在收集指标信息时会根据设置的时间窗长度拆分成多个桶来累计各度量值,每个桶记录了一段时间的采集指标。例如,当为默认值10000毫秒时,断路器默认将其分成10个桶,每个桶记录1000毫秒内的指标信息。
metrics.rollingStats.numBuckets:用来设置滚动时间窗统计指标信息时划分“桶”的数量。默认值为10。
metrics.rollingPercentile.enabled:用来设置对命令执行延迟是否使用百分位数来跟踪和计算。默认为true,如果设置为false,那么所有的概要统计都将返回-1。
metrics.rollingPercentile.timeInMilliseconds:用来设置百分位统计的滚动窗口的持续时间,单位为毫秒。
metrics.rollingPercentile.numBuckets:用来设置百分位统计滚动窗口中使用桶的数量。
metrics.rollingPercentile.bucketSize:用来设置每个“桶”中保留的最大执行数。
metrics.healthSnapshot.intervalInMilliseconds:用来设置采集影响断路器状态的健康快照的间隔等待时间。
5、Request Context(涉及HystrixCommand使用HystrixRequestContext的设置。)
requestCache.enabled:用来配置是否开启请求缓存。
requestLog.enabled:用来设置HystrixCommand的执行和事件是否打印到日志的HystrixRequestLog中。
Collapser Properties
配置前缀为 hystrix.collapser.default
- maxRequestsInBatch:该属性用来设置一次请求合并批处理允许的最大请求数量,默认值 Integer.MAX_VALUE
- timerDelayInMilliseconds:该属性用来设置批处理过程中每个命令延迟的时间,单位毫秒,默认值 10
- requestCache.enabled:该属性用来设置批处理过程中是否开启请求缓存,默认值 true
Thread Pool Properties
配置前缀为 hystrix.threadpool.default
- coreSize:该属性用来设置执行命令线程池的核心线程数,该值也就是命令执行的最大并发量,默认值 10
- maxQueueSize:该属性用来设置线程池的最大队列大小,当设置为 -1 时,线程池将使用 SynchronousQueue 实现的队列,否则使用 LinkedBlockingQueue 实现的队列,默认值 -1
- queueSizeRejectionThreshold :该属性用来为队列设置拒绝阈值,即使队列没有到达最大值也能拒绝请求,该属性主要对 LinkedBlockingQueue 队列的补充,默认值 5,当 maxQueueSize 属性为 -1 时候,该属性无效
- metrics.rollingPercentile.timeInMilliseconds:该属性用来设置线程池统计的滚动窗口的持续时间,单位:毫秒,默认值 10000
- metrics.rollingPercentile.numBuckets:该属性用来设置线程池统计窗口中使用"桶"的数量,默认值 10
Ribbon
另见《SpringCloud微服务实战》=> 第6章 声明式服务调用:Spring Cloud Feign=> Ribbon配置
饥饿加载
饥饿加载:即在启动的时候便加载所有配置项的应用程序上下文。
Hystrix默认的超时时间是1秒,如果超过这个时间尚未响应,将会进入fallback代码。而首次请求往往会比较慢(由于Ribbon是懒加载的,在首次请求时,才会开始初始化相关类),这个响应时间可能就大于1秒了。
ribbon:
# 饥饿加载
eager-load:
# 是否开启饥饿加载
enabled: true
# 饥饿加载的服务
clients: demo-goods,demo-product
超时时间
ribbon:
# http建立连接的超时时间,毫秒
ConnectTimeout: 60000
# http读取响应(也就是处理请求)超时时间,毫秒
ReadTimeout: 60000
也可以为每个Ribbon客户端设置不同的超时时间, 通过服务名称进行指定:
ribbon-config-demo.ribbon.ConnectTimeout=2000
ribbon-config-demo.ribbon.ReadTimeout=5000
重试机制
在集群环境中,用多个节点来提供服务,难免会有某个节点出现故障。用 Nginx 做负载均衡的时候,如果你的应用是无状态的、可以滚动发布的,也就是需要一台台去重启应用,这样对用户的影响其实是比较小的,因为 Nginx 在转发请求失败后会重新将该请求转发到别的实例上去。
由于 Eureka 是基于 AP 原则构建的,牺牲了数据的一致性,每个 Eureka 服务都会保存注册的服务信息,当注册的客户端与 Eureka 的心跳无法保持时,有可能是网络原因,也有可能是服务挂掉了。
在这种情况下,Eureka 中还会在一段时间内保存注册信息。这个时候客户端就有可能拿到已经挂掉了的服务信息,故 Ribbon 就有可能拿到已经失效了的服务信息,这样就会导致发生失败的请求。
这种问题我们可以利用重试机制来避免。重试机制就是当 Ribbon 发现请求的服务不可到达时,重新请求另外的服务。
ribbon:
# 同一台实例最大重试次数,不包括首次调用。默认值为0
MaxAutoRetries: 0
# 同一个服务其他实例的最大重试次数,不包括第一次调用的实例。默认值为1
MaxAutoRetriesNextServer: 2
# 是否所有操作都重试。默认false:只有get请求会重试
OkToRetryOnAllOperations: true
Spring Cloud Finchley 版 Ribbon 的重试机制是默认开启的,默认重试一次。旧版本是默认关闭的,开启方法如下:
spring.cloud.loadbalancer.retry.enabled=true
服务列表更新频率
ribbon.ServerListRefreshInterval=2000
指定服务的配置
以上超时与重试的配置都是全局配置,也可以指定服务来配置,指定服务相比全局多了一个配置项:NFLoadBalancerRuleClassName。示例如下
### 针对单个服务的 Ribbon 配置
demo-goods:
ribbon:
# 基于配置文件形式的 针对单个服务的 Ribbon 负载均衡策略
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
ConnectTimeout: 2000
ReadTimeout: 10000
MaxAutoRetries: 0
MaxAutoRetriesNextServer: 2
OkToRetryOnAllOperations: true
客户端类型
简介
说明
Feign是对普通HTTP客户端的一层封装,其目的是降低集成成本、提升可靠性。Feign支持三种HTTP客户端,如下:
- HttpURLConnection:JDK自带的,不支持线程池,性能差。(Feign默认客户端)
- HttpClient:从5.0版本开始支持HTTP/2。
- OkHttp:支持HTTP/2。
HttpClient与OkHttp的区别
项 | HttpClient | OkHttp |
易用性 | 不如OkHttp易用 | 易用 |
限制性 | 可修改超时时间 | 不能修改超时时间。(例如创建单例连接后无法配置超时时间) |
性能 | 和OkHttp差不多 | 和HttpClient差不多 |
一般情况下,选用OkHttp,当然这两者也可同时使用
默认客户端的代码追踪
类 feign/Client$Default.java 中,可以看到,默认执行 http 请求的是 URLConnection:
public static class Default implements Client {
@Override
public Response execute(Request request, Options options) throws IOException {
HttpURLConnection connection = convertAndSend(request, options);
return convertResponse(connection).toBuilder().request(request).build();
}
...
}
负载均衡默认也是URLConnection:
类 org/springframework/cloud/openfeign/ribbon/FeignRibbonClientAutoConfiguration.java 中,可以看到引入了三个类:HttpClientFeignLoadBalancedConfiguration、OkHttpFeignLoadBalancedConfiguration、DefaultFeignLoadBalancedConfiguration。可以看到在 DefaultFeignLoadBalancedConfiguration 中,使用的是 Client.Default,即使用 URLConnection。
配置方法
公共依赖
新feign:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
旧feign
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
OkHttp
依赖
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
无需指定版本,它的版本已经被指定,指定的链路为:
org.springframework.cloud:spring-cloud-dependencies
=> org.springframework.cloud:spring-cloud-openfeign-dependencies
=> io.github.openfeign:feign-okhttp
不要随意指定版本,否则会容易出问题。
application.yml
feign:
httpclient:
enabled: false
okhttp:
enabled: true
HttpClient
依赖
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
无需指定版本,它的版本已经被指定,指定的链路为:
org.springframework.cloud:spring-cloud-dependencies
=> org.springframework.cloud:spring-cloud-openfeign-dependencies
=> io.github.openfeign:feign-okhttp
不要随意指定版本,否则会容易出问题。
application.yml
feign:
httpclient:
enabled: true
开启日志
其他网址
Spring Cloud 学习笔记(七)一Spring Cloud--Feign-advance - ZFC's blog
法1:application.yml
application.yml
logging:
level:
com.example.product.feign.UserFeignClient: debug
FeignClient接口
package com.example.product.feign;
import com.example.product.entity.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(name = "user")
public interface UserFeignClient {
@GetMapping("/user/{id}")
User getUser(@PathVariable("id") Long id);
}
法2:配置类中配置