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

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

代码地址
代码地址

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容