微服务之Spring cloud alibaba入门——Sentinel篇
一. 官网简介
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
Sentinel 具有以下特征:
- 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
- 完备的实时监控:Sentinel 同时提供实时的监控功能。可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
- 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
- 完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。
Setinel的主要特征:
二. Sentinel控制台安装
-
下载jar包
-
启动运行控制台
启动控制台:jar -jar 下载的jar包
浏览器输入:http://localhost:8080/
默认的登录名和密码为都为sentinel
三. Sentinel——初始化工程
-
引入pom依赖
<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> <!-- sentinel的持久化配置--> <dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
-
创建application.yml
server: port: 8512 spring: application: name: cloud-sentinel-provider cloud: nacos: #注册中心的地址 discovery: server-addr: localhost:8848 sentinel: transport: #配置仪表盘 dashboard: localhost:8080 port: 8719 # 默认为8719,若已被占用则会自动递增 management: endpoints: web: exposure: include: "*"
-
修改主启动类
@SpringBootApplication @EnableDiscoveryClient public class Sentinel8512Application { public static void main(String[] args) { SpringApplication.run(Sentinel8512Application.class,args); } }
-
创建测试类
@RestController public class FlowLimitController { @GetMapping(value = "/testA") public String testA(){ return "=======Test A======="; } @GetMapping(value = "/testB") public String testB(){ return "=======Test B======="; } }
-
测试监控功能
启动该项目后,在打开的sentinel仪表盘中仍然看不到任何信息,因为sentinel采用的是懒加载模式,只有请求了某个服务后才会在仪表盘显示相应的服务。在服务器中输入http://localhost:8512/testA
或者http://localhost:8512/testB
,再次查看sentinel的仪表盘,可以发现服务出现在了列表中,并且打开后在实时监控处可以查看刚刚请求的情况。在簇点链路处也可以看到刚刚的请求路径,并且在该处可以为相应的链路设置流控规则、降级、热点、授权等。
四. Sentinel——流控规则
-
资源名:唯一名称,默认请求路径
-
针对来源:Sentinel可以针对调用者进行限流,填写微服务名,默认default
-
阈值类型:
- QPS:调用该API的QPS达到阈值时进行限流,可以设置流控效果
- 线程数:当调用该API的线程数超过阈值时进行限流,不能设置流控效果
-
流控模式:
名称 说明 直接 API达到限流条件时,直接限流并返回错误页面 关联 当关联的资源达到阈值时,就限流自己 链路 只记录指定链路上的流量 -
流控效果
名称 说明 快速失败 直接失败,抛异常 Warm up 根据CodeFactor(冷加载因子,默认为3)的值,从阈值/CodeFactor的值,经过预热时长,才达到设置的QPS阈值。秒杀系统经常使用 排队等待 请求过多时,让请求匀速的进入后台进行处理。采用漏斗算法,控制流量 通过仪表盘可以很轻松的配置流控规则,同时也可通过代码配置,代码配置可自行在官网查看。
五. Sentinel——降级规则
Sentinel的熔断降级会在调用链路中某个资源出现不稳定状态时,对这个资源进行限制,让请求快速失败,避免影响其他资源。当资源被降级后,在时间窗口内,所有的对该资源的调用都会被降级。
- 降级策略
名称 说明 RT(平均响应时间) 平均响应时间超出阈值,并且时间窗内的请求数>5,时间窗口后关闭降级 异常比例 超过一定的异常比例触发,并且时间窗内的请求数>5,时间窗口后关闭降级 异常数 超过一定的异常数触发,时间窗口后关闭降级
六. SentinelResouce
Sentinel 提供了 @SentinelResource 注解用于定义资源,该注解用于定义降级方法或者处理BlockException的方法。
属性说明:
- value:用于定义资源的名称
- blockHandler:对应处理 BlockException 的函数名称,函数访问范围需要是 public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException
- blockHandlerClass:存放了处理 BlockException 的函数
- fallback:用于在抛出异常的时候提供 fallback 方法处理逻辑
- fallbackClass:存放了处理java异常的函数
- exceptionsToIgnore:发生该异常忽略
七. Sentinel——热点规则
热点即经常访问的数据,可以通过热点规则对访问量特别大的数据进行限制。热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。
- 资源名:该处的资源名必须为@SentinelResource注解中设置的资源名
- 参数索引:该处的索引为方法中参数的下标,从0开始,通过参数索引的设置,sentinel就知道要限制的参数名称。那么url中有该参数时,若不符合热点规则,会抛出BlockException,那么会对本次访问进行限制,调用block handler的方法。
- 参数例外项:当参数是某一类型或者值在某一范围内可以单独设定规则
该处配置SentinelResource时,最好配置block handler方法,否则对用户不友好。
代码演示:在测试类添加如下代码,给资源名为test_hotkey的资源添加热点规则,当不符合该规则时,则会调用blockhandler中的方法,可以看到两个函数的返回值相同,参数列表的区别在于处理异常的函数比原函数多一个BlockException函数。
@GetMapping(value = "/testHot")
@SentinelResource(value = "test_hotkey",blockHandler ="handle_C" )
public String testHot(@RequestParam(value = "p1",required = false) String p1,
@RequestParam(value = "p2",required = false) String p2){
return "======testHot======";
}
public String handle_C(String p1, String p2, BlockException exception){
return "======handle_hot======";
}
定义全局处理类:如果处理异常的方法和原方法同一个类中会显得代码十分臃肿,那么sentinel可以实现将所有的兜底方法定义在另外的一个类中,只要求保证对应处理异常的方法和原方法返回值相同,参数列表多一个BlockException,且都为静态方法。
- 定义全局处理类
public class MyHandler { public static String handleEx1(BlockException exception){ return "handleEx1"; } public static String handleEx2(BlockException exception){ return "handleEx2"; } }
- 测试类添加测试代码
@GetMapping(value = "/testOutHandler") @SentinelResource(value = "test_OutHandler",blockHandlerClass = MyHandler.class,blockHandler ="handleEx1" ) public String testOutHandler(){ return "======testOutHandler======"; }
八. Sentinel——系统规则
名称 | 说明 |
---|---|
Load自适应 | 适用于linux和unix系统,一般参考值为CPU核数*2.5 |
CPU使用率 | 当系统CPU使用率高过阈值即触发系统保护 |
平均RT | 当所有入口流量的平均响应时间超过阈值触发系统保护 |
并发线程数 | 当单台机器上所有入口流量的并发线程数达到阈值触发 |
入口QPS | 当单台机器的所有QPS达到阈值触发保护 |
九. Sentinel——服务熔断
处理基本的配置和前面讲的blockHandler是相同的,blockhandler能处理不符合规则的请求,但处理不了发生java其他的异常。那么此时就需要用到fallback属性,该属性是配置发生异常后的兜底方法。
@GetMapping("/fallback/{id}")
@SentinelResource(value = "fallback",fallback = "my_fallback",blockHandler = "my_handler")
public String hello(@PathVariable("id") Integer id){
if (id==4){
throw new IllegalArgumentException();
}
return “调用成功”;
}
public String my_fallback(Integer id){
return "fallback方法";
}
public String my_handler(Integer id, BlockException exception){
return "handler方法";
}
该处既配置了熔断方法又配置了blockHandler方法。若此时给该资源定义了热点规则,并且同时传入参数4,那么BlockException和IllegalArgumentException同时发生异常的情况下,会先调用my_handler方法,若符合定义的规则,那就只会调用my_fallback方法来处理IllegalArgumentException异常。
-
sentinel与OpenFeign的整合
修改application.yml配置文件:feign.sentinel.enabled=true
,若不加这一配置则无法配置OpenFeign的兜底方法。以下为OpenFeign的映射和兜底代码。@FeignClient(value = "nacos-sentinel-provider",fallback = FallBack.class) public interface BalanceService { @GetMapping(value = "/balance") String nacos_sentinel(); }
@Component public class FallBack implements BalanceService{ @Override public String nacos_sentinel() { return "这是feign的兜底方法"; } }
十. Sentinel——持久化配置
为什么要进行持久化的配置?
答:重启微服务后,相应的流控规则等都会消失,必须重新配置,那么就需要持久化配置,那么需要一个解决方案,将持久化规则保存起来,可以写入Nacos,也可写入数据库或者文件中。本文用到的是将持久化配置写入Nacos。
-
引入依赖
<dependency> <groupId>com.alibaba.csp</groupId> <artifactId>sentinel-datasource-nacos</artifactId> </dependency>
-
配置持久化
spring: application: name: nacos-sentinel-consumer cloud: nacos: discovery: server-addr: localhost:8848 sentinel: transport: dashboard: localhost:8080 port: 8719 datasource: # 配置sentinel持久化 ds1: nacos: server-addr: localhost:8848 dataId: nacos-sentinel-consumer groupId: DEFAULT_GROUP data-type: json rule-type: flow
-
sentinel中添加 json 配置文件
{ { "resource": "/balance", 监控的资源名称 "limitApp": "default", 来源应用 "grade": 1, 阈值类型,0为线程数,1为QPS "count": 1, 单机阈值 "strategy": 0, 流控模式, 0直接,1关联,2链路 "controlBehavior": 0, 流控效果:0快速失败,1warmup,2排队等待 "clusterMode": false 是否集群 } }
-
验证流控规则持久化
也是懒加载模式,当某个资源被调用后那么在Sentinel的监控后台就可以看到相应的规则。
十一. 下一篇介绍
对spring cloud alibaba seata介绍,针对的是微服务当中的分布式事务问题。