目录
1:服务降级
1.1 feign实现服务降级
Spring Cloud 中,Feign默认整合了Hystrix,所以只需要在配置中启用Hystrix即可,如下是在application.yml中的配置:
feign:
hystrix:
enabled: true
feign实现回退方法有两种方式:fallback,FallbackFactory,其不能同时使用,只能用其中的一种。(1.1章节中的代码,延用了上一文章《声明式服务调用的实现(Feign)及其优化(Ribbon)》中的consumer,Controller api )
1.1.1 fallback方法回退
编写一个Feign Client的实现类,且在@FeignClient的fallback属性指定对应的类:
@Component
public class ErrorFallback implements BookConsumerControllerInterface {
@Override
public List<Book> getBookList() {
List<Book> booklist = new ArrayList<Book>();
Book book = new Book();
book.setId(404);
book.setAuthor("error");
book.setBookName("Error Fallback");
booklist.add(book);
return booklist;
}
@Override
public Book getBook(Integer id) {
Book book = new Book();
book.setId(id);
book.setAuthor("error");
book.setBookName("error name");
return book;
}
@Override
public Book getBook(Book book) {
return book;
}
@Override
public Book getBook(Integer id, String bookName, String author) {
Book book = new Book();
book.setId(id);
book.setAuthor(bookName);
book.setBookName(author);
return book;
}
@Override
public Book addBook(Book book) {
return book;
}
}
在@FeignClient的fallback属性指定对应的类
@FeignClient(name="bookshop-service-provider" ,fallback=ErrorFallback.class)
public interface BookConsumerControllerInterface extends BookController {
}
1.1.2 FallbackFactory方法回退
如下图,是Feign client及FallbackFactory接口的继承与实现关系,需要额外提出的是,本次代码中没有额外的实现BookConsumerControllerInterface接口类,而是以类中类在ErrorFallbackFactory类中实现。
实现FallbackFactory<BookConsumerControllerInterface>类:
@Component()
public class ErrorFallbackFactory implements FallbackFactory<BookConsumerControllerInterface> {
@Override
public BookConsumerControllerInterface create(Throwable arg0) {
return new BookConsumerControllerInterface() {
@Override
public List<Book> getBookList() {
List<Book> booklist = new ArrayList<Book>();
Book book = new Book();
book.setId(404);
book.setAuthor("error");
book.setBookName("error name");
booklist.add(book);
return booklist;
}
@Override
public Book getBook(Integer id) {
Book book = new Book();
book.setId(id);
book.setAuthor("error");
book.setBookName("error name");
return book;
}
@Override
public Book getBook(Book book) {
return book;
}
@Override
public Book getBook(Integer id, String bookName, String author) {
Book book = new Book();
book.setId(id);
book.setAuthor(bookName);
book.setBookName(author);
return book;
}
@Override
public Book addBook(Book book) {
return book;
}
};
}
}
在@FeignClient的fallbackFactory中指定对应的类。
@FeignClient(name="bookshop-service-provider" ,fallbackFactory=ErrorFallbackFactory.class)
public interface BookConsumerControllerInterface extends BookController {
}
1.2 Hystrix实现服务降级
hystrix提供了降级操作,可以实现一个fallback方法, 当请求后端服务出现异常的时候, 可以使用fallback方法返回的值. fallback方法的返回值一般是设置的默认值或者来自缓存。下述代码主要利用注解的方式来实现服务降级,Hystrix还可以实现HystrixCommand接口来实现降级。
1.2.1 引入Hystrix依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
1.2.2 启动类开启熔断
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
@EnableCircuitBreaker //开启熔断
public class BookshopConsumerHystrixApplication {
public static void main(String[] args) {
SpringApplication.run(BookshopConsumerHystrixApplication.class, args);
}
}
1.2.3 编写fallbackMethod方法
/**
* 以下四种情况会触发fallback调用
* 1:方法抛出非HystrixBadRequestException异常
* 2:方法调用超时
* 3:熔断器开启拦截调用
* 4:线程池/队列/信号量是否饱满
*
* 降级参数:
* fallback.enabled --- fallback是否可用----默认true---当执行失败或者请求被拒绝,是否尝试调用hystrixCommand.getFallback()
* fallback.isolation.semaphore.maxConcurrentRequests ---fallback最大并发度,默认10,如果并发数达到设置值,请求会被拒绝和抛出异常并且fallback不会被调用
* */
@HystrixCommand(fallbackMethod="getBookListFallback")
@RequestMapping(value="getbooklist",method=RequestMethod.GET)
public List<Book> getBookList(){
return bookCon.getBookList();
}
public List<Book> getBookListFallback() {
List<Book> bookList = new ArrayList<Book>();
Book book = new Book();
book.setAuthor("hystrix error");
book.setBookName("hystrix fallback");
book.setId(0);
bookList.add(book);
return bookList;
}
注意:fallbackMethod方法,需要和@HystrixCommand注解处于同一个类中,同时,服务降级函数在执行过程中也有可能发生异常,所以也可以给服务降级函数添加降级方法。
关闭provider服务,浏览器调用consumer,结果如下:
1.2.4 异常处理
如果有一个异常抛出后我不希望进入到服务降级方法中去处理,而是直接将异常抛给用户,那么我们可以在@HystrixCommand注解中添加忽略异常(ignoreExceptions)。
@HystrixCommand(fallbackMethod="getBookListFallback",ignoreExceptions = ArithmeticException.class)
@RequestMapping(value="getbooklist",method=RequestMethod.GET)
public List<Book> getBookList(){
int i = 1/0;
return bookCon.getBookList();
}
public List<Book> getBookListFallback() {
List<Book> bookList = new ArrayList<Book>();
Book book = new Book();
book.setAuthor("hystrix error");
book.setBookName("hystrix fallback");
book.setId(0);
bookList.add(book);
return bookList;
}
执行调用结果:
1.2.5 参数详解
降级参数 | |||
参数 | 作用 | 默认值 | 备注 |
fallback.enabled | fallback是否可用 | TRUE | 当执行失败或者请求被拒绝,是否会尝试调用hystrixCommand.getFallback() |
fallback.isolation.semaphore.maxConcurrentRequests | fallback最大并发数 | 10 | 如果并发数达到该设置值,请求会被拒绝和抛出异常并且fallback不会被调用. |
以下四种情况将触发getFallback调用 | |||
1:方法抛出非HystrixBadRequestException异常 | |||
2:方法调用超时 | |||
3:熔断器开启拦截调用 | |||
4:线程池/队列/信号量是否饱满 |
2:服务熔断
2.1 熔断机制
如下图,是熔断开启/关闭的一般流程:
2.2 Consumer侧引入pom
在Consumer侧的pom中引入hystrix的依赖。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2.3 在Consumer侧启动类开启熔断
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker //开启Hystrix熔断
public class BookshopConsumerHystrixBreakerApplication {
@Bean
public RestTemplate createRt() {
return new RestTemplate();
}
public static void main(String[] args) {
SpringApplication.run(BookshopConsumerHystrixBreakerApplication.class, args);
}
}
2.4 在Consumer侧编写熔断方法及配置
在Consumer中建立service类,其实现getBookList方法调用服务Provider中的/getbooklist接口,并对getBookList实现熔断处理:
@Service
public class BookService {
@Autowired
private RestTemplate restTemplate;
@Autowired
private LoadBalancerClient loadBalancerClient;//ribbon 负载均衡客户端
@HystrixCommand(fallbackMethod="getBookListFallback",
commandProperties={
//10s内请求数大于20(默认)个时就启动熔断器,当请求符合熔断器条件时触发getFallBack()
@HystrixProperty(name=HystrixPropertiesManager.CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD,value="10"),
//请求错误率大于50%时就熔断,然后for循环发起请求,当请求符合熔断条件时触发getFallBack()
@HystrixProperty(name=HystrixPropertiesManager.CIRCUIT_BREAKER_ERROR_THRESHOLD_PERCENTAGE,value="50"),
//熔断器开启5s后去尝试请求,默认5秒,以毫秒为单位
@HystrixProperty(name=HystrixPropertiesManager.CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS,value="5000"),
//超时设置
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "8000"),
})
public List<Book> getBookList(Integer id) {
System.out.println("====================get BookList===== " + id);
if (id ==1) {
throw new RuntimeException();
}
ServiceInstance si=loadBalancerClient.choose("bookshop-service-provider");
StringBuffer sb=new StringBuffer("");
sb.append("http://");
sb.append(si.getHost());
sb.append(":");
sb.append(si.getPort());
sb.append("/getbooklist");
System.out.println(sb.toString());
//String data = restTemplate.getForObject(sb.toString(), String.class);
/**
*封装返回对象为List<Book>
**/
ParameterizedTypeReference<List<Book>> responseType = new ParameterizedTypeReference<List<Book>>(){};
ResponseEntity<List<Book>> result = restTemplate.exchange(sb.toString(),HttpMethod.GET, null,responseType);
System.out.println("code : " + result.getStatusCode());
return result.getBody();
}
/**
* 实现List<Book> getBookList()的熔断方法
* */
@HystrixCommand
public List<Book> getBookListFallback(Integer id) {
System.out.println("=========get book list fallback== " +id);
List<Book> bookList = new ArrayList<Book>();
Book book = new Book();
book.setAuthor("breaker");
book.setBookName("breaker");
bookList.add(book);
return bookList;
}
}
参数详解:
熔断参数 | |||
参数 | 作用 | 默认值 | 备注 |
circuitBreaker.enabled | 是否开启熔断 | TRUE | |
circuitBreaker.requestVolumeThreshold | 一个统计窗口内熔断触发的最小个数/10s | 20 | 10s内请求数大于20个时就启动熔断器,当请求符合熔断条件时将触发getFallback(). |
circuitBreaker.sleepWindowInMilliseconds | 熔断多少秒后去尝试请求 | 5000ms | |
circuitBreaker.errorThresholdPercentage | 失败率达到多少百分比后开启熔断 | 默认配置下采样周期为10s,失败率为50% | 请求错误率大于50%时就熔断,然后for循环发起请求,当请求符合熔断条件时将触发getFallback() |
circuitBreaker.forceOpen | 是否强制开启熔断 | FALSE | 置为true时,所有请求都将被拒绝,直接到fallback |
circuitBreaker.forceClose | 是否强制关闭熔断 | FALSE | 置为true时,将忽略错误. |
2.5 Provider服务概述
本章的Provider服务利用了《声明式服务调用的实现(Feign)及其优化(Ribbon) 》中的provider服务,此处不做具体的介绍,