1.雪崩问题和解决方案
微服务调用链路中的某个服务故障,引起整个链路中的所有微服务都不可用,这就是雪崩。
1.1 解决雪崩的常见方式有四种:
(1)超时处理:设定超时时间,请求超过一定时间没有响应就返回错误信息,不会无休止的等待。
(2)舱壁模式:限定每个业务能使用的线程数,避免耗尽整个tomcat的资源,因此也叫线程隔离。
(3)熔断降级:由断路器统计业务执行的异常比例,如果超出阈值会熔断该业务,拦截访问该业务的一切请求。
(4)流量控制:限制业务访问的QPS,避免因流量的突增而故障。
1.2 什么是雪崩问题?
(1)什么是雪崩问题?
微服务之间相互调用, 因为调用链中的一个服务故障,引起整个链路都无法访问的去情况。
(2)如何避免因瞬间高并发流量而导致服务故障?
流量控制
(3)如何避免因服务故障引起的雪崩问题?
1.超时处理 ;2.线程隔离 ; 3.降级熔断
2.认识sentinel
Sentinel是阿里巴巴开源的一款微服务流量控制组件。官网地址:home | Sentinel
Sentinel具有一下特征:
(1)丰富的应用场景:Sentinel承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
(2)完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
(3)广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
(4)完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。
2.1 安装Sentinel控制台
sentinel官方提供了UI控制台,方便我们对系统做限流设置。可以在GitHub下载。
(1)下载到非中文目录下,在路径上输入cmd进入黑窗口,然后执行命令:
java -jar sentinel-dashboard-1.8.1.jar
(2)启动之后,浏览器访问:localhost:端口号 即可进入控制台,账号密码都是:sentinel
(3)如果要修改Sentinel的默认端口、账户、密码,可以通过下列配置:
例如:java -Dserver.port=8090 -jar sentinel-dashboard-1.8.1.jar
(4)要使用Sentinel肯定要结合微服务,这里我们使用SpringCloud实用篇中的cloud-demo工程。没有的小伙伴可以在课前资料中找到:
2.2微服务整合Sentinel
我们在order-service中整合Sentinel,并且连接Sentinel的控制台,步骤如下:
(1)引入sentinel依赖
<!--sentinel-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
(2)配置控制台地址:
#配置sentinel地址
spring.cloud.sentinel.transport.dashboard=localhost:8070
(3)访问微服务的任意端点,触发sentinel监控
3.限流规则
3.1 簇点链路
就是项目内的调用链路,链路中被监控的每个接口就是一个资源。默认情况下sentinel会监控SpringMVC的每一个端点(Endpoint),因此SpringMVC的每一个端点(Endpoint)就是调用链路中的一个资源。
流控、熔断等都是针对簇点链路中的资源来设置的,因此我们可以点击对应资源后面的按钮来设置规则:
点击资源/order/{read}后面的流控按钮,就可以弹出表单。表单中可以添加流控规则
设置单机阈值为2:表示限制这个资源的单机QPS为2,即每秒只允许2次请求,超出的请求会被拦截并报错。
3.2流控模式
在添加限流规则时,点击高级选项,可以选择三种流控模式
(1)直接:统计当前资源的请求,触发阈值时对当前资源直接限流,也是默认模式。
(2)关联:统计与当前资源相关的另一个资源,触发阈值时,对当前资源限流
(3)链路:统计从指定链路访问到本地资源的请求,触发阈值时,对指定的链路限流
(1)流控模式:直接
(2)流控模式:关联
关联模式:统计当前资源相关的另一个资源,触发阈值时,对当前资源限流
Jmeter测试:当执行order/write资源每秒超过2次,则直接对read资源进行限流
order/write请求全部成功 :
order/read请求,当write每秒超过2次时开始失败
使用场景:
比如用户支付时需要修改订单状态,同时用户需要查询订单,查询和修改操作会争抢数据库锁,产生竞争;业务需求时优先支付和更新订单状态,因此当修改订单业务时触发阈值,需要对查询订单业务限流;
(3) 流控模式:链路
需求:
有查询订单和创建订单业务,两者都需要查询商品。针对从查询订单进入到查询商品的请求统计,并设置限流。
步骤:
(1)在orderService中添加good()方法,不用实现业务
(2)在OrderContorller中改造order/read和write路径的方法,都调用good()方法
(3)给good()方法设置限流规则,从order/read进入good方法限制QPS必须小于2
(4)在sentinel中默认只标记@controller中的方法为资源,如果要标记其他方法,需要利用@SentinelResource注解,示例:在server实现类中:
(5)Sentinel默认会将Controller方法做context整合,导致链路模式的流控失效,需要修改application.yml,添加配置:
#流控模式:链路---关闭context整合
spring.cloud.sentinel.web-context-unify=false
(6)在Jmeter中测试,read资源和write资源都需要调用good方法,只针对从read进入good方法统计, 并进行限流。
3.3流控效果
流控效果是指请求达到流控阈值时应该采取的措施,包括三种:
(1)快速失败:达到阈值后,新的请求会被立即拒绝并抛出FlowExecption异常,时默认的处理方法。
(2)warm up:预热模式,对超出阈值的请求同样时拒绝并抛出异常,但是这种模式阈值会动态变化,从一个小的值逐渐增加到最大的值。
测试结果:成功率逐渐上升,被拒绝QPS逐渐变少
(3)排队等待:让所有的请求按照先后次序排队执行,两个请求的间隔不能小于指定市场。
3.4 热点参数限流
之前的限流是统计访问某个资源的所有请求,判断是否超过QPS阈值。而热点参数限流是分别统计参数值相同的请求,判断是否超过QPS阈值。
配置示例:
controller层端点:
热点参数限流规则:
代表的含义是:对hot这个资源的0号参数(第一个参数)做统计,每1秒相同参数值的请求数不能超过2
如果参数值是102,则每一秒允许的QPS是4,超过4限流
如果参数值时103,则每一秒允许的QPS是10,超过10限流
Jmter测试:
3.5 熔断和降级
虽然限流可以尽量避免因高并发而引起的服务故障,但服务还会因为其它原因而故障。而要将这些故障控制在一定范围,避免雪崩,就要靠线程隔离(舱壁模式)和熔断降级手段了。
不管是线程隔离还是熔断降级,都是对客户端(调用方)的保护。
步骤一:在order项目中定义类,实现FallbackFactory:
package com.qwq.order.feign.factory;
import com.qwq.order.feign.ProductFeign;
import com.qwq.pojo.Product;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;
/**
* @program: spring_cloud2
* @author: 乔文庆
* @create: 2023-05-18 18:21
**/
@Component
public class ProductFeignFactory implements FallbackFactory<ProductFeign> {
@Override
public ProductFeign create(Throwable throwable) {
return new ProductFeign() {
@Override
public Product findProduct(Integer pid) {
Product product = new Product();
product.setPid(-1);
product.setPname("商品超时");
return product;
}
};
}
}
步骤二:在order项目中的ProductFeign接口中使用ProductFeignFactory:
package com.qwq.order.feign;
import com.qwq.order.feign.factory.ProductFeignFactory;
import com.qwq.pojo.Product;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
* @program: spring_cloud2
* @author: 乔文庆
* @create: 2023-05-14 13:57
**/
@FeignClient(value = "qy163-product",fallbackFactory = ProductFeignFactory.class) // vlaue=服务提供者的名字
public interface ProductFeign {
//抽象方法必须和服务提供者的方法完全一致
@GetMapping("product/findID/{pid}")
public Product findProduct(@PathVariable Integer pid);
}
浏览器测试:注意:测试时,在代码中抛出一个异常:
熔断降级: 熔断降级是解决雪崩问题的重要手段。其思路是由断路器统计服务调用的异常比例、慢请求比例,如果超出阈值则会熔断该服务。即拦截访问该服务的一切请求;而当服务恢复时,断路器会放行访问该服务的请求。
断路器熔断策略有三种:慢调用、异常比例、异常数
慢调用:业务的响应时长(RT)大于指定时长的请求认定为慢调用请求。在指定时间内,如果请求数量超过设定的最小数量,慢调用比例大于设定的阈值,则触发熔断。例如:
注释:RT超过300ms的调用是慢调用,统计最近1000ms内的请求,如果请求量超过3次,并且慢调用比例不低于0.5,则触发熔断,熔断时长为7秒。然后进入half-open状态,放行一次请求做测试,如果消耗时常还是超过300ms,则继续熔断,以此类推。
4. 规则持久化-push到配置中心nacos
4.1 规则管理模式-push模式
push模式:控制台将规则推送到远程配置中心,例如:Nacos,sentinel客户端监听Nacos,获取配置变更的推送消息,完成本地配置更新。
sentinel的持久化,我们希望这样:
(1)我们在sentinel控制台配置限流规则,并且同步到nacos做持久化
(2)我们在nacos中修改规则,同步到sentinel控制台
要实现上述第一个功能需要对 sentinel 控制台的源码有所了解,并加依改造。但 GitHub 上已经有人改造好了,做了个加强版 控制台
(1)打开上述网址 下载到本地 并解压
(2)打开根目录下的 pom.xml ,修改 sentinel 的版本
(3)进入项目根目录,cmd,执行命令: mvn clean package
(4)打包后生产在target目录下
(5)执行命令,启动控制台:
命令:
java -Dserver.port=8070 -jar sentinel-dashboard.jar
-Dserver.port 控制台端口号
# -Dnacos.serverAddr: nacos 地址
# -Dnacos.namespace: 你项目所在的 nacos 命名空间 如果命名空间就是public可以省略该参数
4.2 微服务客户端接入sentinel控制面板
(1)引入依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<version>1.8.1</version>
</dependency>
(2)修改配置文件
spring.cloud.sentinel.transport.dashboard=localhost:8070
spring.cloud.sentinel.datasource.ds1-flow.nacos.server-addr=localhost:8848
spring.cloud.sentinel.datasource.ds1-flow.nacos.data-id=${spring.application.name}-flow-rules
# 还可以是 degrade authority param-flow
spring.cloud.sentinel.datasource.ds1-flow.nacos.rule-type=flow
spring.cloud.sentinel.datasource.ds1-flow.nacos.data-type=json
spring.cloud.sentinel.datasource.ds1-flow.nacos.group-id=SENTINEL_GROUP
(3)启动微服务
然后浏览器访问:http://localhost:8090 , 最开始什么都没有,然后访问你自己的项目的任意一个要限流的接口,则 左侧会出现对于的 服务名称
注意,一定要点 带 2 的,只有带 2 的才能推送到 nacos,在 流控规则 选项中添加也不行,只能点击 蓝色方框 才能推送到 nacos
(4) 添加成功后,nacos 中,你指定的命名空间下会自动生成 ${application-name}-flow-rules 格式的配置文件