在微服务架构中,一个请求需要调用多个服务是非常常见的。**但!!
**
如客户端访问A服务,而A服务需要调用B 服务,B服务需要调用C服务
但!!
B服务或者C服务不能及时响应
A服 务将处于阻塞状态,直到B服务C服务响应。导致服务瘫痪。
会对整个微服务系统造成灾难性的严重后果
这就是服务故障的“雪崩”效应。雪崩的根本原因来源于服务之间的强依赖
**
所以我们可以提前评估,做好:**熔断
**,**隔离
**,**限流。
** 避免雪崩的产生~各个模块之间相对独立,无强依赖。
**能将问题和影响隔离在某个模块内部
而不扩散风险,不波及其它模块,不影响整体的系统服务。电压高~保险丝断~跳闸~保护电器
在互联网系统中,当下游服务因访问压力过大而响应变慢或失败
上游服务为了保护系统整体的可用性,可以暂时切断对下游服务的调用。
直接返回错误,或者降级处理。
**
所谓降级,就是当某个服务熔断之后,服务器将不再被调用
此时客户端可以自己准备一个本地的fallback回调,返回一个缺省值.也可以理解为 兜底
fallback回调方法是对你目前请求失效后的一个解决方案:
hystrix
** 很好的实现了熔断和降级的功能。
他的主要思想是,设置一些阀值,比如,最大并发数,错误率百分比,熔断尝试恢复时间等。
通过这些阀值来转换熔断器的状态:
1.关闭状态,允许调用依赖
2.打开状态,不允许调用依赖
,直接返回错误,或者调用fallback
3.半开状态,根据熔断尝试恢复时间
来开启,允许调用依赖,如果调用成功则关闭
失败则继续打开
一旦检测达到的限制的阈值,就限制流量访问并采取少量措施以完成限制流量的目的。
比如,我们限制每秒最大处理200个请求,超过个数量直接拒绝请求。
logo:**非洲的一个动物, 豪猪~我也不知道为啥..就很nice~
**
Netflflix开源的
**一个**延迟和容错库
**用于隔离访问远程系统、服务或者第三方库,防止级联失败: 从而提升系统的可用性与容错性。
被调用的那些服务就是依赖服务,有的时候某些依赖服务出现故障也是很正常的。
容错机制.
**这种故障在整个系统所有的依赖服务调用中进行蔓延时
Hystrix还提供故障时的fallback降级机制
总而言之,Hystrix通过这些方法帮助我们提升分布式系统的可用性和稳定性
延迟
容错
HystrixCommand包裹
** 对依赖的调用逻辑包裹,**使每个命令在独立线程中执行。
一般来说是对于经常使用的方法进行包裹~ 不是很长调用的并不需要进行包裹~**
也对 Hystrix 也主要是做熔断的…**防止雪崩
**对于不经常使用的方法也不会**崩坏
**包裹
服务的错误率超过一定的阈值时,自动
**或**手动跳闸
**,停止请求:服务一段时间
错误率:当请求满足一定的数量默认20 且请求失败比例的大于 50% Hystrix就会使服务暂时的停止...
使服务冷静一段时间, 这段时间都是响应一个可正常运行的fallback
方法, 并不会让你的程序卡在这儿…
等过一段时间, 又会自动的又将 服务打开~让你进行访问… 整个过程都是自动的!
发往该依赖的请求就被立即拒绝,而不是排队等待,从而加速失败判定。(也是保护服务正常运行的一种形式...)
下面的 Hystrix监控就是靠着这些线程需要进行的操作..
例如成功、失败、超时、以及被拒绝的请求等。
断路器打开一段时间后,会自动进入“半开”状态。
半开状态: 有可能之后变为打开, 有可能是关闭状态; 半开状态对当前情况一种分析,来觉得之后的状态情况!
实战!
ok, 终于经过了上面 乱七八糟,令人头疼的理论终于到了代码了…
什么是雪崩
熔断
降级
…处理雪崩的 熔断降级
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流: 配置这个表示状态信息已流的方式 实时进行记录;
包裹方法的执行状态!
http://localhost:对应调用者端口/actuator/hystrix.stream
本人这里都是已学习为主的,所以都是localhost本地的ip主程序类, 几乎不要任何的配置!就只要一个注解:
表示, 开启Hystrix的
熔断降级!
接下来介绍 熔断降级的两种实现~
controller层进行的修改! 在最顶上进行的**降级!
**
服务降级
@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;
}
}
服务降级
@DefaultPropertiesdefaultFallback = "全局的降级方法"
** 指定全局的**降级处理
** 类中任一个报错都会进入该方法实现的降级方法
** 不在需要一模一样…因为你也不知道要啥参数 返回值了…
需要注意: 虽然@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 对降级操作提供一个监控器平台
主要作用是:
.yml
配置的监控文件, 它可以对文件进行监视.实时的数据
**!!
毕竟 没人喜欢一直盯着这个满屏的子 瞅! 😥hystrix-dashBoard-server
这个监控平台实现的话,特别容易! 就 依赖
配置监控平台端口
启动主程序即可!!
pom.xml
<?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>SpringCloudBJ</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>hystrix-dashBoard-server</artifactId>
<dependencies>
<!-- 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>
<!-- 仪表盘:等会页面展示需要的依赖: -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
</dependencies>
</project>
.yml
application.yml
server:
port: 7003
本人的端口 7003~**这个随便搞都行!
**
@EnableHystrixDashboard
MyHystrixDashBoardServer.Java
@SpringBootApplication
@EnableHystrixDashboard
public class MyHystrixDashBoardServer {
public static void main(String[] args) {
SpringApplication.run(MyHystrixDashBoardServer.class, args);
}
}
正常不能在正常的SpringBoot 微服务项目, 就加了一个注解 @EnableHystrixDashboard
启动数据图形化仪表盘
localhost:服务端口/hystrix
这样就表示成功了!!
再次强调指定要查看的 监视流文件(copy): http://localhost:被监控的端口/actuator/hystrix.stream
ok, 进入监控文件!
需要注意这里**端口状态
**:
CLOSED
,当触发熔断后状态变更为OPEN
在等待到指定的时间,Hystrix会放请求检测服务是否开启,这期间熔断器会变为 HALF_OPEN
半启状态,熔断探测服务可用则继续变更为 CLOSED
关闭熔断器。失败次数超过了在给定时间内允许失败的阈值
,则代理类切换到断开(Open)状态。
此时代理开启了一个超时时钟,当该时钟超过了该时间
,则切换到半断开(Half-Open)状态。
该超时时间的设定是给了系统一次机会来修正导致调用失败的错误。默认20次 失败率 50%以上
(默认是5S)。
**
随后断路 器会自动进入半开状态。此时会释放1次请求通过,若这个请求是健康的,则会关闭断路器
否则 继续保持打开,再次进行5秒休眠计时.
上面已经通过 Hystrix 实现了,
监视器实时的监控数据, 但只是对于一个请求的使用, 那么如果有很多呢?
我怎么一下子看很多, 开很多的 Hystrix监视页面吗? 一个页面一个? 很显然是不行滴!!
因为要给监控器加一个 监视多个的操作,这是要修改 监控平台的
依旧**三板斧
**坚持到底~~
pom.xml
<?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>SpringCloudBJ</artifactId>
<groupId>org.example</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>hystrix-dashBoard-server</artifactId>
<dependencies>
<!-- 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>
<!-- 仪表盘:等会页面展示需要的依赖: -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>
<!-- 导入turbine所需要的依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-turbine</artifactId>
</dependency>
</dependencies>
</project>
.yml
文件application.yml
server:
port: 7003
spring:
application:
name: my-cloud-hystrix-dashboard
#注册至eureka上
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka/
instance:
prefer-ip-address: true
turbine:
# 要监控的微服务列表,多个用,分隔
app-config: user-server
cluster-name-expression: "'default'"
#因为归根结底,想要通过turbine来实现多服务监控;
#底层是将多个服务模块的流文件写入到一个 turbine的流文件;
#htstrix监视器解析的是 汇总之后的turbine的流文件————实现多文件查看!!
加了一个 注册中心
因为它要去注册中心上去找, 要监控对应的服务…
注册中心可以提供方便的访问!!
turbine配置
turbine的流文件;
MyHystrixDashBoardServer.Java
@SpringBootApplication
@EnableHystrixDashboard //作为一个独立的监控项目,需要配置启动类,开启HystrixDashboard监控平台
@EnableTurbine //并激活Turbine
public class MyHystrixDashBoardServer {
public static void main(String[] args) {
SpringApplication.run(MyHystrixDashBoardServer.class, args);
}
}
首先Eureka**注册中心
**上可以看到 已经都在注册中心上了: 可以实现访问了
分布直接查看**实时监控文件的情况
**可以看到页面是在不停的**实时刷新,监测新的数据~
**
单文件 http://localhost:6002/actuator/hystrix.stream
汇总文件 http://localhost:7003/turbine.stream
前面端口别在意, 根据自己情况来! 后面的请求路径才是要注意 需要copy的!
查看多文件监视的时候,**使用汇总文件~
**
三板斧!!
提供注册中心配置,为了更好的去汇总模块的监视文件
Turbine根据 , 逗号分隔添加多个要汇总的模块..
激活Turbine
默认已为Feign整合了hystrix
**不用在添加hystrix依赖
**可以参考这里:拉到最后Fegin**服务调用
**
和之前相比加了一个 Fegin服务调用的接口实现, 专门为其做熔断的类 OrderFeginRD
不需要加入什么依赖
**pom.xml
#fegin 就是最顶层!
feign:
hystrix:
enabled: true #开启fegin的熔断
FeginRD
熔断包;定一个一个实现类
实现Fegin服务调用的 提供者provide模块,接口
OrderFeginRD.Java
//把普通pojo实例化到spring容器中,相当于配置文件中的 )
@Component
public class OrderFeginRD implements OrderFeginClient {
@Override
public List<Order> findOrderByUser(Integer uid){
//这里做的就是熔断服务降级的,处理方法...根据需求来呗! 本人就返回一个 List:Order Fegin熔断!
System.out.println("Fegin熔断降级!!");
List<Order> list = new ArrayList<>();
list.add(new Order(1, "Fegin的熔断方法", 0.0, 1));
return list;
}
}
它主要是实现采用 Fegin调用模块, 所引入调用模块 声明的接口
OrderFeginClient.Java
//@FeignClient指定需要调用的微服务名称
@FeignClient(value = "order-server",fallback = OrderFeginRD.class)
public interface OrderFeginClient {
//调用的请求路径,要注意这里尽量要和 提供者的实现方法一模一样包括参数,参数类型!!
@GetMapping("/findOrderByUser/{uid}")
public List<Order> findOrderByUser(@PathVariable("uid") Integer uid);
}
fallback = OrderFeginRD.class 指定当改接口实现, 出现错误进行熔断降级的实现类
OrderFeginRD
@EnableFeignClients
这个应该不会忘, 毕竟Fegin的服务调用,也需要这个注解来实现:**@EnableFeignClients 启动Fegin的支持!
**
因为Fegin的内部实现了 hystrix 所以不需要在引入什么依赖~
一模一样的接口方法!Fegin的底层对其做了实现!给Service直接调用!
重写的方法就是后面熔断降级方法 Fallback
@FeignClient(value = "order-server",fallback = OrderFeginRD.class)
value = “order-server” 引入要调用的模块名~
fallback = “当方法异常,熔断降级的类!” 目前这个降级类就是 当然接口的实现类!
因此:Fegin的熔断策略是针对 , 调用方的
调用方出现异常, 则执行Fallback的降级方法~ok, 这就实现了Fegin的熔断, 是不是特别简单!!
说实话把, 难? 不难但是SpringCloud / Boot 的东西:注解/中间件/依赖…
实在太多了!不费点劲, 可不容易完全搞懂!
Sentinel
短期内
**,Hystrix依然是继续使用的。Alibaba Sentinel
阿里巴巴开源
**的一款断路器实现
目前在Spring Cloud的孵化器项目Spring Cloud Alibaba中的一员
Sentinel本身在阿里内部已经被大规模采用,非常稳定。因此可以作为一个较好的替代品。
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。
Sentinel 以流量为切入点: 从流量控 制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入
您可以通过实现扩展接口来快 速地定制逻辑。例如定制规则管理、适配动态数据源等
这里使用的是 用户模块common_userService:**已经采用hystrix 实现了熔断!就不在用Sentinel 处理熔断降级了
**
熔断降级~
只是使项目被管理 监控! 所以代码不多就导了个 依赖pom 配置.yml!
使用前要确保存在,启动一个:**管理控制台
**
您可以从官方网站中下载最新版本的控制台 jar 包 sentinel-dashboard-1.6.3.jar
在Jar包路径下执行,使用如下命令**启动控制台:
**
java -Dserver.port=10000 -Dcsp.sentinel.dashboard.server=localhost:10000 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.6.3.jar
上述的两个 10000 更改为你要修改的端口号:xxx
sentinel
给要进行管理的 项目模块导入Sentinel的依赖:**pom.xml
**
<!-- 阿里巴巴 Sentinel所需依赖: -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
引入父工程依赖:**pom.xml
**
<!-- <dependencyManagement></> :结构下,因为是阿里巴巴的依赖,需要引入阿里巴巴的 父依赖! -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>1.5.0.RELEASE</version>
<type>pom</type> <!-- 因为这里是 pom所以是父工程的 -->
<scope>import</scope>
</dependency>
application.yml
spring:
application:
name: user-server #服务模块名!
cloud:
sentinel:
transport:
dashboard: http://localhost:1000 #这里设置需要引入,你Sentinel 的路径!
在目录下通过命令启动
服务被平台管理!