一、Hystrix 简介
1、Hystrix 是什么?
流量高峰时,一个单节点的宕机或延迟,会迅速导致所有服务负载达到饱和。应用中任何一个可能通过网络访问其他服务的节点,都有可能成为造成潜在故障的来源。更严重的是,还可能导致服务之间的延迟增加,占用队列、线程等系统资源,从而导致多系统之间的级联故障。
简单的说,当服务器依次请求 A->P->H->I 时,如果其中一个发生了故障,都有可能导致整个流程失败,或者降低整个流程的效率。
更严重的是,当网络请求是通过第三方的一个黑盒客户端来发起时,实现细节都被隐藏起来了,而且还可能频繁变动,这样发生问题时就很难监控和改动。如果这个第三方还是通过传递依赖的,主应用程序中根本没有显示地写出调用的代码,那就更难了。
网络连接失败或者有延迟,服务将会产生故障或者响应变慢,最终反应成为一个 bug。
所有上述表现出来的故障或延迟,都需要一套管理机制,将节点变得相对独立,这样任何一个单节点故障,都至少不会拖垮整个系统的可用性。 所以 Hystrix 就是为了解决请求序列中请求出现问题的情况,核心原则就是丢车保帅,如果一个请求出现问题,常见的有两种方案:
2、Hystrix 能干什么?
1、服务熔断 2、服务降级 3、数据监控
二、服务熔断
1、服务熔断简介
熔断机制是赌赢雪崩效应的一种微服务链路保护机制。
当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。检测到该节点微服务调用响应正常后恢复调用链路。在 SpringCloud 框架里熔断机制通过 Hystrix 实现。Hystrix 会监控微服务间调用的状况,当失败的调用到一定阀值缺省是 5 秒内 20 次调用失败,就会启动熔断机制。熔断机制的注解是:@HystrixCommand。
服务熔断解决如下问题:
2、配置 pom.xml
首先新建一个 module,和 springcloud-provider-dept-8001 一模一样(名字除外),修改一下 application.yaml,一个是端口(也可以不改,最好修改一下,避免端口冲突),另一个是 instance-id,这样在尤里卡中可以分辨出来。需要引入 hystrix 的依赖,和 feign 一样,只是把 feign 换成 hystrix
<!--引入hystrix依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
复制代码
3、配置 application.yaml
和 springcloud-provider-dept-8001 一样,只需要修改一下端口号和 instance-id
#端口号
server:
port: 8001
#配置数据库
spring:
datasource:
url: jdbc:mysql:///dp80?serverTimezone=UTC
username: root
password: 200201203332
driver-class-name: com.mysql.jdbc.Driver
application:
name: springcloud-provider-dept
debug: true
#配置Eureka的配置
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka/
instance:
instance-id: springcloud-provider-8001
info: #autuator监控信息
app.name: rainhey-springcloud
company.name: www.rainhey.com
复制代码
4、修改 Controller
@HystrixCommand 注解
用来处理服务熔断和服务降级,属性和方法可以点进去查看。@HystrixCommand 注解通常放到方法之上,当这个方法抛出异常的时候,系统不会立刻停止处理异常,而是先找 Hystrix 里面绑定的备用方法,然后去执行备用方法。那么 @HystrixCommand 如何绑定备用方法呢?见下图
@HystrixCommand 注释通过内部属性 fallbackMethod 绑定方法,具体步骤是 @HystrixCommand(fallbackMethod = "备用方法名")
package com.you.Controller;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.you.mapper.DeptMapper;
import com.you.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@ResponseBody
@Component
public class DeptController {
@Autowired
DeptMapper deptMapper;
@GetMapping("/dept/aDept/{id}")
@HystrixCommand(fallbackMethod = "hystrixGetDeptOfId")
public Dept getDeptOfId(@PathVariable("id") Long id)
{
System.out.println("进来了,id是:"+id);
Dept dept = deptMapper.finaDeptOfId(id);
if(dept==null)
{
throw new RuntimeException("id=>"+id+"不存在该用户,或者信息没有找到!");
}
return dept;
}
/* 备用方案 */
public Dept hystrixGetDeptOfId(@PathVariable("id") Long id)
{
Dept dept = new Dept();
dept.setDeptno(id);
dept.setDeptname("id=>"+id+"不存在该用户,或信息没有找到!@Hystrix");
dept.setDb_source("no info in datebase");
System.out.println("dept的值是:"+dept);
return dept;
}
}
复制代码
5、修改启动类
从前面的 4 篇文章里我们了解到,每次用到新的技术,启动类里都会增加一个新的注解,那么?Hystrix 的注解是什么呢?@EnableCircuitBreaker,只要把这个注解加在主启动类上,那么主启动类就可以处理服务熔断了。
6、效果图
不开熔断机制
开了熔断机制
三、服务降级
1、什么是服务降级
服务降级是指 当服务器压力剧增的情况下,根据实际业务情况及流量,对一些服务和页面有策略的不处理,或换种简单的方式处理,从而释放服务器资源以保证核心业务正常运作或高效运作。说白了,就是尽可能的把系统资源让给优先级高的服务。例如假设有三个服务器 ABC,在某一段时间,访问 A 的用户特别多,导致 A 服务器快要崩溃了,这时候访问 B、C 的用户很少,那么我暂时先把 B、C 停掉,用来处理 A。服务降级主要用于什么场景呢?当整个微服务架构整体的负载超出了预设的上限阈值或即将到来的流量预计将会超过预设的阈值时,为了保证重要或基本的服务能正常运行,可以将一些 不重要 或 不紧急 的服务或任务进行服务的 延迟使用 或 暂停使用。
降级的方式可以根据业务来,可以延迟服务,比如延迟给用户增加积分,只是放到一个缓存中,等服务平稳之后再执行 ;或者在粒度范围内关闭服务,比如关闭相关文章的推荐。
2、DeptClientFailBackFactory 类
在 springcloud-api 模块下的 service 包中新建降级配置,DeptClientServiceFallBackFactory.java。同时实现其方法,他的返回类型就是我们写服务的接口。
package com.you.service;
import com.you.pojo.Dept;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;
/*!!!降级!!!*/
@Component //注册到容器里面去
public class DeptClientFailBackFactory implements FallbackFactory {
@Override
public DeptClientService create(Throwable throwable) {
return new DeptClientService() {
@Override
public Dept getDeptOfId(Long id) {
Dept dept = new Dept();
dept.setDeptno(id);
dept.setDeptname("id=>"+id+"没有对应的信息,客户端提供了降级的信息,这个服务现在被关闭了!");
dept.setDb_source("没有数据");
return dept;
}
};
}
}
复制代码
3、添加注解
在 DeptClientService 中指定降级配置:DeptClientServiceFallBackFactory
package com.you.service;
import com.you.pojo.Dept;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@Component
/*@FeignClient:value的值即为 服务的名字,fallbackFactory的值即为 实现FallbackFactory类的名字 */
@FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT",fallbackFactory = DeptClientFailBackFactory.class)
public interface DeptClientService {
@GetMapping("/dept/aDept/{id}")
public Dept getDeptOfId(@PathVariable("id") Long id);
}
复制代码
4、修改 application.yaml
为的是开启服务,但切记此处修改的 application 是 springcloud-consumer-dept-feign 下的 application.yaml,添加如下代码
#开启降级 feign-hystrix
feign:
hystrix:
enabled: true
复制代码
5、效果图
依次启动 springcloud-eureka-7001、springcloud-consumer-dept-feign、springcloud-provider-dept-8001,访问服务正确打开服务
现在,停掉这个 springcloud-provider-dept-8001,模拟服务降级中暂时关闭的一些端口。8001 端口的服务被停掉了,这时候刷新页面。
端口是可以访问的,只是显示了我们设计的文字
四、DashBorder
1、新建一个 module
新建一个名为 springcloud-consumer-hystrix-dashborder 的 module
2、pom.xml 配置
将 springcloud-provider-dept-8001 的依赖如复制过来,并且增加上 dashborder 的依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.you</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--引入Eureka的依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</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>
<!--引入DashBorder-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix-dashboard</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<!--引入hystrix依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
</dependencies>
复制代码
3、配置 application.yml
只需要配置端口号
4、配置启动类
创建一个名为 DeptConsumerDashBorder_9001 的 JAVA 类
package com.you;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
@SpringBootApplication
@EnableHystrixDashboard
public class DeptConsumerDashBorder_9001 {
public static void main(String[] args) {
SpringApplication.run(DeptConsumerDashBorder_9001.class,args);
}
}
复制代码
5、添加被监控的类
给 springcloud-provider-dept-hystrix-8001 模块下的主启动类添加如下代码,添加监控
package com.you;
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
@EnableDiscoveryClient
/*对熔断的支持*/
@EnableCircuitBreaker
public class DeptApplication_Hystrix_8001 {
public static void main(String[] args) {
SpringApplication.run(DeptApplication_Hystrix_8001.class,args);
}
@Bean
public ServletRegistrationBean hystrixMetricsStreamServlet(){
ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
//访问该页面就是监控页面
registrationBean.addUrlMappings("/actuator/hystrix.stream");
return registrationBean;
}
}
复制代码
6、效果图
启动 springcloud-eureka-7001、springcloud-consumer-hystrix-dashborder、springcloud-provider-dept-hystrix-8001 在 7001 尤里卡界面,看到 springcloud-provider-dept-hystrix-8001 被注册进来。
访问 8011,输入 http://localhost:8011/dept/aDept/1(我设置的端口号是 8011),可以看到被成功访问。
访问 http://localhost:8011/actuator/hystrix.stream,看到如下效果
访问 9001,地址输入 http://localhost:9001/hystrix,看到如下界面
将地址填入,http://localhost:8011/actuator/hystrix.stream
刷新这个界面,下面的图像会随之变化
评论