美文网首页spring cloudspringcloud学习
spring cloud feign学习三:Feign的更多使用

spring cloud feign学习三:Feign的更多使用

作者: 二月_春风 | 来源:发表于2017-09-03 13:49 被阅读908次

    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-serviceRibbon客户端。所以我们也可以使用@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之外,还引入了服务保护了容错的工具Hystrixspring 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)
    ...
    

    参考资料
    Feign Hystrix Support

    指定命令配置

    对于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中的回退操作,


    控制台上输出错误日志:

    参考资料
    Feign Hystrix Fallbacks

    其他配置

    请求压缩

    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

    代码地址
    代码地址

    相关文章

      网友评论

        本文标题:spring cloud feign学习三:Feign的更多使用

        本文链接:https://www.haomeiwen.com/subject/nfzdjxtx.html