Feign中的Ribbon配置

  由于Spring Cloud Feign的客户端负载均衡是通过Spring Cloud Ribbon实现的,所以我们可以直接通过配置Ribbon客户端的方式来自定义各个服务客户端调用多个参数。

  • 全局配置

   全局配置的方法非常简单,直接使用ribbon.<key>=<value>的方式来设置ribbon的各项默认参数。例如,修改默认的客户端调用超时时间:

#请求连接的超时时间
ribbon.ConnectTimeout=500
#请求处理的超时时间
ribbon.ReadTimeout=2000
  • 指定服务配置

  大多数情况,我们对于服务的超时时间可能会不同的服务特性做一些调整,针对各个服务客户端进行个性化配置的方式与使用Spring Cloud Ribbon时的配置方式是一样的,都采用<client>.ribbon.key=value 的格式进行设置,其中<client>指的是 @FeignClient(value="HELLO-SERVICE")中的value值,在使用@FeignClient(value="HELLO-SERVICE")来创建Feign客户端的时候,同时也创建了一个名为HELLO-SERVICE的Ribbon客户端,具体配置如下:

HELLO-SERVICE.ribbon.ConnectTimeout=500
HELLO-SERVICE.ribbon.ReadTimeout=2000
HELLO-SERVICE.ribbon.OkToRetryOnAllOperations=true
#最多重试服务器的个数
HELLO-SERVICE.ribbon.MaxAutoRetriesNextServer=2
#每台服务器最多重试次数,首次调用除外
HELLO-SERVICE.ribbon.MaxAutoRetries=1
  • 重试机制

  在Spring Cloud Feign中默认实现了请求的重试机制,而上面标红的就是对HELLO-SERVICE客户端的配置内容就是对于请求超时以及重试机制的配置,我们可以通过修改之前的示例做一些验证。在hello-service应用的/hello接口实现中,增加一个随机延迟,比如:

 package com.server.provide.web;

 import java.util.List;
import java.util.Random; import org.apache.catalina.servlet4preview.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.serviceregistry.Registration;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController; @RestController
public class HelloController {
@Autowired
private Registration registration; // 服务注册
@Autowired
private DiscoveryClient discoveryClient; // 服务发现客户端
private static final Logger log = LoggerFactory.getLogger(HelloController.class);
@RequestMapping("/hello")
public String hello(HttpServletRequest request) throws Exception {
//测试超时
int sleepTime = new Random().nextInt(3000);
log.info("sleepTime"+sleepTime);
Thread.sleep(sleepTime);
log.info(request.getRemoteAddr()+","+request.getLocalName()+","+registration.getServiceId()+","+serviceInstance().getServiceId());
return "hello I am provider";
} @RequestMapping("/hello1")
public String hello(@RequestParam String name) {
return "Hello "+name;
} @RequestMapping("/hello2")
public User hello(@RequestHeader String name,@RequestHeader Integer age) {
return new User(name,age);
} @RequestMapping("/hello3")
public String hello(@RequestBody User user) {
return "Hello "+user.getName()+","+user.getAge();
} /**
* 获取当前服务的服务实例
*
* @return ServiceInstance
*/
public ServiceInstance serviceInstance() {
List<ServiceInstance> list = discoveryClient.getInstances(registration.getServiceId());
if (list != null && list.size() > 0) {
return list.get(0);
}
return null;
} }

  在feign-consumer应用中增加上文中提到的重试配置参数。其中HELLO-SERVICE.ribbon.MaxAutoRetries=1代表重试机制在失败一次后,先尝试访问第一次失败的实例一次,再次失败后才更换服务器访问,而更换服务访问的次数通过HELLO-SERVICE.ribbon.MaxAutoRetriesNextServer=2控制,代表会尝试更换两次服务进行重试。

  最后,启动这些应用,并尝试访问几次http://localhost:8092/feign-consumer接口。当请求发生超时的时候,我们在服务提供者的控制台中会获得如下内容输出(由于sleepTime的随机性,并不一定每次相同):

  

Feign中的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.enable=false来关闭熔断功能。

  • 禁用Hystrix

  上面我们提到了,在Spring Cloud Fegn中,可以通过feign.hystrix.enabled=false来关闭Hystrix功能。如果不想全局的关闭Hystrix支持,而只想针对某个服务客户端关闭Hystrix支持时,需要通过使用@Scope("prototype")注解为指定的客户端配置Feign.Builder实例,详细实现步骤如下:

  构建一个关闭Hystrix的配置类

 @Configuration
public class DisableHystrixConfiguration { @Bean
@Scope("prototype")
public Feign.Builder feignBuilder(){ return Feign.builder();
} }

  在HelloService的@FeignClient注解中,通过configuration参数引入上面实现的配置

 @FeignClient(name="feign-provide",configuration=DisableHystrixConfiguration.class)
