目录
一、导览
Sentinel与Hystrix一样,都是Spring Cloud Circuit Breaker的具体实现(其实这句表述不严谨,因为Sentinel可以不依赖于Spring Cloud)。
Sentinel支持服务流控、熔断降级等功能。
Sentinel 的使用可以分为两个部分:
- 核心库(Java 应用客户端):不依赖任何框架/库,能够运行于 Java 8 及以上的版本的运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持(见 主流框架适配)。是真正的规则执行者。
- 控制台(Dashboard):Dashboard 主要负责管理推送规则、监控、管理机器信息等。它只是一个控制台(控制台是可选的),本身不负责存储规则和流量控制。
二、Sentinel 基本概念
资源
资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。在接下来的文档中,我们都会用资源来描述代码块。
只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源。
规则
围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则。所有规则可以动态实时调整。
三、Sentinel控制台Dashboard
Sentinel 提供一个轻量级的开源控制台,它提供机器发现以及健康情况管理、监控(单机和集群),规则管理和推送的功能。 (流控和服务降级规则的具体执行还是应用中的Sentinel,而不是控制台)
Sentinel 控制台包含如下功能:
- 查看机器列表以及健康情况:收集 Sentinel 客户端发送的心跳包,用于判断机器是否在线。
- 监控 (单机和集群聚合):通过 Sentinel 客户端暴露的监控 API,定期拉取并且聚合应用监控信息,最终可以实现秒级的实时监控。
- 规则管理和推送:统一管理推送规则(但不存储规则,不执行规则)。
- 鉴权:生产环境中鉴权非常重要。这里每个开发者需要根据自己的实际情况进行定制。
1、下载:https://github.com/alibaba/Sentinel/releases
2、运行:
java -Dserver.port=8383 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.2.jar
其中 -Dserver.port=8383
用于指定 Sentinel 控制台监听端口为 8383
3、启动后浏览器访问:http://IP:端口 (用户名密码默认都是sentinel)
这里还看不到应用情况。因为这时没有应用向Sentinel报告情况。
四、Sentinel客户端(应用程序)
Sentinel本身是独立组件,可以不与Spring Cloud绑定。但是由于使用Spring Cloud比较多,这里也使用Spring为例。
在之前的工程( 以此工程为基础 https://blog.youkuaiyun.com/zyplanke/article/details/120860958 ) 的基础上。
1、增加sentinel依赖
------ 省略 ------
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>${springcloudalibaba.version}</version>
</dependency>
------ 省略 ------
2、增加应用与控制台之间的互联参数。
以下方法一与方法二任选其一即可,两种配置效果等价
【方法一】:在Java启动时增加两个 JVM参数
-Dcsp.sentinel.dashboard.server=IP:8383
-Dcsp.sentinel.api.port=8719
第1个JVM参数为:Sentinel控制台地址,该应用程序(客户端)会自动向该控制台地址发送心跳包。
第2个JVM参数为:该应用程序(客户端)在本地启动的HTTP端口(默认起始端口8719,如果端口已经被占用,则自动依次递增直到找到空闲的端口),Sentinel控制台会访问此端口(例如控制台增加一条规则时,会把规则通过此端口push传输给应用)。
【方法二】:在Spring 的application.properties配置文件(或者配置中心)通过参数:
spring.cloud.sentinel.transport.dashboard和spring.cloud.sentinel.transport.port配置指定
注:确保应用程序与Sentinel控制台之间网络通畅。
3、通过控制台查看情况
必须确保应用程序(客户端)有访问量。应用至少需要1笔访问,以完成Sentinel初始化(这样在Sentinel控制台才能看到)
以上实时监控仅存储 5 分钟以内的数据,如果需要持久化,需要通过调用实时监控接口来定制
五、定义流控规则
在Sentinel控制台中,对payment服务新增一条流量规则,如下:
各个规则的参数配置和含义,请参考官网:https://sentinelguard.io/zh-cn/docs/introduction.html
若QPS阈值为0,则相当于全部按失败处理。(严格说QPS设置小于1都会按失败处理,因为每笔业务计数为1,每笔都会超过QPS设置,所以都会按全部失败处理)
是否集群:
- 单机:流控规则仅对设置的单机(应用程序)有效。
- 集群:集群限流需要一些前置条件(例如理解server和client两种身份概念并进行配置,确认应用程序存在sentinel-cluster*依赖,需要对接动态规则源),否则可能会退化至单机限流模式。具体参考:https://github.com/alibaba/Sentinel/wiki/%E9%9B%86%E7%BE%A4%E6%B5%81%E6%8E%A7
在控制台定义规则后,会自动把规则传输给应用程序(这里即payment应用服务)。
规则的存放和执行都是在应用程序端完成。 控制台只接收应用程序的报告,控制台本身不存放这些规则(仅在内存中暂存)。
这时在调用payment服务时,则sentinel会执行此流控规则。超过此规则的,payment服务会按规则定义返回对应信息。
payment服务中对访问的拒绝(默认无日志,可以开启日志或自行增加代码输出日志显示)。
在调用方(order服务)的日志中可以看到由payment服务返回的HTTP Status=429,信息为:“Blocked by Sentinel (flow limiting)”
Sentinel默认会把对外暴露的HTTP服务作为资源。通过查看源代码,其过程简要总结如下:
- 类DefaultBlockExceptionHandler中:定义了默认的Block处理行为:服务端向response写入“Blocked by Sentinel (flow limiting)”文本内容作为HTTP返回
- 类SentinelWebAutoConfiguration中:创建sentinelWebInterceptor的Bean时依赖了sentinelWebMvcConfig的Bean,而在创建sentinelWebMvcConfig的Bean过程中:若已经存在BlockExceptionHandler的Bean对象则使用该对象,否则new DefaultBlockExceptionHandler()。
- Spring Interceptor的子类SentinelWebInterceptor和AbstractSentinelInterceptor中:定义了拦截器的具体动作。
- 类SentinelWebMvcConfigurer中:使用了拦截器sentinelWebInterceptor的Bean,并将该拦截器增加/注册到Spring Interceptor列表中。
六、定义资源Resource
Sentinel默认会把对外暴露的HTTP服务作为资源,我们有时需要自己定义资源。(比如将某个函数定义为资源)。定义资源的方法如下:
1、利用@SentinelResource注解(该注解要求 SentinelResourceAspect类型的Bean存在才生效,该Bean已经由类SentinelAutoConfiguration中完成创建),在需要的地方将某个函数定义为资源。示例如下:
@RestController
public class PaymentController {
@Value("${server.port}")
private int myport;
@GetMapping("/dopay/{orderid}")
@SentinelResource(value = "resourcePayPPP", entryType = EntryType.IN, fallback = "fallbackHandler")
public ResponseEntity<String> paylogic(@PathVariable("orderid") Long orderid) {
return ResponseEntity.ok("支付服务successful! orderid=" + orderid + ", 支付成功。 支付服务的端口为port=" + myport );
}
/**
* 服务降级的处理函数,需要与原函数的返回类型、入参保持一致(入参最后需要增加一个BlockException)
*/
public ResponseEntity<String> fallbackHandler (Long orderid, BlockException e) {
System.err.println("fallbackHandler 限流,当前系统忙");
return ResponseEntity.ok("限流,当前系统忙");
}
}
注解@SentinelResource属性:value资源名(必须指定);entryType方向(IN还是OUT); fallback 降级的函数名。 该注解更多属性既说明请参阅源代码或官网:https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81
若工程已引入了Spring Cloud Alibaba的依赖spring-cloud-starter-alibaba-sentinel,则无需额外进行配置,注解@SentinelResource会在类SentinelAutoConfiguration中调用创建SentinelResourceAspect的Bean时进行识别处理。
2、启动后(需要存在流量),可以在控制台中“簇点链路”菜单界面中,查看应用程序的资源情况(如下)。 然后可以对资源名,进行规则设置(具体参见控制台操作)。
七、热点规则
何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top N 数据,并对其访问进行限制。比如:
- 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
- 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制
热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
1、增加热点规则
上图中:
- 限流模式:只能为QPS
- 参数索引从资源函数的入参从左往右树,第一个为0,第二个为1。。。
- 单机阈值:限流QPS阈值
- 统计窗口时长:以多长时间窗口进行阈值统计。
2、增加规则后,若每次调用传入的入参值不同,则不会触发热点规则。若某个时间段内每次传入的入参值大量相同(例如同时间类,以相同的入参值进行调用访问),则会形成热点,触发热点限流。
可以通过Jmeter等工具模拟发出HTTP请求
八、API获取Sentinel信息
可以通过以下API,获取应用程序(客户端)当前已经有的规则,以JSON数组形式返回规则数据应用程序ip不是Sentinel控制台的ip而是是客户端的IP;端口不是服务的端口而是sentinel端口(默认起始端口8719)。
# 获取应用程序的 流控规则
curl http://应用程序ip:sentinel端口/getRules?type=flow
# 获取应用程序的 服务熔断降级规则
curl http://应用程序ip:sentinel端口/getRules?type=degrade
# 获取应用程序的 系统保护规则
curl http://应用程序ip:sentinel端口/getRules?type=system
# 获取应用程序的 某个资源的统计信息
curl http://应用程序ip:sentinel端口/cnode?id=resourceName
九、规则持久化(规则中心)
由于Sentinel默认会将规则保存应用程序的内存中,重启应用后规则数据都会丢失。因此需要将流控和降级规则持久化保存外部数据源中(例如文件、数据库、Nacos等),这样在应用启动时从外部数据源读取规则。
这里以Nacos为例(以此工程为基础演示 https://blog.youkuaiyun.com/zyplanke/article/details/120860958)。
1、以Nacos配置中心作为Sentinel的外部数据源,需要在应用程序中增加依赖
------ 省略 ------
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>${springcloudalibaba.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<version>1.8.0</version>
</dependency>
------ 省略 ------
2、因应用程序已经使用Nacos作为配置中心,则在Nacos上的应用配置Data ID=paymentService.properties内容里,增加Sentinel外部数据源配置,内容如下
# 指定Sentinel控制台的IP和端口
#spring.cloud.sentinel.transport.dashboard=ip:port
#配置Sentinel规则中心来源(持久化存放在Nacos配置中心)
spring.cloud.sentinel.datasource.ds1.nacos.rule-type=flow
spring.cloud.sentinel.datasource.ds1.nacos.server-addr=39.100.80.168:8848
spring.cloud.sentinel.datasource.ds1.nacos.data-id=sentinel_rules_flow.json
spring.cloud.sentinel.datasource.ds1.nacos.group-id=DEFAULT_GROUP
spring.cloud.sentinel.datasource.ds1.nacos.data-type=json
3、在Nacos配置中心增加Data ID配置(与上步配置对应),其中JSON的规则内容如下。
注意JSON内容有方括号(内容可以借鉴前文通过curl访问API获得的JSON内容作为参考 )
[
{
"resource": "/dopay/{orderid}",
"limitApp": "default",
"grade": 1,
"count": 1,
"controlBehavior": 0,
"strategy": 0,
"clusterMode": false
}
]
4、重启应用 (启动后,需要至少由1笔流量)。
5、测试验证。这是测试可以发现流控规则已经生效,且在Sentinel控制台也也能看到这个流控规则
过程:客户端应用从Nacos配置中心获取规则并作用于本应用。 后续,客户端应用会主动向Sentinel控制台报告,所以Sentinel控制台界面也能看到该规则
十、在生产环境中使用Sentinel
具体见下文: