随着微服务的流行,服务和服务之间的稳定性变得越来越重要。 Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
Sentinel 具有以下特征:
丰富的应用场景: Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、实时熔断下游不可用应用等。
完备的实时监控: Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
广泛的开源生态: Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
完善的 SPI 扩展点: Sentinel 提供简单易用、完善的 SPI 扩展点。您可以通过实现扩展点,快速的定制逻辑。例如定制规则管理、适配数据源等。
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-alibaba-dependenciesartifactId>
<version>2.2.9.RELEASEversion>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
dependency>
Sentinel 控制台提供一个轻量级的控制台,它提供机器发现、单机资源实时监控、集群资源汇总,以及规则管理的功能。您只需要对应用进行简单的配置,就可以使用这些功能。
注意:下载的jar包要对应 Spring Cloud alibaba 的版本
Sentinel 控制台是一个标准的 Spring Boot 应用,以 Spring Boot 的方式运行 jar 包即可。
Sentinel 控制台默认的端口为8080,为避免端口冲突可以通过自定义端口的命令启动.
java -jar sentinel-dashboard.jar
或
java -Dserver.port=自定义端口 -Dcsp.sentinel.dashboard.server=IP:自定义端口 -jar sentinel-dashboard.jar
server:
port: 8088
spring:
application:
name: sentinel-client
cloud:
sentinel:
transport:
dashboard: localhost:8080
流量控制在网络传输中是一个常用的概念,它用于调整网络包的发送数据。然而,从系统稳定性角度考虑,在处理请求的速度上,也有非常多的讲究。任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制。Sentinel 作为一个调配器,可以根据需要把随机的请求调整成合适的形状.
其原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。
流量控制主要有两种统计类型,一种是统计并发线程数,另外一种则是统计 QPS。类型由 FlowRule 的 grade 字段来定义。其中,0 代表根据并发数量来限流,1 代表根据 QPS 来进行流量控制。其中线程数、QPS 值,都是由 StatisticSlot 实时统计获取的。
控制脉冲流量 针对不用调用来源进行流控 web接口流控
流量控制有以下几个角度:
资源的调用关系,例如资源的调用链路,资源和资源之间的关系;
运行指标,例如 QPS、线程池、系统负载等;
控制的效果,例如直接限流、冷启动、排队等。
梳理核心接口 通过事前压测评估核心接口的容量,配置QPS阈值
一条限流规则主要由下面几个因素组成,我们可以组合这些元素来实现不同的限流效果:
Field | 说明 | 默认值 |
---|---|---|
resource | 资源名,资源名是限流规则的作用对象 | 直接拒绝 |
count | 限流阈值 | |
grade | 限流阈值类型,QPS(1) 或线程数模式(0) | QPS 模式 |
limitApp | 流控针对的调用来源 | default,代表不区分调用来源 |
strategy | 调用关系限流策略:直接、链路、关联 | 根据资源本身(直接) |
controlBehavior | 流控效果(直接拒绝 / 排队等待 / 慢启动模式),不支持按调用关系限流 | 直接拒绝 |
QPS :指的是在一秒内同时服务的请求数 (并发数)
线程数 : 指同时在处理请求的线程数量
当配置了流程参数设置后,程序达到流控上限,会返回下面的提示
如果需要自定义放回或是需要在降级之后增加处理逻辑可以通过 @SentinelResource 实现
@SentinelResource
代码示例:
value 对应的是 resource 资源名 需要在控制台中设置流控参数自定义返回开会生效
blockHandler 块异常函数的名称 (使用blockHandler 指定的方法需要在定义在同一个类中)
blockHandlerClass 指定的方法不在同一个类中可以使用blockHandlerClass来指定,但是方法必须声明为static 静态方法,
/**
* blockHandlerClass = WebUtil.class
*/
@RequestMapping(value = "/index",method = RequestMethod.GET)
@SentinelResource(value = "index",blockHandler = "testBlockHandler")
public CommonResult test(){
return new CommonResult("OK");
}
//自定义流控返回
public CommonResult testBlockHandler(BlockException e){
return new CommonResult("流控");
}
如果不想用 @SentinelResource 注解来处理,则可以采用统一异常处理,如果需要对不同的业务做不同的处理,建议使用 @SentinelResource 注解来处理.
一旦使用了@SentinelResource 注解来处理,统一异常处理就不会被使用,需要另外定义返回
import com.alibaba.csp.sentinel.adapter.spring.webmvc.callback.BlockExceptionHandler;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityException;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
import com.alibaba.csp.sentinel.slots.block.flow.FlowException;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowException;
import com.alibaba.csp.sentinel.slots.system.SystemBlockException;
import com.car.hailing.saas.base.CommonResult;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Slf4j
@Component
public class MyBlockExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
//getRule() 规则的详细信息
log.info("lockExceptionHandler============="+e.getRule());
CommonResult r = null;
if (e instanceof FlowException){
r = new CommonResult<>(100,"接口限流");
}else if (e instanceof DegradeException){
r = new CommonResult<>(101,"服务降级");
}else if (e instanceof ParamFlowException){
r = new CommonResult<>(102,"热点参数限流");
}else if (e instanceof SystemBlockException){
r = new CommonResult<>(103,"出发系统保护规则");
}else if (e instanceof AuthorityException){
r = new CommonResult<>(104,"授权规则不通过");
}
httpServletResponse.setStatus(500);
httpServletResponse.setCharacterEncoding("utf-8");
httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);
new ObjectMapper().writeValue(httpServletResponse.getWriter(),r);
}
}
/**
* api rest返回实体
*/
@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
public class CommonResult<T> implements Serializable {
private int code;
private String msg;
private T data;
/**
* 默认成功
*/
public CommonResult()
{
this.code = SystemResult.SUCCESS.code;
this.msg = SystemResult.SUCCESS.message;
}
public CommonResult(T t)
{
this.code = SystemResult.SUCCESS.code;
this.msg = SystemResult.SUCCESS.message;
this.data = t;
}
public CommonResult(SystemResult r)
{
this.code = r.code;
this.msg = r.message;
this.data = null;
}
public CommonResult(int r, String t)
{
this.code = r;
this.msg = t;
this.data = null;
}
}
1.直接 模式: 直接模式就是对当前入口直接限流
2.关联 模式 : 当关联的资源达到阈值时就会对配置的资源进行限流
比如: 下单接口和查询订单接口,当我们对查询接口设置了流控规则并关联了下单接口,当下单接口的请求数量达到阈值时,就会对查询接口进行限流,这样就能保证下单接口的安全性
3.链路模式 : 对调用链路的入口进行限流,Sentinel不仅可以对接口入口进行限流还可以对方法进行限流.
例如 我们通过@SentinelResource 对 方法getUser 进行了限流,通过链路模式关联了接口A,在调用过程中,接口A和接口B都会调用getUser方法,当getUser方法达到调用阈值时,就会对关联的接口A进行限流,而接口B可以不受限制的进行调用.
使用链路模式还需要配置一下web-context-unify配置,限流才会生效
spring:
cloud:
sentinel:
transport:
dashboard: localhost:8080
#展开调用链路, 默认为收起
web-context-unify: false
1.快速失败: 当并发量超过设置的阈值后,超出的请求会被直接拒绝.
- Warm Up(激增流量) : 流控预热模式有一个预热时长参数,当大量请求过来时,并不是直接处理相当于阈值数量的请求,而是在设置的预热时长内,逐渐递增式的处理请求,直到达到阈值数量.递增初始值的冷加载因子值为设置的阈值除以3.
- 排队等待(脉冲流量): 相当于队列,当大量请求过来时,超过阈值的请求不会马上拒绝,而是进行排队等待,并提供了一个设置超时时间的参数,在超时时间到期之前,如果前面的请求被出来完,排队等待中的请求会被继续处理
除了流量控制以外,降低调用链路中的不稳定资源也是 Sentinel 的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳定,最终会导致请求发生堆积。这个问题和 Hystrix 里面描述的问题是一样的。
慢调用比例 (SLOW_REQUEST_RATIO):选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
异常比例 (ERROR_RATIO):当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
异常数 (ERROR_COUNT):当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。
注意异常降级仅针对业务异常,对 Sentinel 限流降级本身的异常(BlockException)不生效。为了统计异常比例或异常数,需要通过 Tracer.trace(ex) 记录业务异常。
熔断降级规则说明
熔断降级规则(DegradeRule)包含下面几个重要的属性:
Field | 说明 | 默认值 |
---|---|---|
resource | 资源名,即规则的作用对象 | |
grade | 熔断策略,支持慢调用比例/异常比例/异常数策略 | 慢调用比例 |
count | 慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值0~1之间的数 | |
timeWindow | 熔断时长,单位为 s | |
minRequestAmount | 熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(1.7.0 引入) | 5 |
statIntervalMs | 统计时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入) | 1000 ms |
slowRatioThreshold | 慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入) |
1.添加依赖
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
2.开启Openfeign对sentinel支持配置
#开启Openfeign对sentinel的支持默认为false
feign:
sentinel:
enabled: true
3.添加对Openfeign接口的实现
public class UserFeignServuceFallback implements UserFeignServuce {
@Override
public String test() {
//TODO 降级操作 实现feign接口的方法 可以在这里做失败处理 比如可以在这里记录降级日志,后续自动补偿
//比如 积分服务, 在服务降级的请求下,如果积分服务被关闭,无法调用,可以现在这里记录日志,需要添加的用,和对应的积分
// 可以通过另外的定时任务捞取日志中的失败操作对用户进行补偿
return null;
}
}
4.在Openfeign接口添加 fallback 属性,并指向实现类
@FeignClient(value = "manage-client",fallback = UserFeignServuceFallback.class)
public interface UserFeignServuce {
@RequestMapping(value = "/index/test")
String test();
}
热点参数规则使用必须要配合 @SentinelResource 注解来处理
热点参数规则(ParamFlowRule)类似于流量控制规则(FlowRule):
属性 | 说明 | 默认值 |
---|---|---|
resource | 资源名,必填 | |
count | 限流阈值,必填 | |
grade | 限流模式 | QPS 模式 |
durationInSec | 统计窗口时间长度(单位为秒),1.6.0 版本开始支持 | 1s |
controlBehavior | 流控效果(支持快速失败和匀速排队模式),1.6.0 版本开始支持 | 快速失败 |
maxQueueingTimeMs | 最大排队等待时长(仅在匀速排队模式生效),1.6.0 版本开始支持 | 0ms |
paramIdx | 热点参数的索引,必填,对应 SphU.entry(xxx, args) 中的参数索引位置 | |
paramFlowItemList | 参数例外项,可以针对指定的参数值单独设置限流阈值,不受前面 count 阈值的限制。仅支持基本类型和字符串类型 | |
clusterMode | 是否是集群参数流控规则 | false |
clusterConfig | 集群流控相关配置 |
Sentinel 系统自适应保护从整体维度对应用入口流量进行控制,结合应用的 Load、总体平均 RT、入口 QPS 和线程数等几个维度的监控指标,让系统的入口流量和系统的负载达到一个平衡,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。
系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量(EntryType.IN),比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。
系统规则支持以下的阈值类型:
属性 | 说明 |
---|---|
Load(仅对 Linux/Unix-like 机器生效) | 当系统 load1 超过阈值,且系统当前的并发线程数超过系统容量时才会触发系统保护。系统容量由系统的 maxQps * minRt 计算得出。设定参考值一般是 CPU cores * 2.5 |
CPU usage(1.5.0+ 版本) | 当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0) |
RT | 当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒 |
线程数 | 当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护 |
入口 QPS | 当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护 |
1.引入依赖
<dependency>
<groupId>com.alibaba.cspgroupId>
<artifactId>sentinel-datasource-nacosartifactId>
dependency>
2.在nacos上新建一个sentinel配置文件,默认为json格式
[
{
“resource”: “/api/test”,
“count”:2,
“grade”:1,
“limitApp”:“default”,
“strategy”:0,
“controlBehavior”:0
}
]
3.yaml配置sentinel整合nacos持久化配置
spring:
application:
name: manage-client
cloud:
nacos:
server-addr: 127.0.0.1:8848
discovery:
username: nacos
password: nacos
namespace: public
sentinel:
transport:
dashboard: localhost:8080
web-context-unify: false
datasource:
nacos-sentinel: #可以自定义
#可以与多种组件整合使用 file/nacos/zk/apollo/redis/consul
nacos:
serverAddr: 127.0.0.1:8847
username: nacos
password: nacos
#自定义了命名空间 可以指定命名空间
namespace: public
#自定义了分组,可以指定分组
groupId: DEFAULT_GROUP
#对应nacos中添加的sentinel配置的DataID
dataId: sentinel-config
#指定规则 flow 流控/degrade 降级/param-flow 热点规则/system系统规则/authority 授权/gw-flow 网关限流
ruleType: flow