SpringCloud详解 第四章声明式服务调用 Feign(二)
本章主要梳理Feign中Ribbon配置
一、全局配置
ribbon.ConnectTimeout = 500 //请求连接的超时时间。 ribbon.ReadTimeout = 2000 //请求处理的超时时间。
二、指定服务配置
大多数情况下,我们对于服务调用的超时时间可能会根据实际服务的特性做 一 些调整,所以仅仅依靠默认的全局配置是不行的。 在使用SpringCloud Feign的时候,针对各个服务客户端进行个性化配置的方式与使用SpringCloud Ribbon时的配置方式是 一 样的, 都采用<client>. ribbon.key=value 的格式进行 设置。在定义Feign客户端的时候, 我们使用了@FeignClient注解。 在初始化过程中,SpringCloud Feign会根据该注解的name属性或value属性指定的服务名, 自动创建一 个同名的Ribbon客户端。也就是说,在之前的示例中,使用@FeignClient(value= "cloud-provider")来创 建 Feign 客 户 端 的 时 候 , 同时也创建了一个 名为cloud-provider的Ribbon客户端。 既然如此, 我们就可以使用@FeignClient注解中的name或value属性值来设置对应的Ribbon参数, 比如:
cloud-provider.ribbon.ConnectTimeout = 500 //请求连接的超时时间。 cloud-provider.ribbon.ReadTimeout = 2000 //请求处理的超时时间。 cloud-provider.ribbon.OkToRetryOnAllOperations = true //对所有操作请求都进行重试。 cloud-provider.ribbon.MaxAutoRetriesNextServer = 2 //切换实例的重试次数。 cloud-provider.ribbon.MaxAutoRetries = 1 //对当前实例的重试次数。
或这样写
user-service: # 注意这是提供某一服务系统的服务名称,仅对这一服务起作用,不能随意抒写 ribbon: # NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 修改ribbon中默认的轮询为随机(采用spring系统提供包) ConnectTimeout: 250 # Ribbon的连接超时时间 ReadTimeout: 1000 # Ribbon的数据读取超时时间 OkToRetryOnAllOperations: true # 是否对所有操作都进行重试 MaxAutoRetriesNextServer: 1 # 切换实例的重试次数 MaxAutoRetries: 1 # 对当前实例的重试次数
三、重试机制
在 Spring Cloud Feign 中默认实 现了 请 求 的重 试 机 制 , 而上面我 们对 于 cloud-provider 客户端的配置内容就是对于请求超时以及重试机制配置的详情.
这里需要注意一 点, Ribbon的超时 与Hystrix的超时是两个概念。 为了让上述实现有效,我们需要 让Hystrix的超时时间大于Ribbon的超时时间, 否则Hystrix命令超时后, 该命令直接熔断, 重试机制就 没有任何意义了。
要么设置 Hystrix 的超时时间比Ribbon大(hystrix.command.default.execution.isolation.thread. timeoutInMilliseconds = 5000),要么直接关闭 Hystrix 超时配置(feign.hystrix.enabled= false).配置的时候不提示没关系,配置上就有效果。
如果不想全局关闭可以只针对服务进行关闭:@FeignClient(name="HELLO - SERVICE", configuration = DisableHystrixConfiguration.class)
在 feign-server应用中增加上文中提到的重试配置参数。其中,由于 cloud-provider.ribbon.MaxAutoRetries 设置为 1, 所以重试策略先尝试访问首选实例 一 次, 失败后才更换实例访问, 而更换实例访问的次数通过 cloud-provider.ribbon.MaxAutoRetriesNextServer 参数 设置为 2, 所以会尝试更换两次实例进行重试。
最后, 启动这些应用, 并尝试访问几次 http://localhost:9012/feign/hello 接口。可以通过 cloud-provider 服务打印请求信息,修改对应/hello接口如下
public String hello(String id) throws InterruptedException { // 测试fegin 超时重试代码开始 List<ServiceInstance> instances = client.getInstances("feign-server"); //测试超时 int sleepTime = new Random().nextInt(3000); System.out.println("sleepTime:" + sleepTime); Thread.sleep(sleepTime); System.out.println("/hello, host:" + instances.get(0).getHost() + instances.get(0).getServiceId()); // 测试fegin 超时重试代码结束 return "Hello Eureka Provider1"; }
然后控制台来查看重试的日志。
从控制台输出中,我们可以看到这次访问的第 一 次请求延迟时间为 2088毫秒,由于超时时间设置为 2000 毫秒, Feign 客户端发起了重试,第二次请求的延迟为 1338 秒,没有超时 。Feign客户端在进行服务调用时, 虽然经历了一 次失败,但是通过重试机制, 最终还是获得了请求结果。所以, 对于 重试机制的实现, 对于构建高可用的 服务集群来说非常重要, 而 SpringCloud Feign也为其提供了足够的支持。
四、Ribbon和 Feign的区别:
- Ribbon添加maven依赖 spring-starter-ribbon 使用@RibbonClient(value="服务名称") 使用RestTemplate调用远程服务对应的方法。feign添加maven依赖 spring-starter-feign 服务提供方提供对外接口 调用方使用 在接口上使用 @FeignClient("指定服务名")
- Ribbon和Feign都是用于调用其他服务的,不过方式不同。
- 启动类使用的注解不同,Ribbon用的是@RibbonClient,Feign用的是@EnableFeignClients。
- 服务的指定位置不同,Ribbon是在@RibbonClient注解上声明,Feign则是在定义抽象方法的接口中使用@FeignClient声明。
- 调用方式不同,Ribbon需要自己构建http请求,模拟http请求然后使用RestTemplate发送给其他服务,步骤相当繁琐。
- Feign则是在Ribbon的基础上进行了一次改进,采用接口的方式,将需要调用的其他服务的方法定义成抽象方法即可,不需要自己构建http请求。不过要注意的是抽象方法的注解、方法签名要和提供服务的方法完全一致。