Ribbon配置
全局配置
由于Spring cloud Feign
的客户端负载均衡是通过spring cloud Ribbon
实现的,所以我们可以直接通过配置Ribbon客户端的方式来自定义各个服务客户端调用的参数。
ribbon.ConnectTimeout=500
ribbon.ReadTimeOut=5000
指定服务配置
大多数情况下,我们对于服务调用的超时时间可能会根据实际服务的特性做一些调整,所以仅仅依靠默认的全局配置是不行的。在使用spring cloud feign
的时候,针对各个服务客户端进行个性化配置的方式与使用Spring Cloud Ribbon
时的配置方式时一样的,都采用了<client>.ribbon.key=value
的格式进行设置。我们使用@Feign(value="user-service")
来创建一个Feign客户端的时候,同时也创建了一个名为user-service
的Ribbon
客户端。所以我们也可以使用@Feign
中的name
或者value
属性只来设置对应的ribbon
参数,比如:
user-service.ribbon.ConnectTimeout=500
user-service.ribbon.ReadTimeout=2000
user-service.ribbon.OkToRetryOnAllOperations=true
user-service.ribbon.MaxAutoRetriesNextServer=2
user-service.ribbon.MaxAutoRetries=1
重试机制
在spring cloud Feign
中默认实现了请求的重试机制,而上面对user-service
客户端的配置内容就是对于请求超时以及重试配置的详情,
@GetMapping
public String userHello() throws Exception{
ServiceInstance serviceInstance = client.getLocalServiceInstance();
//线程阻塞,测试超时
int sleeptime = new Random().nextInt(3000);
logger.info("sleeptime:"+sleeptime);
Thread.sleep(sleeptime);
logger.info("/user,host:"+serviceInstance.getHost()+",service id:"+serviceInstance.getServiceId()+",port:"+serviceInstance.getPort());
return "hello world";
}
user-service.ribbon.ConnectTimeout=500
user-service.ribbon.ReadTimeout=2000
user-service.ribbon.OkToRetryOnAllOperations=true
user-service.ribbon.MaxAutoRetriesNextServer=2
user-service.ribbon.MaxAutoRetries=1
在pay-service
应用中增加了重试配置参数,其中,由于user-service.ribbon.MaxAutoRetries
设置为1,所以重试策略先尝试访问首选案例一次,失败后才更换实例访问,而更换实例访问的次数通过user-service.ribbon.MaxAutoRetriesNextServer
参数设置为2,所以会尝试更换两次实例进行重试。
Ribbon的超时与Hystrix的超时是两个概念。一般需要让hystrix的超时时间大于Ribbon的超时时间,否则Hystrix命令超时后,改命令直接熔断,重试机制就没有任何意义了。
Hystrix配置
spring cloud Feign
中,除了引入了用于客户端负载均衡的spring cloud Ribbon
之外,还引入了服务保护了容错的工具Hystrix
,spring cloud feign
客户端的方法都封装到Hystrix
命令中进行服务保护。
全局配置
对于Hystrix的全局配置同spring cloud Ribbon
的全局配置一样,直接使用它的默认配置前缀hystrix.command.default
就可以进行设置,比如设置全局的超时时间:
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=5000
在对hystrix进行设置之前,需要确认feign.hystrix.enabled
参数没有被设置为false,否则该参数设置会关闭Feign客户端的Hystrix支持。而对于我们之前测试重试机制时,对于Hystrix的超时时间控制除了可以使用上面的配置来增加熔断超时时间,也可以通过feign.hystrix.enabled=false
来关闭Hystrix功能,或者使用hystrix.command.default.execution.timeout.enabled=false
来关闭熔断功能。
禁用Hystrix
在spring cloud feign
中,可以通过feign.hystrix.enabled=false
来关闭Hystrix功能。另外,如果不想全局地关闭Hystrix支持,而只想针对某个服务客户端关闭Hystrix支持时,需要通过使用@Scope("protototype")
注解为指定的客户端配置Feign.Builder
实例,
@Configuration
public class DisableHystrixConfigutation {
@Bean
@Scope("prototype")
public Feign.Builder feignBuilder(){
return Feign.builder();
}
}
在pay-service
服务的user-service
接口中引入该配置。
@FeignClient(value = "user-service",configuration = DisableHystrixConfigutation.class)
...
指定命令配置
对于Hystrix命令的配置,在实际应用时往往也会根据实际业务情况制定出不同的配置方案。配置方法也跟传统的Hystrix命令的参数配置相似,采用hystrix.command.<commandKey>
作为前缀。而<commandKey>
默认情况下会采用feign客户端中的方法名作为标识,所以,针对上面的hello方法,可以如下配置:
hystrix.command.hello.isolation.thread.timeoutInmilliseconds=5000
需要注意的是,由于方法名有可能会重复,这个时候相同的方法名的hystrix配置会共用,所以在进行方法与配置的时候需要做好一定的规划,当然也可以重写Feign.Builder
的实现,并在应用主类中创建它的实例来覆盖自动化配置的HystrixFegin.Builder
实现。
服务降级配置
Hystrix提供的服务降级是服务容错的重要功能,由于Spring cloud feign
在定义服务客户端的时候与Spring cloud Ribbon
有很大的差别,HystrixCommand
定义被封装起来,我们无法像之前介绍spring cloud hystrix
时,通过@HystrixCommand
注解的fallback
参数那样来指定具体的服务降级处理方法。但是,spring cloud feign
提供了另外一种简单的定义方式,
定义一个Feign客户端的服务降级类UserServiceFallback,实现UserService接口,其中每个重写方法的实现逻辑都可以用来定义相应的服务降级逻辑,具体如下:
@Component
public class UserServiceFallback implements UserService{
@Override
public String index() {
return "error";
}
@Override
public String hello() {
return "hello error";
}
@Override
public String hello1(String username) {
return "hello username is null";
}
@Override
public User hello2(String username, Integer age) {
return new User("未知",0);
}
@Override
public String hello3(User user) {
return "user error";
}
}
- 在服务绑定接口
user-service
中,通过@FeignClient
注解的fallback
属性来指定对应的服务降级实现类:
@FeignClient(value = "user-service",fallback = UserServiceFallback.class)
public interface UserService {
@RequestMapping("/user/index")
String index();
@RequestMapping("/user/hello")
String hello();
@RequestMapping(value = "/user/hello1",method = RequestMethod.GET)
String hello1(@RequestParam("username") String username);
@RequestMapping(value = "/user/hello2",method = RequestMethod.GET)
User hello2(@RequestHeader("username") String username, @RequestHeader("age") Integer age);
@RequestMapping(value = "/user/hello3",method = RequestMethod.POST)
String hello3(@RequestBody User user);
}
测试,停止用户的服务:
localhost:7070/pay/hello1?username=zhihao.miao
localhost:7070/pay/hello2
localhost:7070/pay/hello3
返回了我们在UserServiceFallback
中定义的每个方法的降级的重写函数的实现。
fallbackFactory参数的使用
If one needs access to the cause that made the fallback trigger, one can use the fallbackFactory attribute inside @FeignClient.
如果需要访问到造成回退的具体原因,可以使用@FeignClient.注解的fallbackFactory属性。
@Component
public class HystrixClientFallbackFactory implements FallbackFactory<UserService> {
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public UserService create(Throwable throwable) {
logger.info("user service exception:" + throwable.getMessage());
return new HystrixClientWithFallBackFactory(){
@Override
public User hello2(String username, Integer age) {
return super.hello2(username, age);
}
};
}
}
定义HystrixClientWithFallBackFactory实现由@Feign注解标记的接口,我这边就实现了hello2方法,只测试这个方法。
public class HystrixClientWithFallBackFactory implements UserService{
@Override
public String index() {
return null;
}
@Override
public String hello() {
return null;
}
@Override
public String hello1(String username) {
return null;
}
@Override
public User hello2(String username, Integer age) {
User user = new User();
user.setAge(0);
user.setUsername("zhihao.miao");
user.setId(-1);
return user;
}
@Override
public String hello3(User user) {
return null;
}
}
测试,断开User服务之后,进入保护模式,执行HystrixClientWithFallBackFactory中的回退操作,
控制台上输出错误日志:
其他配置
请求压缩
spring cloud feign
支持对请求与相应进行GZIP压缩,以减少通信过程中的性能损耗,我们只需要通过下面的两个参数设置,就能开启请求与相应的压缩功能。
feign:
compression:
request:
enabled: true
response:
enabled: true
同时,我们还可以对请求压缩做一些更细致的设置,比如下面的配置内容指定压缩的请求数据类型,并设置了请求压缩的大小下限,只有超过了这个大小的请求才会对其进行压缩。
feign:
compression:
request:
enabled: true
mime-types: text/xml,application/xml,application/json
min-request-size: 2048
而mime-types
属性和min-request-size
都是默认值
参考资料
Feign request/response compression
日志配置
spring cloud Feign
在构建被@FeignClient
注解修饰的服务客户端时,会为每一个客户端都创建一个feign.Logger
实例,我们可以利用改日志对象的DEBUG
模式来帮助分析Feign的请求细节。可以在application.yml
配置logging.level.<feignClient>
的参数配置格式来开启指定feign客户端的debug日志,其中<feignClient>
为feign客户端定义接口的完整路径
logging:
level:
com.zhihao.miao.pay.service.UserService: debug
但是,只添加了该配置还无法实现对debug日志的输出。这是因为feign客户端默认的Logger.Level对象定义为NONE级别,该级别不会记录任何Feign调用过程中的信息,所以我们需要调整它的级别,针对全局的日志级别,可以在应用主类中加入Logger.Level的Bean创建,
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class PayApplication {
public static void main(String[] args) {
SpringApplication.run(PayApplication.class,args);
}
@Bean
Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
}
也可以实现配置类,然后在Feign客户端来指定配置类以实现是否需要调整不同的日志级别,比如说下面的实现:
@Configuration
public class FullLogConfiguration {
@Bean
Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
}
@FeignClient(value = "user-service",configuration = FullLogConfiguration.class)
public interface UserService {
@RequestMapping("/user/index")
String index();
@RequestMapping("/user/hello")
String hello();
@RequestMapping(value = "/user/hello1",method = RequestMethod.GET)
String hello1(@RequestParam("username") String username);
@RequestMapping(value = "/user/hello2",method = RequestMethod.GET)
User hello2(@RequestHeader("username") String username, @RequestHeader("age") Integer age);
@RequestMapping(value = "/user/hello3",method = RequestMethod.POST)
String hello3(@RequestBody User user);
}
访问localhost:7070/pay/hello1?username=zhihao.miao
接口,控制台上打印如下信息:
对于Feign的Logger级别主要有下面4类,可根据实际需要进行调整使用:
- none:不记录任何信息
- basic:仅记录请求方法,url以及响应状态码和执行时间
- headers:除了记录basic级别的信息之外,还会记录请求和响应的头信息。
- FULL:记录所有请求与响应的明细,包括头信息,请求体,元数据等。
参考资料
Feign logging
代码地址
代码地址