public interface HelloService { @RequestMapping(value="/hello")
String hello();
@RequestMapping(value="/hello1",method=RequestMethod.GET)
String hello(@RequestParam("name") String name);
@RequestMapping(value="/hello2",method=RequestMethod.GET)
String hello(@RequestHeader("name") String name,@RequestHeader("age") Integer age);
@RequestMapping(value="/hello3",method=RequestMethod.POST)
String hello(@RequestBody User user); }
  • 指定命令配置

  配制方法也跟传统的Hystrix命令的参数配置相似,采用hystrix.command.<commandKey>作为前缀。而<commandKey>默认情况下会采用Feign客户端中的方法名作为标识,所以,针对上一节介绍的尝试机制中对/hello接口的熔断超时时间的配置可以通过其方法名作为<commandKey>来进行配置:

hystrix.command.hello.execution.isolation.thread.timeoutInMilliseconds=5000
  • 服务降级配置

  Hystrix提供的服务降级是服务容错的重要功能,由于Spring Cloud Feign在定义服务客户端的时候与Spring Cloud Ribbon有很大差别,HystrixCommand定义被封装了起来,我们无法像之前介绍Spring Cloud Hystrix时,通过@HystrixCommand注解的fallback参数那样来制定具体的服务降级处理方法。但是,Spring Cloud Feign提供了另外一种简单的定义方式。

  服务降级逻辑的实现只需要为Feign客户端的定义接口编写一个具体的接口实现类。比如为HelloService接口实现一个服务降级类HelloServiceFallback,其中每个重写方法的实现逻辑都可以用来定义相应的服务降级逻辑:

 @Component
public class HelloServiceFallback implements HelloService { @Override
public String hello(String name) {
// TODO Auto-generated method stub
return "error";
} @Override
public String hello(User user) {
// TODO Auto-generated method stub
return "error";
} @Override
public String hello() {
// TODO Auto-generated method stub
return "error";
} @Override
public String hello(String name, Integer age) {
// TODO Auto-generated method stub
return "error";
} }

  在服务接口HelloService中,通过@FeignClient注解的fallback属性来制定对应的服务降级实现类。

 @FeignClient(name="feign-provide",fallback=HelloServiceFallback.class) //configuration=DisableHystrixConfiguration.class,
public interface HelloService { @RequestMapping(value="/hello")
String hello();
@RequestMapping(value="/hello1",method=RequestMethod.GET)
String hello(@RequestParam("name") String name);
@RequestMapping(value="/hello2",method=RequestMethod.GET)
String hello(@RequestHeader("name") String name,@RequestHeader("age") Integer age);
@RequestMapping(value="/hello3",method=RequestMethod.POST)
String hello(@RequestBody User user); }
  • 测试验证

  我们启动服务注册中心和feign-consumer,但不启动feign-provide服务,发送GET请求到http://localhost:8092/feign-consumer2,由于没有启动feign-provide服务,会直接触发服务降级,得到下面输出:


注释一:Spring Cloud中提供的DiscoveryClient类,虽然有 
ServiceInstance getLocalServiceInstance();方法,但是被标记为@Deprecated. 更为严重的是, Spring Cloud的Finchley版本中,getLocalServiceInstance方法从DiscoveryClient移除了,新版本中获取服务自身的ServiceInstance信息用registration.getServiceId()。

注释二:在使用指定命令配置的时候,需要注意,由于方法名很有可能重复,这个时候相同方法名的Hystrix配置会共用,所以在进行方法定义与配置的时候需要做好一定的规则。当然,也可以重写Feign.Builder的实现,并在应用主类中创建它的实例来覆盖自动化配置的HystrixFeign.Builder实现。

注释三:Feign对Hystrix的支持默认是关闭的,如果想开启对Hystrix的支持需要配置 feign.hystrix.enabled=true,并且需要把之前关闭Hystrix的配置类注释掉,方可开启服务降级功能,否则会报com.netflix.client.ClientException: Load balancer does not have available server for client:XXX。

