一、Hystrix
Hystrix是一个技术解决方案。通过服务隔离,服务熔断,服务降级等方式提供整个系统弹性。
首先在消费端和服务端进行导入Hystrix的jar包
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
配置yml文件,并没有hystrix的相关配置
server:
port: 8081
spring:
application:
name: cloud-provider-hystrix
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka, http://eureka7002.com:7002/eureka
1. 服务降级:当服务不可用,客户端就会一直等待到超时为止,系统应该直接返回一个服务暂时不可用提示,让客户端不用等待。这样也可以防止雪崩效应。
在服务端的服务降级:
controller进行调用服务
@RestController
public class PaymentController {
@Resource
private PaymentService paymentService;
@GetMapping("/payment/hystrix_fail/{id}")
public String payinfo_fail(@PathVariable("id") Integer id) throws InterruptedException {
return paymentService.payinfo_fail(id);
}
}
在service层进行服务降级
@Service
public class PaymentService {
// 出现服务降级会去找paymentHandler方法,超时时间定义为3秒
@HystrixCommand(fallbackMethod = "paymentHandler",
commandProperties ={@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds",value = "3000")})
public String payinfo_fail(Integer id) throws InterruptedException {
Thread.sleep(5000);
return "线程池fail"+Thread.currentThread().getName();
}
public String paymentHandler(Integer id){
return "接口调用异常";
}
}
主启动类:
@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker // 开启Hystrix
public class Hystrixmain {
public static void main(String[] args) {
SpringApplication.run(Hystrixmain.class, args);
}
}
在消费端进行1对1的服务降级:
@RestController
public class OrderHystrixController {
@Resource
private PaymentService paymentService;
@GetMapping("/consumer/payment/hystrix_fail/{id}")
// 一对一形式的服务降级,当前方法出错就会找fallbackMethod定义好的方法
@HystrixCommand(fallbackMethod = "holdpayment", commandProperties = {@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000")})
public String payinfo_fail(@PathVariable("id") Integer id) throws InterruptedException {
return paymentService.payinfo_fail(id);
}
public String holdpayment(@PathVariable("id") Integer id){
return "gogoggo";
}
}
在消费端进行1对多的服务降级:
为了防止同一类的方法都要定义服务降级这种代码冗余出现,出现了一对多的服务降级
@RestController
@DefaultProperties(defaultFallback = "gTest") // 一对多降级,只要添加了HystrixCommand注解服务降级的方法都是defaultFallback 定义的方法
public class OrderHystrixController {
@Resource
private PaymentService paymentService;
@GetMapping("/consumer/payment/hystrix_fail/{id}")
@HystrixCommand
public String payinfo_fail(@PathVariable("id") Integer id) throws InterruptedException {
return paymentService.payinfo_fail(id);
}
public String gTest(){
return "fafafafafaf";
}
}
在消费端进行通配的服务降级:
为了防止代码冗余以及结构混乱所以出现了此方法,首先需要进行yml文件的添加
feign:
hystrix:
enabled: true
在OpenFeign接口中@FeignClient注解的fallback进行定义,首先创建一个OpenFeign接口的实现类
/**服务降级类,这个类中每一个方法都对应一个服务降级的方法*/
@Component
public class FallBackSService implements PaymentService{
public String payinfo_Ok(Integer id) {
return "--------payinfo_Ok";
}
public String payinfo_fail(Integer id) {
return "-------payinfo_fail";
}
}
主启动类:
@SpringBootApplication
@EnableFeignClients
@EnableHystrix // 启用Hystrix客户端
public class OrderHystrix {
public static void main(String[] args) {
SpringApplication.run(OrderHystrix.class, args);
}
}
2. 服务熔断:服务中的熔断产生的原因就是并发过大。
服务熔断一般发生在服务端,Controller进行service调用
@RestController
public class PaymentController {
@Resource
private PaymentService paymentService;
@GetMapping("/payment/circuit/{id}")
public String paymentCircuitBreaker(@PathVariable("id") Integer id) {
String result = paymentService.paymentCircuitBreaker(id);
log.info("*****result: " + result);
return result;
}
}
在service层进行熔断规则定义:
@Service
public class PaymentService {
// 这个断路器的意思是在10秒钟内10次请求有60%的错误率就跳闸
@HystrixCommand(fallbackMethod = "paymentCircuitBreaker_fallback",commandProperties = {
@HystrixProperty(name = "circuitBreaker.enabled", value = "true"), //是否开启断路器
@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"), //请求数达到后才计算
@HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000"), //休眠时间窗
@HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "60"), //错误率达到多少跳闸
})
public String paymentCircuitBreaker(@PathVariable("id") Integer id) {
if(id < 0){
throw new RuntimeException("****id 不能为负数");
}
String serialNumber = IdUtil.simpleUUID();
return Thread.currentThread().getName() + "\t" + "调用成功,流水号:" + serialNumber;
}
public String paymentCircuitBreaker_fallback(@PathVariable("id") Integer id){
return "id 不能为负数,请稍后再试, o(╥﹏╥)o id: " + id;
}
}
熔断条件以及定义都在HystrixCommandProperties这个类中,这里列举一小部分
protected HystrixCommandProperties(HystrixCommandKey key, HystrixCommandProperties.Setter builder, String propertyPrefix) {
this.key = key;
this.circuitBreakerEnabled = getProperty(propertyPrefix, key, "circuitBreaker.enabled", builder.getCircuitBreakerEnabled(), default_circuitBreakerEnabled);
this.circuitBreakerRequestVolumeThreshold = getProperty(propertyPrefix, key, "circuitBreaker.requestVolumeThreshold", builder.getCircuitBreakerRequestVolumeThreshold(), default_circuitBreakerRequestVolumeThreshold);
this.circuitBreakerSleepWindowInMilliseconds = getProperty(propertyPrefix, key, "circuitBreaker.sleepWindowInMilliseconds", builder.getCircuitBreakerSleepWindowInMilliseconds(), default_circuitBreakerSleepWindowInMilliseconds);
}
3. Hystrix仪表盘
为了更好的图形化展示服务调用的过程,我们可以用Hystrix Dashboard进行展示
首先我们需要导入Hystrix Dashboard相关的jar包
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
在yml文件进行端口号的定义,在主启动类开启仪表盘注解
@SpringBootApplication
@EnableHystrixDashboard // 开启豪猪哥仪表盘
public class Dashboard {
public static void main(String[] args) {
SpringApplication.run(Dashboard.class, args);
}
}
然后在需要监视的服务上进行 bean的注册,这是spring cloud升级的一个坑
/**这是服务监控而 配置,与服务容错无关,这是一个坑,因为springboot的默认配置不是/hystrix.stream,在自己项目下配置servlet即可**/
@Bean
public ServletRegistrationBean getServlet() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet() ;
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
然后开启服务,访问http://localhost:9001/hystrix 就能看到豪猪哥的主页面了, 此时就成功了。