Hystrix引入
在微服务场景中,由于大部分微服务采用同步接口调用,而且多个领域相关的微服务会部署在同一个进程中,很容易发生“雪崩效应”,即某个微服务提供者故障,导致调用该微服务的消费者、或者与故障微服务合设在同一个进程中的其它微服务发生级联故障,最终导致系统崩溃,在spring cloud中提供了一种机制,断路器即Hystrix
Hystrix简介
Hystrix也是Netflix套件的一部分。它的作用是当对某个服务的调用在一定的时间内(默认10s,由metrics.rollingStats.timeInMilliseconds配置),有超过一定次数(默认20次,由circuitBreaker.requestVolumeThreshold参数配置)并且失败率超过一定值(默认50%,由circuitBreaker.errorThresholdPercentage配置),该服务的断路器会打开。返回一个由开发者设定的fallback,在fallback中返回给用户一个指定的页面,不至于出现error页面,影响用户体验
Hystrix使用前
创建maven项目
在maven新项目中添加几个module,commons是公共依赖的包,consumer是消费者,provider是生产者,eurekaconsumer是服务注册中心(名字随便起的),先不管hystrix,我们对commons进行install安装到本地仓库中,便于在consumer、provider可以导入依赖,对provider进行install,我们先启动eurekaconsumer服务
在eurekaconsumer就只配置了application.properties
eureka.client.fetch-registry=false
eureka.client.register-with-eureka=false
spring.application.name=eureka
server.port=1111
eureka.client.service-url.defaultZone=http://localhost:1111/eureka
启动类中添加了@EnableEurekaServer注解,表示开启eureka注册服务
package com.zhouym.eurekaconsumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaconsumerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaconsumerApplication.class, args);
}
}
接下来启动两个provider实例,在控制台中
E:\IDEA_WorkSpace\cloud\provider\target>java -jar provider-0.0.1-SNAPSHOT.jar --server.port=3001
E:\IDEA_WorkSpace\cloud\provider\target>java -jar provider-0.0.1-SNAPSHOT.jar --server.port=3002
此时访问eureka的后台服务http://localhost:1111/,就会发现注册的两个provider
provider中的接口
package com.zhouym.provider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 〈〉
*
* @author zhouym
* @create 2019/9/2
* @since 1.0.0
*/
@RestController
public class ProviderController {
@Value("${server.port}")
Integer port;
@GetMapping("/provider")
public String provide(){
return "provider:"+port;
}
}
application.properties配置文件
spring.application.name=provider
server.port=3000
eureka.instance.hostname=localhost
eureka.client.service-url.defaultZone=http://localhost:1111/eureka
接下来我们开启consumer
package com.zhouym.consumer;
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;
/**
* 〈〉
*
* @author zhouym
* @create 2019/8/31
* @since 1.0.0
*/
@RestController
public class ConsumerController {
@Autowired
RestTemplate restTemplate;
@GetMapping("/consumer4")
public String consumer4(){
return restTemplate.getForObject("http://provider/provider",String.class);
}
}
application.properties配置文件
spring.application.name=consumer
server.port=4000
eureka.client.service-url.defaultZone=http://localhost:1111/eureka
启动运行类
访问http://localhost:4000/consumer4,看看页面效果
因为启动了两个provider实例,所以刷新后,返回的数据是在3001和3002切换,当我们关闭其中一个provider实例,再次刷新看看页面效果
再次刷新看看
出现了如上图的error页面,这严重会影响用户体验,在spring cloud中提供了一个hystrix组件,就是用来解决这个的
Hystrix引入后
创建一个Hystrix项目,引入web、eureka discovery client、hystrix依赖
在application.properties文件中配置如下信息
spring.application.name=hystrix
server.port=5000
eureka.client.service-url.defaultZone=http://localhost:1111/eureka
service层
package com.zhouym.hystrix;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
/**
* 〈〉
*
* @author zhouym
* @create 2019/9/2
* @since 1.0.0
*/
@Service
public class HystrixService {
@Autowired
RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "error")
public String test(){
return restTemplate.getForObject("http://provider/provider",String.class);
}
public String error(){
return "error";
}
}
controller层
package com.zhouym.hystrix;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 〈〉
*
* @author zhouym
* @create 2019/9/2
* @since 1.0.0
*/
@RestController
public class HystrixController {
@Autowired
HystrixService hystrixService;
@GetMapping("/hello")
public String hello(){
return hystrixService.test();
}
}
在启动类中添加@EnableCircuitBreaker,以及RestTemplate
package com.zhouym.hystrix;
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 HystrixApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixApplication.class, args);
}
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
启动hystrix运行类,访问页面http://localhost:5000/hello
此时我们关闭一个provider实例
刷新之后就访问到了我们指定的error页面了
再次刷新,断路器就会认为provider有一个服务已经掉线了,此后不会再去访问这个掉线的服务
多次刷新,访问到的仍是这个3001的页面