SpringCloud开发学习总结(七)—— 声明式服务调用Feign(三)的更多相关文章

  1. SpringCloud 源码系列(6)—— 声明式服务调用 Feign

    SpringCloud 源码系列(1)-- 注册中心 Eureka(上) SpringCloud 源码系列(2)-- 注册中心 Eureka(中) SpringCloud 源码系列(3)-- 注册中心 ...

  2. SpringCloud开发学习总结(七)—— 声明式服务调用Feign(一)

    在实践的过程中,我们会发现在微服务架构中实现客户端负载均衡的服务调用技术Spring Cloud Ribbon<SpringCloud开发学习总结(四)—— 客户端负载均衡Ribbon> ...

  3. SpringCloud之声明式服务调用 Feign(三)

    一 Feign简介 Feign是一种声明式.模板化的HTTP客户端,也是netflix公司组件.使用feign可以在远程调用另外服务的API,如果调用本地API一样.我们知道,阿里巴巴的doubbo采 ...

  4. 004声明式服务调用Feign & 断路器Hystrix

    1.POM配置 和普通Spring Boot工程相比,添加了Eureka Client.Feign.Hystrix依赖和Spring Cloud依赖管理 <dependencies> &l ...

  5. Spring Cloud第七篇 | 声明式服务调用Feign

    本文是Spring Cloud专栏的第七篇文章,了解前六篇文章内容有助于更好的理解本文: Spring Cloud第一篇 | Spring Cloud前言及其常用组件介绍概览 Spring Cloud ...

  6. 【Dalston】【第三章】声明式服务调用(Feign)

    当我们通过RestTemplate调用其它服务的API时,所需要的参数须在请求的URL中进行拼接,如果参数少的话或许我们还可以忍受,一旦有多个参数的话,这时拼接请求字符串就会效率低下,并且显得好傻.那 ...

  7. 声明式服务调用Feign

    什么是 Feign Feign 是种声明式.模板化的 HTTP 客户端(仅在 consumer 中使用).   什么是声明式,有什么作用,解决什么问题? 声明式调用就像调用本地方法一样调用远程方法;无 ...

  8. Spring Cloud 声明式服务调用 Feign

    一.简介 在上一篇中,我们介绍注册中心Eureka,但是没有服务注册和服务调用,服务注册和服务调用本来应该在上一章就应该给出例子的,但是我觉得还是和Feign一起讲比较好,因为在实际项目中,都是使用声 ...

  9. Spring Cloud Feign 1(声明式服务调用Feign 简介)

    Spring Cloud Feign基于Netflix Feign 同时整合了Spring Cloud Ribbon和Spring Cloud Hytrix,除了提供两者的强大功能外,它还提供了一种声 ...

  10. SpringCloud开发学习总结(七)—— 声明式服务调用Feign(二)

    参数绑定 在上一章的示例中,我们使用Spring Cloud Feign实现的是一个不带参数的REST服务绑定.然而现实系统中的各种业务接口要比它复杂得多,我们有时会在HTTP的各个位置传入各种不同类 ...

随机推荐

  1. HDU 6138 Fleet of the Eternal Throne 后缀数组 + 二分

    Fleet of the Eternal Throne Problem Description > The Eternal Fleet was built many centuries ago ...

  2. aop中获取方法的注解

    @Around(value="@annotation(apiLog)") public Object around(ProceedingJoinPoint pjp, ApiLog ...

  3. fstab文件解析

    1 这个文件的用途 这个文件是启动时自动挂载指定的磁盘或者分区到系统目录下用的,提供给mount命令用. 2 文件解析 每一行是一次mount操作. 磁盘或者分区    挂载的目录     挂载的磁盘 ...

  4. gRPC错误码 http状态码 provide your APIs in both gRPC and RESTful style at the same time

    How gRPC error codes map to HTTP status codes in the response https://github.com/grpc-ecosystem/grpc ...

  5. C/C++ 操作符优先级

    不能光转贴,有空要熟悉之后,要写点心得.现在发现 . 的优先级确实很高. C: Precedence Operator Description Associativity 1 ++ -- Suffix ...

  6. thinkphp中的volist

    在thinkphp中,使用volist一定要注意,<volist name='' id=''></volist>,name和id的变量一定要不一致,如果一致的话会导致当voli ...

  7. React中Transition的作用

    /** * `Transaction` creates a black box that is able to wrap any method such that * certain invarian ...

  8. AjaxControlToolkit没有通过WebResource.axd加载css导致ajaxToolkit:TabPanel无法显示正确的样式

    https://stackoverflow.com/questions/3318092/what-is-webresource-axd WebResource.axd provides access ...

  9. BZOJ_1264_[AHOI2006]基因匹配Match_树状数组

    BZOJ_1264_[AHOI2006]基因匹配Match_树状数组 Description 基因匹配(match) 卡卡昨天晚上做梦梦见他和可可来到了另外一个星球,这个星球上生物的DNA序列由无数种 ...

  10. 「HNSDFZ暑期集训 测试1」「LuoguT36488」 连连看

    题目描述 给定一个n × m的矩形地图,每个各自上可能为空,可能有牌,牌上有一个数字. 对于两张同样数字的牌,如果我们可以在地图上用不超过三根水平或竖直,在地图界内,且不经过其他牌的线段将两张牌连起来 ...