赞
踩
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。 Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护、 热点防护等多个维度保护服务的稳定性。
Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案,Sentinel 作为其核心组件之一,具有熔断与限流等一系列服务保护功能。
Spring Cloud Sentinel 里所有的资源都对应一个资源名称resourceName
,每次资源调用都会创建一个 Entry
对象。Entry 可以通过对主流框架的适配自动创建,也可以通过注解的方式或调用 SphU API 显式创建。Entry 创建的时候,同时也会创建一系列功能插槽 slot chain,这些插槽有不同的职责:
NodeSelectorSlot
负责收集资源的路径,并将这些资源的调用路径,以树状结构存储起来,用于根据调用路径来限流降级
ClusterBuilderSlot
用于存储资源的统计信息以及调用者信息,例如该资源的 RT, QPS, thread count 等等,这些信息将用作为多维度限流,降级的依据
StatisticSlot
用于记录、统计不同纬度的 runtime 指标监控信息
FlowSlot
用于根据预设的限流规则以及前面 slot 统计的状态,来进行流量控制
AuthoritySlot
根据配置的黑白名单和调用来源信息,来做黑白名单控制
DegradeSlot
通过统计信息以及预设的规则,来做熔断降级
SystemSlot
通过系统的状态,例如 load1 等,来控制总的入口流量
丰富的应用场景
Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
完备的实时监控
Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
广泛的开源生态
Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
完善的 SPI 扩展点
Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。
下载
下载地址
:https://github.com/alibaba/Sentinel/releases
Sentinel控制台是一个轻量级的控制台应用,它可用于实时查看单机资源监控及集群资源汇总,并提供了一系列的规则管理功能,如流控规则、降级规则、热点规则等。
启动
java -jar sentinel-dashboard-1.6.3.jar
测试
访问地址
:http://localhost:8080,用户名密码默认是sentinel
监控数据
添加依赖
<dependencyManagement> <dependencies> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.2.0.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId> </dependency> <!--搭配feign使用时需要--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
添加配置
server: port: 8081 spring: application: name: nacos-service cloud: nacos: discovery: server-addr: localhost:8848 service: ${spring.application.name} sentinel: # 是否开启服务的sentinel监控 enabled: true # 是否立即加载服务的sentinel监控 eager: true # 监听地址 transport: dashboard: localhost:8080 port: 8719 # 开启feign对sentinel的支持 feign: sentinel: enabled: true management: endpoints: web: exposure: include: '*'
编写控制器类
@RestController
public class UserController {
@GetMapping("/get/{id}")
public Map<String, Object> getUser(@PathVariable Long id) {
Map<String, Object> result = new HashMap<>();
result.put("type", "ok");
result.put("msg", "查询成功");
return result;
}
}
测试
多次访问地址
:http://localhost:8081/get/1,查看Sentinel监控
@SentinelResource注解
属性
value
资源名称
entryType
entry类型
blockHandler
指定BlockException异常处理器方法
@GetMapping("/show/test1") @SentinelResource(value = "test1", blockHandler = "myBlockHandler") public String test1(Long id) { return "test1调用成功"; } public String myBlockHandler(Long id, BlockException blockException){ if(blockException instanceof FlowException){ return "test1不可达,出现限流!"; } if(blockException instanceof DegradeException){ return "test1不可达,出现熔断!"; } return "test1不可达,出现其它异常!"; }
blockHandlerClass
指定BlockException异常处理器类
@GetMapping("/show/test1")
@SentinelResource(
value = "test1",
blockHandler = "myBlockHandler",
blockHandlerClass = SentinelBlockHandler.class
)
public String test1(Long id) {
System.out.println(1/0);
return "test1调用成功";
}
public class SentinelBlockHandler {
public String myBlockHandler(Long id, BlockException blockException){
if(blockException instanceof FlowException){
return "test1不可达,出现限流!";
}
if(blockException instanceof DegradeException){
return "test1不可达,出现熔断!";
}
return "test1不可达,出现其它异常!";
}
}
fallback
指定内部异常处理器方法
@GetMapping("/show/test1")
@SentinelResource(value = "test1", fallback = "myFallback")
public String test1(Long id) {
System.out.println(1/0);
return "test1调用成功";
}
public String myFallback(Long id){
return "test1不可达,出现内部调用异常!";
}
fallbackClass
指定内部异常处理器类
@GetMapping("/show/test1")
@SentinelResource(
value = "test1",
fallback = "myFallback",
fallbackClass = SentinelFallbackHandler.class
)
public String test1(Long id) {
System.out.println(1/0);
return "test1调用成功";
}
public class SentinelFallbackHandler {
public String myFallback(Long id){
return "test1不可达,出现内部调用异常!";
}
}
defaultFallback
指定内部异常默认处理器
exceptionsToIgnore
忽略指定的内部异常出现,不做fallback处理
@GetMapping("/show/test1") @SentinelResource( value = "test1", fallback = "myFallback", exceptionsToIgnore = {NullPointerException.class} ) public String test1(Long id) { if (id == 1) { throw new IndexOutOfBoundsException(); } else if (id == 2) { throw new NullPointerException(); } return "test1调用成功"; } public String myFallback(Long id){ return "test1不可达,出现内部调用异常!"; }
@SentinelRestTemplate注解
@Configuration
public class RibbonConfig {
@Bean
@SentinelRestTemplate
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
Sentinel 支持对服务间调用进行保护,对故障应用进行熔断操作
配置示例
属性说明
Field | 说明 | 默认值 |
---|---|---|
resource | 资源名,即规则的作用对象 | |
grade | 熔断策略,支持慢调用比例/异常比例/异常数策略 | |
count | 慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值 | |
timeWindow | 熔断时长,单位为 s | |
minRequestAmount | 熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(1.7.0 引入) | 5 |
statIntervalMs | 统计时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入) | 1000 ms |
slowRatioThreshold | 慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入) |
降级策略
平均响应时间
当指定资源的每秒请求量 >= N(默认为5,可以在启动sentinel时通过 -Dcsp.sentinel.statistic.max.rt=xxx 来设置)个时,如果这N个请求的平均响应时间如果超过指定的RT时间,就会触发熔断降级;如果此时在指定的时间窗口时间内没有任何请求,则熔断关闭,服务恢复正常。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M3oUyo2X-1616478058783)(Spring Cloud Alibaba.assets/20210321223354.png)]
异常比例
当指定资源的每秒请求量 >= N个时,如果在这N个请求处理中有超过指定比例的异常数出现,则就会触发熔断降级;如果此时在指定的时间窗口时间内没有任何请求,则熔断关闭,服务恢复正常。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iXvB0c4O-1616478058784)(Spring Cloud Alibaba.assets/20210321223926.png)]
异常数
在一分钟之内,如果指定资源的请求处理中有超过指定的异常数出现,则就会触发熔断降级;如果此时在指定的时间窗口时间内没有任何请求,则熔断关闭,服务恢复正常。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TFF31pHt-1616478058785)(Spring Cloud Alibaba.assets/20210321225020.png)]
限流原理
配置示例
属性说明
资源名(resource)
:限流规则的作用对象针对来源(limitApp)
:若为default,则不区分流量来源,即为所有服务阈值类型(grade)
:限流规则的种类
单机阈值(count)
:限流规则的数值是否集群(cluster)
:当前访问资源是否为集群流控模式(strategy)
:触发限流后的执行策略
流控效果(controllerBehavior)
:触发限流后的执行方式
编写控制器类
@RestController @RequestMapping("/rateLimit") public class RateLimitController { /** * 按资源名称限流,需要指定限流处理逻辑 */ @GetMapping("/byResource") @SentinelResource(value = "byResource") public CommonResult byResource() { return new CommonResult("按资源名称限流", 200); } /** * 按访问路径限流,有默认的限流处理逻辑 */ @GetMapping("/byUrl") @SentinelResource(value = "byUrl") public CommonResult byUrl() { return new CommonResult("按url限流", 200); } }
按资源名称限流
按访问路径限流
简介
两种身份
Token Client
集群流控客户端,用于向所属 Token Server 通信请求 token。集群限流服务端会返回给客户端结果,决定是否限流。
Token Server
集群流控服务端,处理来自 Token Client 的请求,根据配置的集群规则判断是否应该发放 token(是否允许通过)。
流控规则定义
客户端
ReadableDataSource<String, List<FlowRule>> flowRuleDataSource =
new NacosDataSource<>(remoteAddress, groupId, dataId, parser);
FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
服务端
ClusterFlowRuleManager.setPropertySupplier(namespace -> {
return new SomeDataSource(namespace).getProperty();
});
启动方式
独立模式
作为独立的 token server 进程启动,独立部署,隔离性好,但是需要额外的部署操作。独立模式适合作为 Global Rate Limiter 给集群提供流控服务。
嵌入模式
作为内置的 token server 与服务在同一进程中启动。在此模式下,集群中各个实例都是对等的,token server 和 client 可以随时进行转变,因此无需单独部署,灵活性比较好。但是隔离性不佳,需要限制 token server 的总 QPS,防止影响应用本身。嵌入模式适合某个应用集群内部的流控。
分配配置
Token Server
限流客户端
添加依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-cluster-client-default</artifactId>
<version>1.8.0</version>
</dependency>
限流服务端
添加依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-cluster-server-default</artifactId>
<version>1.8.0</version>
</dependency>
简介
Sentinel 支持对 Spring Cloud Gateway、Zuul 等主流的 API Gateway 进行限流。
限流规则
GatewayFlowRule:网关限流规则,针对 API Gateway 的场景定制的限流规则,可以针对不同 route 或自定义的 API 分组进行限流,支持针对请求中的参数、Header、来源 IP 等进行定制化的限流。
resource
资源名称,可以是网关中的 route 名称或者用户自定义的 API 分组名称。
resourceMode
规则是针对 API Gateway 的 route(RESOURCE_MODE_ROUTE_ID)还是用户在 Sentinel 中定义的 API 分组(RESOURCE_MODE_CUSTOM_API_NAME),默认是 route。
grade
限流指标维度,同限流规则的 grade 字段。
count
限流阈值
intervalSec
统计时间窗口,单位是秒,默认是 1 秒。
controlBehavior
流量整形的控制效果,同限流规则的 controlBehavior 字段,目前支持快速失败和匀速排队两种模式,默认是快速失败。
burst
应对突发请求时额外允许的请求数目。
maxQueueingTimeoutMs
匀速排队模式下的最长排队时间,单位是毫秒,仅在匀速排队模式下生效。
paramItem
参数限流配置。若不提供,则代表不针对参数进行限流,该网关规则将会被转换成普通流控规则;否则会转换成热点规则。其中的字段:
实现原理
SphU.entry(res, args)
中。GatewayFlowSlot
,专门用来做网关规则的检查。GatewayFlowSlot
会从 GatewayRuleManager
中提取生成的热点参数规则,根据传入的参数依次进行规则检查。若某条规则不针对请求属性,则会在参数最后一个位置置入预设的常量,达到普通流控的效果。测试使用
在 API Gateway 端,用户只需要在原有启动参数的基础上添加如下启动参数即可标记应用为 API Gateway 类型:
# 注:通过 Spring Cloud Alibaba Sentinel 自动接入的 API Gateway 整合则无需此参数
-Dcsp.sentinel.app.type=1
Spring Cloud Gateway
添加依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-spring-cloud-gateway-adapter</artifactId>
<version>x.y.z</version>
</dependency>
Spring Cloud Zuul
添加依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-zuul-adapter</artifactId>
<version>x.y.z</version>
</dependency>
默认情况下在Sentinel控制台中配置规则时,控制台推送规则方式是通过API将规则推送至客户端并直接更新到内存中。一旦我们重启应用,规则将消失。我们可以将配置规则进行持久化,以存储到Nacos为例。
原理
使用
添加依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
添加配置
spring:
cloud:
sentinel:
datasource:
ds1:
nacos:
server-addr: localhost:8848
dataId: ${spring.application.name}-sentinel
groupId: DEFAULT_GROUP
data-type: json
rule-type: flow
Nacos配置
添加如下内容
[ { // 资源名称 "resource": "/rateLimit/byUrl", // 来源应用 "limitApp": "default", // 阈值类型,0表示线程数,1表示QPS "grade": 1, // 单机阈值 "count": 1, // 流控模式,0表示直接,1表示关联,2表示链路 "strategy": 0, // 流控效果,0表示快速失败,1表示Warm Up,2表示排队等待 "controlBehavior": 0, // 是否集群 "clusterMode": false } ]
测试
启动服务以及Sentinel面板
快速访问测试接口
【源码地址】:GitHub
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。