什么是Hystrix
hystrix是一个处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的会调用失败,比如超时,异常,hystrix能够保证在一个依赖问题的情况选,不会导致整体服务的失败,避免级联故障,一提高分布式系统的弹性.
"断路器"本身是一种开关装置,当某个服务单元发生故障后,通过断路器的故障监控(类似熔断保险丝),向调用方法返回一个服务预期的,可处理的备选响应,而不是长时间的等待或者抛出调用方法无法处理的异常了.这样就可以保证了服务调用方的线程不会被长时间,不必要的占用,从而避免故障在分布式系统中的蔓延,乃至雪崩.
作用:服务降级,服务熔断,服务限流,接近实时的监控.
上图所示:一个程序进来,需要连续调用A,G,E2,E3这四个服务,如果说这四个服务正常运行,则没啥问题,但是如果E2出现了问题,没有任何解决措施的情况下,会导致在运行完G时出现等待,延迟,异常等,进而该程序无法进行下去,这个时候我们就需要给服务备份,可以考虑异步等方法,给予用户提示,服务崩溃,但后面的服务能继续运行.解决措施就是我们这里考虑的Hystrix,这也是一个最经典的应用
服务熔断:
熔断机制是对应雪崩效应的一种微服务链路保护机制.
现在进行一项实例测试:
按照之前的项目:如果要加上Hystrix我们可以增加一个module:
代码:
package com.qiu.springcloud.controller;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.qiu.springcloud.pojo.Dept;
import com.qiu.springcloud.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
//提供restfull服务
@RestController
public class DeptController {
@Autowired
private DeptService deptService;
@HystrixCommand(fallbackMethod = "hystrixGet")
@GetMapping("/dept/get/{deptNo}")
public Dept get(@PathVariable("deptNo") Long deptNo){
Dept dept = deptService.queryById(deptNo);
if (dept==null){
throw new RuntimeException("id=>"+deptNo+".不存在该用户,或者信息未找到~");
}
return dept;
}
//备选方案
public Dept hystrixGet(@PathVariable("deptNo") Long deptNo){
return new Dept()
.setDeptno(deptNo)
.setDname("id=>"+deptNo+".不存在该用户,或者信息未找到~")
.setDb_sources("no this database in mysql");
}
}
其他代码与前module:8001类似.需要修改的代码:
yaml文件:
第二步:在controller的方法上添加注解
表示如果服务出错调取备用方法
第三步:
主启动类上添加对熔断器的支持,注意这里不是开启
@EnableHystrix的注解
然后依次启动服务:
在网页中我们可以看到:
这是正常访问的结果:因为数据库中有1-6号的deptno
如果访问了数据库中没有的
则会调用备用的方法.这就是服务熔断的小案列体现.
服务降级
看上图:假设有三个服务器分别为A,B,C.这些箭头是客户端,它们要去请求服务端的数据.这个时候可能由于某个时间段A服务器的访问量高,出现资源不过的情况,所以我们可以使用服务降级的策略,将C服务器关闭,释放C服务器上的资源加在A服务器上,进而使得用户能够正常访问.但是这个时候由于C服务器关闭了,这样会导致访问C服务器的人就不能正常运行.所以说我们要提示正在访问C服务器的人,从而达到高可用的目的.
同样解释服务降级我么可以用一个小案例
依然是上述那个案例.
首先我们需要创建一个类:DeptClientServiceFallbackFactory.这里用于提示访问C服务器的人.该服务已经降级.
package com.qiu.springcloud.service;
import com.qiu.springcloud.pojo.Dept;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class DeptClientServiceFallbackFactory implements FallbackFactory {
public DeptClientService create(Throwable throwable) {
return new DeptClientService() {
public Dept queryById(Long deptNo) {
return new Dept()
.setDeptno(deptNo)
.setDname("id"+deptNo+"没有对用的信息,客户端提供了降级的信息,这个服务已经被关闭")
.setDb_sources("no data");
}
public List<Dept> queryAll() {
return null;
}
public boolean addDept(Dept dept) {
return false;
}
};
}
}
我们需要实体层添加注解.在前面博客中用到了Feign,同样这里也适用
.通过查看源码我们可以得知
源码中Frign注解中提供了fallbackFactory方法,所以
我们可以在注解里面添加fallbackFactory = DeptClientServiceFallbackFactory.class
这样可以使service与DeptClientServiceFallbackFactory进行绑定.
同样不要忘了需要在feign80的配置文件中开启feign-hystrix
上诉操作完成之后我们开始运行.开启7001,7002,7003注册中心,然后开启一个8001用来提供数据,进而开启feign80端口.然后在网站中查询.当我们把服务8001断开时,网站能及时通信客户端.
这样就简单的实现了服务降级
服务熔断:服务端,某个服务超时,引起熔断~ 类似于保险丝
服务降级:客户端从整体的网站请求负载考虑,当某个服务熔断或者关闭之后,服务将不再调用,此时我们可以准备一个FallbackFactory,返回一个默认的值(缺省值),缺点:整体的服务水平下降了.好歹能用,总比挂了强
最后一个我们来看下Hystrix的DashBoard监控
SpringCloud对Hystrix Dashboard进行了整合,可以对通过Hystrix发起的请求进行准实时统计,并以报表和图形的形式展示给用户(包括每秒执行多少次请求成功和失败等.
首先我们先把案例所需的关键代码附上
第一步开启eureka端口7001.为了简要说明,我们这边就开一个即可,
package com.qiu.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer //服务端的启动类,可以接受别人注册进来
public class EurekaServer_7001 {
public static void main(String[] args) {
SpringApplication.run(EurekaServer_7001.class,args);
}
}
第二步就是新建一个modules:springcloud-consumer-hystrix-dashboard
结构如下:
pom文件:
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>SpringCloud</artifactId>
<groupId>com.qiu</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-consumer-hystrix-dashboard</artifactId>
<!-- 实体类+web-->
<dependencies>
<!--Hystrix依赖~-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--Ribbon-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--erueka-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>com.qiu</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>
yaml配置:
server:
port: 9001
主启动类中需要加上相关的注解
package com.qiu.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
@SpringBootApplication
@EnableHystrixDashboard
public class DeptConsumerDashboard_9001 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumerDashboard_9001.class,args);
}
}
然后就是我们的8001端口.
在这个服务提供者中我们需要注意几点
第一:
确认pom文件中有有三个依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!-- 添加监控信息,完善监控信息 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- 配置eureka-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
第二:确保主启动类的注解完整:
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
//启动类
@SpringBootApplication
@EnableEurekaClient //自动的在服务启动后自动注册到eureka中
@EnableDiscoveryClient//服务发现
@EnableCircuitBreaker //添加对熔断的支持
public class DeptProviderHystrix_8001 {
public static void main(String[] args) {
SpringApplication.run(DeptProviderHystrix_8001.class,args);
}
//增加一个servlet
@Bean
public ServletRegistrationBean getServlet() {
HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
registrationBean.setLoadOnStartup(1);
registrationBean.addUrlMappings("/actuator/hystrix.stream");
registrationBean.setName("HystrixMetricsStreamServlet");
return registrationBean;
}
}
第三:注意路径:/actuator/hystrix.stream
完整路径为http://localhost:8001//actuator/hystrix.stream
在网页中打开这个网址,将会得到一串字符,这是一些ping记录.
然后我们打开localhost:9001/hystrix
输入网址http://localhost:8001//actuator/hystrix.stream进去后得到:
关于该页面详细介绍: