SpringCloud 应用笔记
服务熔断Hystrix入门
雪崩效应
在微服务架构中,一个请求需要调用多个服务是非常常见的。**但!!
**
如客户端访问A服务,而A服务需要调用B 服务,B服务需要调用C服务
但!!
- 如果,由于网络原因或者自身的原因:
B服务或者C服务不能及时响应
A服 务将处于阻塞状态,直到B服务C服务响应。 - 此时若有大量的请求涌入,容器的线程资源会被消耗完毕
导致服务瘫痪。
- 服务与服务之间的依赖性,故障会传播,造成连锁反应,
会对整个微服务系统造成灾难性的严重后果
这就是服务故障的“雪崩”效应。
雪崩是系统中的蝴蝶效应导致其发生的原因多种多样:
- 有不合理的容量设计
- 亦或是某台机器的资源耗尽。
- 或者是高并发下某一个方法响应变慢
- 硬件问题,这感觉只能说是点背了⊙︿⊙
- 缓存击穿,导致调用全部访问某服务,导致down掉
- 我们无法完全杜绝雪崩源头的发生,但是**
雪崩的根本原因来源于服务之间的强依赖
** 所以我们可以提前评估,做好:**熔断
**,**隔离
**,**限流。
** 避免雪崩的产生~
避免雪崩的产生
服务隔离
- 顾名思义,它是指将系统按照一定的原则划分为若干个服务模块:**
各个模块之间相对独立,无强依赖。
** - 当有故障发生时
能将问题和影响隔离在某个模块内部
而不扩散风险,不波及其它模块,不影响整体的系统服务。
熔断降级
- 熔断这一概念来源于电子工程中的断路器(Circuit Breaker)
电压高~保险丝断~跳闸~保护电器
在互联网系统中,当下游服务因访问压力过大而响应变慢或失败
上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。
- 在客户端控制对依赖的访问,如果调用的依赖不可用时,则不再调用,**
直接返回错误,或者降级处理。
** 所谓降级,就是当某个服务熔断之后,服务器将不再被调用此时客户端可以自己准备一个本地的fallback回调,返回一个缺省值.也可以理解为 兜底
fallback回调方法是对你目前请求失效后的一个解决方案:
- 开源的库比如**
hystrix
** 很好的实现了熔断和降级的功能。 他的主要思想是,设置一些阀值,比如,最大并发数,错误率百分比,熔断尝试恢复时间等。 通过这些阀值来转换熔断器的状态: 1.关闭状态,允许调用依赖
2.打开状态,不允许调用依赖
,直接返回错误,或者调用fallback
3.半开状态,根据熔断尝试恢复时间
来开启,允许调用依赖,如果调用成功则关闭
失败则继续打开
服务限流
- 限流可以认为服务降级的一种 限流就是限制系统的输入和输出流量已达到保护系统的目的。
- 一般来说系统的吞吐量是可以被测算的
一旦检测达到的限制的阈值,就限制流量访问并采取少量措施以完成限制流量的目的。
- 限制客户端的调用来达到限流的做法是很常见的
比如,我们限制每秒最大处理200个请求,超过个数量直接拒绝请求。
- 推迟解决,拒绝解决,或者者部分拒绝解决等等。
- 常见的算法如令牌桶算法
Hystrix介绍
logo:**非洲的一个动物, 豪猪~我也不知道为啥..就很nice~
**
Hystrix是由**Netflflix开源的
**一个**延迟和容错库
**
用于隔离访问远程系统、服务或者第三方库,防止级联失败: 从而提升系统的可用性与容错性。
- 在分布式系统中,每个服务都可能会调用很多其他服务
被调用的那些服务就是依赖服务,有的时候某些依赖服务出现故障也是很正常的。
- Hystrix可以让我们在分布式系统中对服务间的调用进行控制,加入一些调用延迟或者依赖故障的**
容错机制.
** - Hystrix通过将依赖服务进行资源隔离,进而组织某个依赖服务出现故障的时候
这种故障在整个系统所有的依赖服务调用中进行蔓延时
Hystrix还提供故障时的fallback降级机制
总而言之,Hystrix通过这些方法帮助我们提升分布式系统的可用性和稳定性
Hystrix主要通过以下几点实现: 延迟
容错
包裹请求:
- 使用**
HystrixCommand包裹
** 对依赖的调用逻辑包裹,**使每个命令在独立线程中执行。
一般来说是对于经常使用的方法进行包裹~ 不是很长调用的并不需要进行包裹~** 也对 Hystrix 也主要是做熔断的…**防止雪崩
**对于不经常使用的方法也不会**崩坏
**
跳闸机制:
- 当某
包裹
服务的错误率超过一定的阈值时, - Hystrix可以**
自动
**或**手动跳闸
**,停止请求:服务一段时间错误率:当请求满足一定的数量默认20 且请求失败比例的大于 50% Hystrix就会使服务暂时的停止...
使服务冷静一段时间, 这段时间都是响应一个可正常运行的fallback
方法, 并不会让你的程序卡在这儿… 等过一段时间, 又会自动的又将 服务打开~让你进行访问…整个过程都是自动的!
资源隔离:
- Hystrix为每个依赖都维护了一个小型的线程池(或者信号量)
- 如果该线程池已满
发往该依赖的请求就被立即拒绝,而不是排队等待,从而加速失败判定。(也是保护服务正常运行的一种形式...)
下面的 Hystrix监控就是靠着这些线程需要进行的操作..
监控:
- Hystrix可以近乎实时地监控运行指标和配置的变化
例如成功、失败、超时、以及被拒绝的请求等。
- 甚至还提供一个图表, 供运维人员可以实时的看图, 就了解了当前程序的状态
回退机制:
- 当请求失败、超时、被拒绝,或当断路器打开时,执行回退逻辑。 回退逻辑由开发人员自行提供,例如返回一个缺省值。
- 自我修复:
断路器打开一段时间后,会自动进入“半开”状态。
半开状态: 有可能之后变为打开, 有可能是关闭状态;半开状态对当前情况一种分析,来觉得之后的状态情况!
Rest 实现服务熔断 实战!
ok, 终于经过了上面 乱七八糟,令人头疼的理论终于到了代码了…
- 目前我们简单的了解了:
什么是雪崩
熔断
降级
… - 接下来就让我们通过 Rest方式实现
处理雪崩的 熔断降级
rest 是调用方请求的一种方式…Hystrix 一般对调用方的方法进行包裹监视
如果出现问题进行降级fallback
**处理**
在之前项目基础上更改: 不了解同学可以点击这儿!!**耐心学习~
**
公工配置:
严格遵循了SpringCloud的 三板斧原则:依赖 配置 注解
首先还是万变不离其宗的依赖 pom.xml
pom.xml
<!-- hystrix实现服务熔断 -->
<!-- 熔断器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- SpringCloud 对hystrix 的starter全部依赖集成... -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
如果需要对状态进行实时的监视配置 还需配置.yml
.yml
#不在任何节点写属性,它就是首级...
management:
endpoints:
web:
exposure:
include: hystrix.stream # hystri流文件实时监控的文件
#stream流: 配置这个表示状态信息已流的方式 实时进行记录;
- 这个 .yml不是强求! 如果不需要实时的监控可以不要
- 通过下面的: 接口就可以访问当然
包裹方法的执行状态!
http://localhost:对应调用者端口/actuator/hystrix.stream
本人这里都是已学习为主的,所以都是localhost本地的ip
主程序类需要提供一个注解:
主程序类, 几乎不要任何的配置!就只要一个注解:
- @EnableCircuitBreaker
表示, 开启Hystrix的
熔断降级!
接下来介绍 熔断降级的两种实现~
controller层进行的修改! 在最顶上进行的**降级!
**
默认一个服务降级
@HystrixCommand
- @HystrixCommand声明在一个要**
包裹的controller请求方法上!
** fallbackMethod = "指定的降级方法"
并通过 fallbackMethod 属性指定一个降级方法 当原方法出现异常, 则会直接执行降级方法.
- 降级方法, 是一个除了方法名以外一切和 包裹方法**
一模一样的方法!!
**参数
参数类型
返回值
…修饰符
! ~类型真的坑我就写错成 int 和 Integer找了半天的错~
UserController.Java
//编程控制层,接受请求响应结果
@RestController
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/showUserOrder") //页面请求的方法名,get方式请求!
@HystrixCommand(fallbackMethod = "showUserOrderFallBack") //给方法指定一个局部熔断方法;
public List<Order> showUserOrder(Integer uid){
int num = (int) (Math.random() * 10); //这里为了方便看到效果,本人决定手动随机抛出异常! 70%几率
System.out.println(num);
if (num > 7) {
throw new RuntimeException(); //主动对外抛出异常...
}
return userService.currentUserOrder(uid);
//Service又是通过网络调用 订单模块来响应的结果,因此在此基础上要缺点订单模块是运行中的...
}
//局部熔断器方法...方法名外: 一模一样
public List<Order> showUserOrderFallBack(Integer uid){
//这里主要做的就是对请求的一种处理,方法: 假的数据....
System.out.println("局部熔断方法");
List<Order> list = new ArrayList<>();
list.add(new Order(0, "进入熔断降级方法", 0.0, uid));
return list;
}
}
类全局 服务降级
@DefaultProperties
- @DefaultProperties 一般上面在类上:
- 并通过**
defaultFallback = "全局的降级方法"
** 指定全局的**降级处理
** 类中任一个报错都会进入该方法 - 与全局不同的是**
实现的降级方法
** 不在需要一模一样…因为你也不知道要啥参数 返回值了… 需要注意: 虽然@DefaultProperties在类上声明了还是要给 要降级的方法上声明 @HystrixCommand
但是不用在指定降级方法了!!
UserController.Java
//编程控制层,接受请求响应结果
@RestController
@DefaultProperties(defaultFallback = "commonFallBack") //全局熔断器 (如有控制器抛出异常直接进到这个方法)
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/showUserOrder") //页面请求的方法名,get方式请求!
@HystrixCommand//(fallbackMethod = "showUserOrderFallBack") //给方法指定一个局部熔断方法;
public List<Order> showUserOrder(Integer uid){
int num = (int) (Math.random() * 10); //这里为了方便看到效果,本人决定手动随机抛出异常! 70%几率
System.out.println(num);
if (num > 7) {
throw new RuntimeException(); //主动对外抛出异常...
}
return userService.currentUserOrder(uid);
}
// //局部熔断器方法...方法名外: 一模一样
// public List<Order> showUserOrderFallBack(Integer uid){
// //这里主要做的就是对请求的一种处理,方法: 假的数据....
// System.out.println("局部熔断方法");
// List<Order> list = new ArrayList<>();
// list.add(new Order(0, "进入熔断降级方法", 0.0, uid));
// return list;
// }
//全局熔断器方法... 因为是全局的所以参数就不好提供了;
public List<Order> commonFallBack(){
System.out.println("全局熔断方法");
List<Order> list = new ArrayList<>();
list.add(new Order(0, "全局熔断方法", 0.0, 1));
return list;
}
}
总结:
- 三板斧~
- 熔断主要做的是类似**
异常处理的
**, 不一定在调用方写的! pom.xml
导入对应依赖- 如果要实时记录数据需要做的
.yml
配置 - 主程序的启动注解
@EnableCircuitBreaker
- 根据需求场景来决定: 局部/全局降级策略!!!
Hystrix的监控平台
Hystrix 对降级操作提供一个监控器平台
- Hystrix官方还提供了基于图形化的DashBoard(仪表板)监控平台。
- Hystrix仪表板可以显示每个断路器(被@HystrixCommand注解的方法)的状态。
主要作用是:
- 主要作用就是针对上面,
.yml
配置的监控文件, 它可以对文件进行监视. - 并产生图形化的页面给开发人员更方便的观看**
实时的数据
**!! 毕竟 没人喜欢一直盯着这个满屏的子 瞅!