简介
在微服务架构中, 微服务之间的依赖关系错综复杂, 难免的某些服务会出现故障, 导致服务调用方出现远程调度的线程阻塞. 在高负载的场景下, 如果不做任何处理, 可能会引起级联故障, 导致服务调用方的资源耗尽甚至整个系统奔溃. Hystrix 是一个由 Netflix 开源的一个延迟和容错库, 它通过添加延迟容忍和容错逻辑来帮助控制这些微服务之间的交互. Hystrix 通过隔离服务之间的访问点, 停止跨服务的级联故障并提供回退选项来实现这一点, 所有这些选项都提高了系统的总体弹性.
项目介绍
sc-parent, 父模块 (请参照 SpringCloud 学习笔记 (1):Eureka 注册中心)
sc-eureka, 注册中心 (请参照 SpringCloud 学习笔记 (1):Eureka 注册中心)
sc-provider, 提供者 (请参照 SpringCloud 学习笔记 (1):Eureka 注册中心)
sc-consumer-hystrix-ribbon, 使用 Hystrix+Ribbon 的消费者
sc-consumer-hystrix-feign, 使用 Hystrix+Feign 的消费者
在 Ribbon 上使用 Hystrix
1. 在父模块下创建子模块项目 sc-consumer-hystrix-ribbon,pom.xml:
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>com.cf</groupId>
- <artifactId>sc-parent</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- </parent>
- <artifactId>sc-consumer-hystrix-ribbon</artifactId>
- <dependencies>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
- </dependency>
- </dependencies>
- </project>
2. 创建启动类 consumer.ConsumerApplication:
- package consumer;
- import org.springframework.boot.SpringApplication;
- import org.springframework.boot.autoconfigure.SpringBootApplication;
- import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
- import org.springframework.cloud.client.loadbalancer.LoadBalanced;
- import org.springframework.context.annotation.Bean;
- import org.springframework.web.client.RestTemplate;
- @SpringBootApplication
- @EnableCircuitBreaker
- public class ConsumerApplication {
- public static void main(String[] args) {
- SpringApplication.run(ConsumerApplication.class, args);
- }
- // 为 RestTemplate 整合 Ribbon, 使其具备负载均衡的能力
- @LoadBalanced
- @Bean
- public RestTemplate restTemplate(){
- return new RestTemplate();
- }
- }
3. 创建调用提供者服务的 Controller:consumer.controller.ConsumerController
- package consumer.controller;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.Web.bind.annotation.GetMapping;
- import org.springframework.Web.bind.annotation.RestController;
- import org.springframework.Web.client.RestTemplate;
- import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
- @RestController
- public class ConsumerController {
- @Autowired
- private RestTemplate restTemplate;
- @HystrixCommand(fallbackMethod="getBookListFallBack")
- @GetMapping("/getBookList")
- public String getBookList(){
- return restTemplate.getForObject("http://sc-provider/book/list", String.class);
- }
- public String getBookListFallBack(){
- return "[\"Java 入门到放弃 \"]";
- }
- }
@HystrixCommand: 表示将 getBookList 方法作为 hystrix 命令调用的方法.
fallbackMethod: 指定处理回退逻辑的方法, 这里是 getBookListFallBack 方法, 当 getBookList 方法跑出异常时将会调用 getBookListFallBack 方法.
注意: 回退方法应该与作为 hystrix 命令调用的方法具有相同的签名.
4. 创建 application.YAML:
- server:
- port: 8083
- spring:
- application:
- name: sc-consumer-hystrix-ribbon
- eureka:
- client:
- registerWithEureka: false
- serviceUrl:
- defaultZone: http://localhost:8080/eureka/
5. 测试
依次启动注册中心 sc-eureka, 提供者 sc-provider, 消费者 sc-consumer-hystrix-ribbon, 并访问 http://localhost:8083/getBookList, 结果显示如下:
这是提供者正常返回的值, 接下来将提供者 sc-provider 关闭, 再次访问 http://localhost:8083/getBookList, 结果显示如下:
因为将提供者 sc-provider 关闭后, 消费者再访问提供者时会报错, Hystrix 捕获异常后会直接调用回退方法也就是 getBookListFallBack 方法.
在 Feign 上使用 Hystrix
1. 在父模块下创建子模块项目 sc-consumer-hystrix-feign,pom.xml:
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>com.cf</groupId>
- <artifactId>sc-parent</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- </parent>
- <artifactId>sc-consumer-hystrix-feign</artifactId>
- <dependencies>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-openfeign</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.cloud</groupId>
- <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
- </dependency>
- </dependencies>
- </project>
2. 创建启动类 feign.FeignApplication:
- package feign;
- import org.springframework.boot.SpringApplication;
- import org.springframework.boot.autoconfigure.SpringBootApplication;
- import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
- import org.springframework.cloud.openfeign.EnableFeignClients;
- @SpringBootApplication
- @EnableFeignClients
- @EnableCircuitBreaker
- public class FeignApplication {
- public static void main(String[] args) {
- SpringApplication.run(FeignApplication.class, args);
- }
- }
3. 创建 Feign 声明式接口: feign.inter.BookService
- package feign.inter;
- import org.springframework.cloud.openfeign.FeignClient;
- import org.springframework.Web.bind.annotation.PostMapping;
- import feign.fallback.BookFallBack;
- @FeignClient(value="sc-provider", fallbackFactory=BookFallBack.class)
- public interface BookService {
- @GetMapping("/book/list")
- public String getBookList();
- }
@FeignClient 注解中的 fallbackFactory 属性是指定的 Feign 客户端界面定义回退工厂.
4. 创建调用提供者服务的 Controller:
- package feign.controller;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.Web.bind.annotation.GetMapping;
- import org.springframework.Web.bind.annotation.RequestMapping;
- import org.springframework.Web.bind.annotation.RestController;
- import feign.inter.BookService;
- @RequestMapping("/feign")
- @RestController
- public class FeignController {
- @Autowired
- private BookService bookService;
- @GetMapping("/getBookList")
- public String getBookList(){
- return bookService.getBookList();
- }
- }
5. 创建 application.YAML:
- server:
- port: 8084
- spring:
- application:
- name: sc-consumer-hystrix-feign
- eureka:
- client:
- registerWithEureka: false
- serviceUrl:
- defaultZone: http://localhost:8080/eureka/
- feign:
- hystrix:
- enabled: true #开启 hystrix 支持
6. 创建回退工厂类:
- package feign.fallback;
- import org.springframework.stereotype.Component;
- import feign.hystrix.FallbackFactory;
- import feign.inter.BookService;
- @Component
- public class BookFallBack implements FallbackFactory<BookService>{
- @Override
- public BookService create(Throwable cause) {
- return new BookService() {
- @Override
- public String getBookList() {
- return "[\"Java 入门到放弃 \"]";
- }
- };
- }
- }
create 方法返回一个回退实例, 回退实例为 Feign 声明式接口 BookService 的实现类, 提供了与 BookService 相对应的回退方法, BookService 接口调用失败时将会调用该实现类中的回退方法.
7. 测试:
依次启动注册中心 sc-eureka, 提供者 sc-provider, 消费者 sc-consumer-hystrix-feign, 并访问 http://localhost:8084/feign/getBookList, 结果显示如下:
这是提供者正常返回的值, 接下来将提供者 sc-provider 关闭, 再次访问 http://localhost:8084/feign/getBookList, 结果显示如下:
8. 查看回退原因
修改回退工厂类 BookFallBack:
- @Component
- public class BookFallBack implements FallbackFactory<BookService>{
- @Override
- public BookService create(Throwable cause) {
- return new BookService() {
- @Override
- public String getBookList() {
- // 将回退原因输出到控制台
- cause.printStackTrace(System.out);
- return "[\"Java 入门到放弃 \"]";
- }
- };
- }
- }
依次启动注册中心 sc-eureka, 消费者 sc-consumer-hystrix-feign, 并访问 http://localhost:8084/feign/getBookList, 控制台输出:
- com.netflix.hystrix.exception.HystrixTimeoutException
- at com.netflix.hystrix.AbstractCommand$HystrixObservableTimeoutOperator$1.run(AbstractCommand.java:1142)
- at com.netflix.hystrix.strategy.concurrency.HystrixContextRunnable$1.call(HystrixContextRunnable.java:41)
- at com.netflix.hystrix.strategy.concurrency.HystrixContextRunnable$1.call(HystrixContextRunnable.java:37)
- at com.netflix.hystrix.strategy.concurrency.HystrixContextRunnable.run(HystrixContextRunnable.java:57)
- at com.netflix.hystrix.AbstractCommand$HystrixObservableTimeoutOperator$2.tick(AbstractCommand.java:1159)
- ......
来源: https://www.cnblogs.com/seve/p/11535891.html