🎉🎉欢迎来到我的CSDN主页!🎉🎉
🏅我是Java方文山,一个在CSDN分享笔记的博主。📚📚
🌟推荐给大家我的专栏《Spring Cloud》。🎯🎯
👉点击这里,就可以查看我的主页啦!👇👇
🎁如果感觉还不错的话请给我点赞吧!🎁🎁
💖期待你的加入,一起学习,一起进步!💖💖
目录
[2.Sentinel 分为两个部分](#2.Sentinel 分为两个部分)
前言
在微服务架构中,我们将业务拆分成一个个的服务,服务与服务之间可以相互调用,但是由于网络原因或者自身的原因,服务并不能保证服务的100%可用,如果单个服务出现问题,调用这个服务就会出现网络延迟,此时若有大量的网络涌入,会形成任务堆积,最终导致服务瘫痪(雪崩)。
接下来,我们来模拟一个高并发的场景
①编写java代码
java
@Slf4j
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private IFeignProductService feignProductService;
@RequestMapping("/findByParameter")
public String findByParameter(String name,Double price){
log.info("服务消费者日志:name={},price={}",name,price);
return feignProductService.findByParameter(name,price);
}
}
②修改配置文件中tomcat的并发数
1秒钟20个请求,最大连接数10,最大等待数10,最大线程数2,相当于一个线程1s能处理5个请求(2个处理10个请求)
java
server:
port: 8091
tomcat:
max-threads: 2 #最大线程数
max-connections: 10 #最大连接数
accept-count: 10 #最大线程等待数
如果我1s发送5个以上的请求,此时会发现, 由于order方法囤积了大量请求, 导致message方法的访问出现了问题,这就是服务雪崩的雏形。
服务雪崩效应
在分布式系统中,由于网络原因或自身的原因,服务一般无法保证 100% 可用。如果一个服务出现了 问题,调用这个服务就会出现线程阻塞的情况,此时若有大量的请求涌入,就会出现多条线程阻塞等 待,进而导致服务瘫痪。 由于服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是 服务故障的 "雪崩效应" 。
雪崩发生的原因多种多样,有不合理的容量设计,或者是高并发下某一个方法响应变慢,亦或是某 台机器的资源耗尽。我们无法完全杜绝雪崩源头的发生,只有做好足够的容错,保证在一个服务发生问 题,不会影响到其它服务的正常运行。也就是"雪落而不雪崩"。
一、常见的容错方案
要防止雪崩的扩散,我们就要做好服务的容错,容错说白了就是保护自己不被猪队友拖垮的一些措 施, 下面介绍常见的服务容错思路和组件。 常见的容错思路 常见的容错思路有隔离、超时、限流、熔断、降级这几种,下面分别介绍一下。
- 隔离 它是指将系统按照一定的原则划分为若干个服务模块,各个模块之间相对独立,无强依赖。当有故障发生时,能将问题和影响隔离在某个模块内部,而不扩散风险,不波及其它模块,不影响整体的系统服务。常见的隔离方式有:线程池隔离和信号量隔离。
- 超时 在上游服务调用下游服务的时候,设置一个最大响应时间,如果超过这个时间,下游未作出反应,就断开请求,释放掉线程。
- 限流 限流就是限制系统的输入和输出流量已达到保护系统的目的。为了保证系统的稳固运行,一旦达到 的需要限制的阈值,就需要限制流量并采取少量措施以完成限制流量的目的。
- 熔断 在互联网系统中,当下游服务因访问压力过大而响应变慢或失败,上游服务为了保护系统整 体的可用性,可以暂时切断对下游服务的调用。这种牺牲局部,保全整体的措施就叫做熔断。
服务熔断一般有三种状态:
- 熔断关闭状态(Closed) 服务没有故障时,熔断器所处的状态,对调用方的调用不做任何限制
- 熔断开启状态(Open) 后续对该服务接口的调用不再经过网络,直接执行本地的fallback方法
- 半熔断状态(Half-Open) 尝试恢复服务调用,允许有限的流量调用该服务,并监控调用成功率。如果成功率达到预期,则说明服务已恢复,进入熔断关闭状态;如果成功率仍旧很低,则重新进入熔断启动状态。
- 降级 降级其实就是为服务提供一个托底方案,一旦服务无法正常调用,就使用托底方案。
常见的容错组件
-
Hystrix Hystrix是由Netflix开源的一个延迟和容错库,用于隔离访问远程系统、服务或者第三方库,防止 级联失败,从而提升系统的可用性与容错性。
-
Resilience4J Resilicence4J一款非常轻量、简单,并且文档非常清晰、丰富的熔断工具,这也是Hystrix官方推 荐的替代产品。不仅如此,Resilicence4j还原生支持Spring Boot 1.x/2.x,而且监控也支持和 prometheus等多款主流产品进行整合。
-
Sentinel Sentinel 是阿里巴巴开源的一款断路器实现,本身在阿里内部已经被大规模采用,非常稳定。
下面是三个组件在各方面的对比:
Sentinel | Hystrix | |
---|---|---|
隔离策略 | 信号量隔离 | 线程池隔离/信号量隔离 |
熔断降级策略 | 基于响应时间或失败比率 | 基于失败比率 |
实时指标实现 | 滑动窗口 | 滑动窗口(基于 RxJava) |
规则配置 | 支持多种数据源 | 支持多种数据源 |
扩展性 | 多个扩展点 | 插件的形式 |
基于注解的支持 | 即将支持 | 支持 |
限流 | 基于 QPS,支持基于调用关系的限流 | 不支持 |
流量整形 | 支持慢启动、匀速器模式 | 不支持 |
系统负载保护 | 支持 | 不支持 |
控制台 | 开箱即用,可配置规则、查看秒级监控、机器发现等 | 不完善 |
常见框架的适配 | Servlet、Spring Cloud、Dubbo、gRPC 等 | Servlet、Spring Cloud Netflix |
二、Sentinel入门
1.什么是Sentinel
Sentinel (分布式系统的流量防卫兵) 是阿里开源的一套用于服务容错的综合性解决方案。它以流量 为切入点, 从流量控制、熔断降级、系统负载保护等多个维度来保护服务的稳定性。 Sentinel 具有以下特征:
-
丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景, 例如秒杀(即 突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
-
完备的实时监控:Sentinel 提供了实时的监控功能。通过控制台可以看到接入应用的单台机器秒 级数据, 甚至 500 台以下规模的集群的汇总运行情况。
-
广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块, 例如与 Spring Cloud、Dubbo、gRPC 的整合。只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
-
完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。
2.Sentinel 分为两个部分
-
核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。
-
控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等 应用容器。
3.微服务集成Sentinel
为微服务集成Sentinel非常简单, 只需要加入Sentinel的依赖即可,在需要的模块pom.xml中加入下面依赖
java
<!--sentinel-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
网关gateway集成sentinel,需还另添加以下依赖
java
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
另外编写一个Controller测试使用
(我这里就直接用我之前讲解组件所写的生产服务和消费服务做模拟,以下是我生产服务的代码)
java
@RestController
public class ProduceController {
@RequestMapping("/run")
public String run() {
return "🍗";
}
}
三、安装Sentinel控制台
Sentinel 提供一个轻量级的控制台, 它提供机器发现、单机资源实时监控以及规则管理等功能。
①下载jar包,解压到文件夹 Releases · alibaba/Sentinel · GitHub
②启动控制台
java
# 直接使用jar命令启动项目(控制台本身是一个SpringBoot项目)
java -Dserver.port=9999 -Dcsp.sentinel.dashboard.server=localhost:9999 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.7.0.jar
#参考1
java -jar sentinel-dashboard-1.8.1.jar --server.port=8080
#参考2
java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.1.jar
③修改shop-order ,在里面加入有关控制台的配置
java
sentinel:
transport:
port: 8719
dashboard: localhost:9999
eager: true
web-context-unify: false
④通过浏览器访问localhost:9999进入控制台 ( 默认用户名密码是 sentinel/sentinel )
补充:
了解控制台的使用原理 Sentinel的控制台其实就是一个SpringBoot编写的程序。我们需要将我们的微服务程序注册到控制台上,即在微服务中指定控制台的地址, 并且还要开启一个跟控制台传递数据的端口, 控制台也可以通过此端口调用微服务中的监控程序获取微服务的各种信息。
实现一个接口的限流
1 通过控制台为message1添加一个流控规则
2 通过控制台快速频繁访问, 观察效果
四、Sentinel规则
流控规则
流量控制,其原理是监控应用流量的QPS(每秒查询率) 或并发线程数等指标,当达到指定的阈值时 对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。 第1步: 点击簇点链路,我们就可以看到访问过的接口地址,然后点击对应的流控按钮,进入流控规则配置页面。新增流控规则界面如下:
资源名 :唯一名称,默认是请求路径,可自定义 针对来源:指定对哪个微服务进行限流,默认指default,意思是不区分来源,全部限制 阈值类型/单机阈值:
-
QPS(每秒请求数量): 当调用该接口的QPS达到阈值的时候,进行限流
-
线程数:当调用该接口的线程数达到阈值的时候,进行限流
是否集群:暂不需要集群 接下来我们以QPS为例来研究限流规则的配置。
①简单配置
我们先做一个简单配置,设置阈值类型为QPS,单机阈值为3。即每秒请求量大于3的时候开始限流。 接下来,在流控规则页面就可以看到这个配置。
然后快速访问/order/message1 接口,观察效果。此时发现,当QPS > 3的时候,服务就不能正常响应,而是返回Blocked by Sentinel (flow limiting)结果。
②配置流控模式
点击上面设置流控规则的编辑按钮,然后在编辑页面点击高级选项,会看到有流控模式一栏。
sentinel共有三种流控模式,分别是:
直接(默认):接口达到限流条件时,开启限流
关联:当关联的资源达到限流条件时,开启限流 [适合做应用让步]
链路:当从某个接口过来的资源达到限流条件时,开启限流
下面呢分别演示三种模式:
直接流控模式 直接流控模式是最简单的模式,当指定的接口达到限流条件时开启限流。上面案例使用的就是直接流控模式。
关联流控模式 关联流控模式指的是,当指定接口关联的接口达到限流条件时,开启对指定接口开启限流。
第1步:配置限流规则, 将流控模式设置为关联,关联资源设置为的 /run2。
第3步:通过produce软件向/run2连续发送请求,注意QPS一定要大于3
第4步:访问/run2,会发现已经被限流
③链路流控模式
链路模式是Sentinel流量控制框架中的一种模式,用于对特定的请求链路进行限流。在一个复杂的系统中,请求可能会经过多个服务或接口的调用链,而其中的某一个接口可能会成为整个链路的瓶颈,导致系统性能下降或者不可用。链路模式允许在该接口的流量达到限制条件时进行限流,以保护整个链路的稳定性。
第1步: 编写一个service,在里面添加一个方法message
java
@Service
class OrderServiceImpl2 {
@SentinelResource("message")
public void message() {
System.out.println("message");
}
}
第2步: 在Controller中声明两个方法,分别调用service中的方法message
java
@RestController
@Slf4j
public class OrderController5 {
@Autowired
private OrderServiceImpl2 orderService;
@RequestMapping("/order/message1")
public String message1() {
orderService.message();
return "message1";
}
@RequestMapping("/order/message2")
public String message2() {
orderService.message();
return "message2";
}
}
第3步:配置文件中将spring.cloud.sentinel.web-context-unify=true即可开启收敛
在 Web 应用中,同一个请求可能会有多种不同的 URL 地址和 HTTP 方法,例如 GET /user 和 POST /user 是两个不同的请求,但它们都是对用户资源的操作。如果不统一这些请求,会导致资源的重复计数,从而影响限流效果。因此,通过设置
web-context-unify
为true
,Sentinel 可以将这些不同的请求统一为同一个资源,并对其进行流量控制。
第4步: 控制台配置限流规则
第5步: 分别通过/order/message1 和/order/message2 访问, 发现1没问题, 2的被限流了
配置流控效果
- 快速失败(默认): 直接失败,抛出异常,不做任何额外的处理,是最简单的效果
- Warm Up:它从开始阈值到最大QPS阈值会有一个缓冲阶段,一开始的阈值是最大QPS阈值的 1/3,然后慢慢增长,直到最大阈值,适用于将突然增大的流量转换为缓步增长的场景。
- **排队等待:**让请求以均匀的速度通过,单机阈值为每秒通过数量,其余的排队等待; 它还会让设 置一个超时时间,当请求超过超时间时间还未处理,则会被丢弃。
五、Feign整合Sentinel
①导入依赖
XML
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
②在配置文件中开启Feign对Sentinel的支持
XML
# 开启feign对sentinel的支持
feign:
sentinel:
enabled: true
③创建容错类
java
@Component
public class FeignUserServiceImpl implements FeignUserService {
//容错类要求必须实现被容错的接口,并为每个方法实现容错方案
@Override
public String getByPath(String account) {
//写入到自己的数据估值表中
//程序员看到就会来处理
return "容错类启动......";
}
}
④为被容器的接口指定容错类
java
@FeignClient(value = "produce" ,fallback = FeignUserServiceImpl.class)
@Primary
public interface FeignUserService {
@RequestMapping("/user/{account}")
public String getByPath(@PathVariable(value = "account") String account);
}
在Spring Cloud中,使用Feign进行服务间的调用时,可以通过设置fallback属性来指定当请求失败或超时时的容错处理类。fallback属性是一个接口的实现类,它会在调用失败时被触发,以提供一个备用的处理逻辑。
当我们正常调用localhost:8084/test01的时候就会响应相应的结果
如果我们访问的模块服务宕机了就会跳转到我们的容错类
我们容错类就会将请求信息进行保存等待我们模块服务正常后重新发送请求
到这里我的分享就结束了,欢迎到评论区探讨交流!!
💖如果觉得有用的话还请点个赞吧 💖