SpringCloud之Hystrix
基本介绍
Hystrix叫做断路器/熔断器。微服务系统中,整个系统出错的概率非常高,因为在微服务系统中,涉及到的模块太多了,每一个模块出错,都有可能导致整个服务出错,当所有模块都稳定运行时,整个模块才算是稳定运行。而Hystrix正好能解决这个问题。
基本用法
创建一个springboot项目,这里是以注解方式实现,注册中心还是用之前的eureka。
1.pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.dpf</groupId>
<artifactId>hystrix</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>hystrix</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<spring-cloud.version>Hoxton.SR3</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<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>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.application.yml配置,将Hystrix注册到eureka注册中心
spring:
application:
name: hystrix
server:
port: 3000
eureka:
client:
service-url:
defaultZone: http://localhost:1111/eureka
3.启动类
@SpringBootApplication
@EnableCircuitBreaker //启动Hystrix
//@SpringCloudApplication
public class HystrixApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixApplication.class, args);
}
@Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
}
@SpringCloudApplication这个注解可以代替前面两个注解
4.提供Hystrix服务层
@Service
public class HelloService {
@Autowired
RestTemplate restTemplate;
/**
* 发起远程调用,去调用eureka-provider中提供的/hello接口
* 但是这个调用可能会失败
*
* 处理失败:方法加上@HystrixCommand注解,配置fallbackMethod属性
* 这个属性表示调用失败时临时替代的方法
* @return
*/
@HystrixCommand(fallbackMethod = "error")
public String hello(){
return restTemplate.getForObject("http://eureka-provider/hello",String.class);
}
/**
* 服务降级
* 注意这个方法名要和fallbackMethod一致
* 方法返回值也要和对应的方法一致
*
* error中也可以用@HystrixCommand调用其他接口
* @return
*/
public String error(){
return "error";
}
/**
* 注解实现请求异步调用
* @return
*/
@HystrixCommand(fallbackMethod = "error")
public Future<String> hello2(){
return new AsyncResult<String>() {
@Override
public String invoke() {
return restTemplate.getForObject("http://provider/hello",String.class);
}
};
}
}
5.调用Hystrix服务层
@RestController
public class HelloController {
@Autowired
HelloService helloService;
@GetMapping("/hello")
public String hello(){
return helloService.hello();
}
}
@GetMapping("/hello3")
public void hello3(){
Future<String> hello2 = helloService.hello2();
try {
String s = hello2.get();
System.out.println(s);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
6.启动eureka-server、eureka-provider、Hystrix测试,http://localhost:3000/hello、http://localhost:3000/hello3
请求命令
请求命令也就是以继承的方式来代替前面的注解实现方式。
1.定义一个HelloCommand继承HystrixCommand接口
public class HelloCommand extends HystrixCommand<String>{
RestTemplate restTemplate;
public HelloCommand(Setter setter, RestTemplate restTemplate) {
super(setter);
this.restTemplate = restTemplate;
}
@Override
protected String run() throws Exception{
return restTemplate.getForObject("http://eureka-provider/hello",String.class);
}
}
2.controller调用
@Autowired
RestTemplate restTemplate;
/**
* 通过继承实现调用
*/
@GetMapping("/hello2")
public void hello2(){
//直接执行
HelloCommand helloCommand = new HelloCommand(HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("runn")), restTemplate);
String execute = helloCommand.execute();
System.out.println(execute);
try {
//一个实例只能执行一次所以在new一个,先入队再执行
HelloCommand helloCommand2 = new HelloCommand(HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("runn")), restTemplate);
Future<String> queue = helloCommand2.queue();
String s = queue.get();
System.out.println(s);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
这里要注意:一个实例只能调用一次,可以先入队再执行。
3.重启测试
4.继承方式使用Hystrix怎么实现服务容错/降级,HelloCommand 中重写getFallback方法
@Override
protected String getFallback() {
return "error-extends";
}
异常处理
这里说的异常不是provider的原因导致请求调用失败,而是由consumer中代码本身有问题而导致的调用失败。即consumer抛出了异常,这时候也会自动进行服务降级,只不过这个时候降级,我们还需要知道到底是哪里出异常了,即知道异常信息。
1.注解方式
这时候我们只需要在 @HystrixCommand(fallbackMethod = “error”)对应的错误处理方法中添加异常参数就可以了
public String error(Throwable t){
return "error"+t.getMessage();
}
2.继承方式
既然是继承,那么父类肯定有对应的获取异常信息的方法,我们只需调用父类的对应方法即可
@Override
protected String getFallback() {
return "error-extends"+getExecutionException().getMessage();
}
在getFallback方法中通过调用getExecutionException方法获取异常信息。
3.如果抛异常,我们希望异常直接抛出,不需要服务降级,那么只需要配置忽略对应的异常即可
@HystrixCommand(fallbackMethod = "error",ignoreExceptions = ArithmeticException.class)
public String hello(){
int i = 10 / 0;
return restTemplate.getForObject("http://provider/hello",String.class);
}
请求缓存
Hystrix提供了缓存,但是主流的缓存还是使用redis。
1.eureka-provider中提供测试缓存接口
@GetMapping("/hello2")
public String hello2(String name){
System.out.println(new Date()+">>"+name);
return "hello"+name;
}
2.Hystrix 的Service中提供测试方法
@HystrixCommand(fallbackMethod = "error2")
@CacheResult //表示该方法的结果会被缓存起来,缓存的默认key为方法名,value为方法的返回值
public String hello3(String name){
return restTemplate.getForObject("http://eureka-provider/hello2?name={1}",String.class,name);
}
public String error2(String name){
return "error2";
}
@CacheResult注解即开启Hystrix缓存,注意error处理方法与处理方法参数要一致不然会报错
3. 控制层调用测试方法
@GetMapping("/hello4")
public void hello4(){
HystrixRequestContext hystrixRequestContext = HystrixRequestContext.initializeContext();
String s = helloService.hello3("pikachues");
System.out.println(s);
s =helloService.hello3("pikachues");
System.out.println(s);
hystrixRequestContext.close();
}
在使用缓存时一般都有一个生命周期,这里也一样,用HystrixRequestContext.initializeContext()开启缓存生命周期,在执行.close方法之前缓存都有效。
4.重启项目调用测试方法
Hystrix中两次调用,你会发现在eureka-provider中只有一次输出,这就是缓存起作用了。
@CacheResult 缓存key名称的几种情况
- 默认情况下是调用方法的参数
- 多个参数时默认为参数名连接起来的字符串
- 多个参数时指定key名称,在参数名前添加
@CacheKey注解指定某个参数名为其key名称
@CacheRemove注解:用于数据删除接口,同时删除缓存中的数据。@CacheRemove在使用时必须指定CommandKey属性,CommandKey就是缓存的key名称。
浙公网安备 33010602011771号