分布式系统面临的问题:
分布式系统环境下,服务间类似依赖非常常见,一个业务调用通常依赖多个基础服务。在某些时候可能存在某个服务出现失败。
服务雪崩:
如下图,对于同步调用,当库存服务不可用时,商品服务请求线程被阻塞,当有大批量请求调用库存服务时,最终可能导致整个商品服务资源耗尽,无法继续对外提供服务。并且这种不可用可能沿请求调用链向上传递,这种现象被称为雪崩效应。
对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上的所有资源在几秒内就饱和。这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发送更多的级联故障,所以需要对故障和延迟进行隔离和管理,即便单个依赖关系的失败,不能取消整个应用程序或系统。
雪崩效应常见场景
- 硬件故障:如服务器宕机,机房断电,光纤被挖断等。
- 流量激增:如异常流量,重试加大流量等。
- 缓存穿透:一般发生在应用重启,所有缓存失效时,以及短时间内大量缓存失效时。大量的缓存不命中,使请求直击后端服务,造成服务提供者超负荷运行,引起服务不可用。
- 程序BUG:如程序逻辑导致内存泄漏,JVM长时间FullGC等。
- 同步等待:服务间采用同步调用模式,同步等待造成的资源耗尽。
什么是Hystrix
Hystrix是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避免的或出现调用失败,比如超时或异常等,Hystrix能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。
当某个服务单元发生故障之后,通过断路器的故障监控(类似熔断保险丝),向调用放返回一个服务预期的,可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方式无法处理的异常,这样就可以保证了服务调用方的线程不会被长时间不必要的占用,从而避免了故障在分布式系统中的蔓延乃至雪崩。
Hystrix的作用
- 服务降级
- 服务熔断
- 服务限流
- 接近实时的监控等
服务熔断
熔断机制是应对雪崩效应的一种微服务链路保护机制。
当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回错误的响应信息。当检测到该节点微服务调用响应正常后,恢复调用链路。在SpringCloud框架里熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况,当失败的调用到达一定阈值时,就会启动熔断机制。
熔断机制的注解:@HystrixCommand
Hystrix三个重要的概念
1.服务降级(还能继续使用)
服务器忙,请稍候再试,不让客户端等待并立刻返回一个友好提示,fallback
哪些情况会触发服务降级:
程序运行异常
超时
服务熔断触发服务降级
线程池/信号量打满也会导致服务降级
2.服务熔断(停止使用)
类比保险丝达到最大服务访问后,直接拒绝访问,拉闸限电,然后调用服务降级的方法并返回友好提示
服务的降级->进而熔断->恢复调用链路
3.服务限流
秒杀高并发等操作,严禁一窝蜂的过来拥挤,大家排队,一秒钟N个,有序进行
服务熔断 是从服务端方面
服务降级 是从客户端的方面 假设有2个服务A,B在服务器上,A服务今天会有大量的请求调用,B服务很久才有一次请求服务,那么为了给A服务更多的资源去处理更多的请求,我们会选择暂时关闭B原本的服务,把B原本的服务降级(目前理解的意思是把原本的服务停了,然后重写一些服务逻辑(在客户端准备一个FallbackFactory)处理用户的请求,例如友好提示用户)。
一、服务熔断实现方式
1、创建一个新的服务端来测试(springcloud-provider-dept-hystrix-8001),复制之前写好的8001服务端,按套路来,先导入pom依赖。
<!--Hystrix-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
2、yml配置不用改,controller层 只写一个服务方法(方便看)
先写好fallback备选方法,然后在接口方法上添加一个 @HystrixCommand注解,参数fallbackMethod = 备用方法名
这里逻辑给个查不到的id假装找不到Dept数据出错,进行报错,使程序去执行fallback备选方法
package com.freeze.springcloud.controller;
import com.freeze.springcloud.pojo.Dept;
import com.freeze.springcloud.service.DeptService;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
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.*;
import java.util.List;
//提供Restful服务
@RestController
public class DeptController {
@Autowired
private DeptService deptService;
@GetMapping("/dept/get/{id}")
@HystrixCommand(fallbackMethod = "hystrixGet")
public Dept get(@PathVariable("id") Long id){
Dept dept = deptService.queryById(id);
if(dept == null){
throw new RuntimeException("id=>"+id+",不存在该用户");
}
return dept;
}
//备选方法
public Dept hystrixGet(Long id){
return new Dept()
.setDeptno(id)
.setDname("不存在该用户")
.setDb_source("no this database in MySQL");
}
}
3、开启功能@EnableHystrix //已经涵盖了@EnableCircuitBreaker这个注解
二、服务降级实现方式
1、在之前写的Feign客户端进行修改,不用导入依赖,在yml配置中 开启服务降级
#开启服务降级
feign:
hystrix:
enabled: true
2、创建一个ServiceFactory,用于服务降级,implements实现FallbackFactory接口,实现creeate方法,当正常服务不可用时,调用方就会执行这里的方法 (友好提示用户)
package com.freeze.springcloud.service;
import com.freeze.springcloud.pojo.Dept;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;
import java.util.List;
//服务降级,关闭原来的服务,重写方法
@Component
public class DeptClientServcieFallBackFactory implements FallbackFactory {
@Override
public Object create(Throwable cause) {
return new DeptClientService() {
@Override
public Dept queryById(Long id) {
return new Dept()
.setDeptno(id)
.setDname("不存在该用户")
.setDb_source("no this database in MySQL");
}
@Override
public List<Dept> queryAll() {
return null;
}
@Override
public boolean addDept(Dept dept) {
return false;
}
};
}
}
3、其他不变,启动测试, 能够正常调用接口,此时假设要把服务关闭,把服务器资源分配给其他服务,这时候再去调用接口,就会执行我们写好的实现FallbackFactory接口的方法。
熔断机制和服务降级是一起使用的。
三、Dashboard监控
1、创建一个新模块(springcloud-consumer-hystrix-dashboard),将客户端的依赖复制过来,添加dashboard依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
2、修改yml配置
server:
port: 9001
hystrix:
dashboard:
proxy-stream-allow-list: localhost
3、开启功能@EnableHystrixDashboard//开启监控页面
此时页面访问(http://localhost:9001/hystrix/)
4、再去配置下之前写的hystrix8001服务端(带有熔断机制的服务端才能被监控)
在启动类中添加一个Servlet
//增加一个Servlet
@Bean
public ServletRegistrationBean hystrixMetricsStreamServlet(){
ServletRegistrationBean registrationBean = new ServletRegistrationBean(new HystrixMetricsStreamServlet());
registrationBean.addUrlMappings("/actuator/hystrix.stream");
return registrationBean;
}
启动服务,再进入DashBoard页面输入 服务端地址+端口+/actuator/hystrix.stream 下面选项默认,点击进入,即可查看到服务端的监控信息。
![请添加图片描述](https://img-blog.csdnimg.cn/cb12829e4c834c3bb49c0903cfb6e84a.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQV9GcmVlemU=,size_20,color_FFFFFF,t_70,g_se,x_16