热点key限流 / 系统规则(系统自适应限流)/ @SentinelResource 注解详解 / 服务熔断 / 持久化规则
1.热点key限流
官方文档:https://github.com/alibaba/Sentinel/wiki/%E7%83%AD%E7%82%B9%E5%8F%82%E6%95%B0%E9%99%90%E6%B5%81
热点参数限制会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限制。热点参数限流可以看作是一种特殊的流量控制,仅对包含热点参数的资源调用生效。
- 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
- 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制

1.1基本使用
兜底防范分为系统默认和客户自定义:
- sentinel系统默认的提示:Blocked by Sentinel (flow limiting)。
- 类似于@HystrixCommand, 引入@SentinelResource注解。

资源名:唯一路径,默认为请求路径。此处必须是 @SentinelResource 注解的 value 属性值,配置@GetMapping 的请求路径无效)
1.1.1测试方法
在8401的controller中,加入热点测试方法。
@SentinelResource注解分析
- 其中 value = “testHotKey” 是一个标识(Sentinel资源名),与rest的`/testHotKey`对应,这里value的值可以任意写,但是我们约定与rest地址一致,唯一区别是没有`/`。
- blockHandler = “del_testHotKey” 则表示如果违背了Sentinel中配置的流控规则,就会调用我们自己的兜底方法del_testHotKey
1.1.2配置热点key限流规则
方法testHotKey里面第一个参数只要QPS超过每秒1次,马上降级处理

1.1.3 测试
- 1次/s正常显示,迅速点击两次,触发热点限流,执行自定义兜底方法:http://127.0.0.1:8401/testHotKey?p1=a
- 仅传入参数p2没有任何影响: http://localhost:8401/testHotKey?p2=b
- 个通过jmeter压测http://localhost:8401/testHotKey?p1=a&p2=b,另外再单独使用浏览器访问http://localhost:8401/testHotKey?p2=b,发现只带参数p2访问没有任何影响。
参数例外项
期望p1参数当它是某个特殊值时,它的限流值和平时不一样,比如当p1的值等于5时,它的阈值可以达到200。

狂点http://localhost:8401/testHotKey?p1=5&p2=b 没有限流
其他
手动添加一个异常:

测试直接错误页面。
Sentinel它只管你有没有触发它的限流规则,也可以说只管这个web交互页面(控制台)里面的东西。 配置类的东西Sentinel可以管,java异常的错误Sentinel不管。
总结:
@SentinelResource主管配置出错,运行出错该走异常走异常
2.系统规则(系统自适应限流)

Sentinel 系统自适应限流从整体维度对应用入口流量进行控制,(让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。)
- Load 自适应(仅对 Linux/Unix-like 机器生效):系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的 maxQps * minRt 估算得出。设定参考值一般是 CPU cores * 2.5。
- CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。
- 平均 RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
- 并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
- 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。
如把入口QPS设置为1,不管是/testA还是/testB 只要QPS > 1 整个系统就不能用。
3.@SentinelResource 注解详解
3.1按资源名称限流+后续处理
3.1.1 修改8401
(1) pom
引入我们自定义的公共api jar包
(2) 业务类
RateLimitController
3.1.2 配置流控规则——按资源名称添加流控规则

3.1.3测试
自测:

触发流控规则:

3.1.4 问题
如果我们重启8401会发现之前配置的一些规则都没有了。难道每次重启服务器都要重新配置一遍规则吗?规则如何进行持久化?
8.2 按照Url地址限流+后续处理
通过访问的URL来限流,会返回Sentinel自带默认的限流处理信息
修改业务层
按rest URI设置流控规则后,触发流控规则:

3.3 总结以及面临的问题
- 依照现有条件,我们自定义的处理方法又和业务代码耦合在一块,不直观。如果都用系统默认的,就没有体现我们自己的业务要求。
- 如果每个业务方法/API接口都添加一个兜底的,那代码膨胀加剧。
- 全局统一的处理方法没有体现。
3.4 客户自定义限流处理逻辑
为了解决代码耦合与膨胀的问题
3.4.1创建CustomerBlockHandler类用于自定义限流处理逻辑(单独放在一个包里)
3.4.2 修改RateLimitController,使用自定义处理逻辑类

3.4.3 测试
设置流控,触发流控后:

3.5 更多属性说明
文档:https://github.com/alibaba/Sentinel/wiki/%E6%B3%A8%E8%A7%A3%E6%94%AF%E6%8C%81

4.服务熔断
主要内容:
- sentinel分别整合ribbon+openFeign以及设置fallback
- 熔断框架比较
4.1 Ribbon系列
nacos中整合了Ribbon,所以直接使用nacos就行。启动nacos和Sentinel。
fallback和blockHandler
fallback管运行异常,blockHandler管配置违规。
fallback对应服务降级,就是服务出错了应该怎么办(需要有个兜底方法);
blockHandler对应服务熔断,就是我现在服务不可用,我应该怎么办,怎么给客户一个户提示(同样需要一个兜底方法)

同时配置fallback:处理业务异常(微服务自身异常,服务降级)和blockHandler:处理触发sentinel配置(微服务不可用,服务熔断)时。在没有违反sentinel规则时,出现业务异常(降级)走fallback方法;违反了sentinel规则时,直接微服务不可用(熔断),走blockHandler指定的自定义方法。
也就是说 有java异常的同时,也违反sentinel规则,此时会走blockHandler(熔断)
异常忽略属性

即出现指定的异常,不执行兜底方法,而是直接返回错误页面!
当然,触发流控之后,仍然通过blockHandler指定的方法进行熔断兜底。
Feign系列
修改消费者模块
(1) pom
加入feign的依赖
(2) yml
激活Sentinel对Feign的支持
(3) 业务类
后续84的controller不找restTemplate(Ribbon),不是restTemplate去调用payment微服务中的接口。而是通过调用PaymentFeignService,service再去调用payment微服务中的端口。
Feign需要定义一个业务逻辑(service)接口+ @FeignClient注解以调用服务提供者。
新建PaymentFeignService interface:
PaymentFeignService
调用失败的兜底方法:PaymentFallbackService
controller加入openFeign的接口:
(4) 主启动类
加上@EnableFeignClient注解开启OpenFeign
(5) 测试

熔断框架比较

5.持久化规则
前面我们微服务新增的限流规则后,微服务关闭后就会丢失,当时配置都限流规则都是临时的。
案例——修改8401已完成持久化设置
(1) pom.
导入持久化所需依赖
(2) yaml
application.yaml
(3) 添加nacos业务规则配置
我们将sentinel的流控配置保存在nacos中,因为nacos的配置持久化在了数据库中。

resource:资源名称;
limitApp:来源应用;
grade:阈值类型,0表示线程数,1表示QPS;
count:单机阈值;
strategy:流控模式,0表示直接,1表示关联,2表示链路;
controlBehavior:流控效果,0表示快速失败,1表示Warm Up,2表示排队等待;
clusterMode:是否集群。
注意:这里如果要配nacos的命名空间(public、dev、test)的话,应该是配namespace的id,不是名称
(4) 测试
启动8401,访问8401任意接口,刷新Sentinel。可以看到Sentinel中加载了通过nacos持久化的规则配置文件
关掉8401后发现流控规则没有了
再次启动8401查看sentinel,访问几次8401后流控规则又出现了。
查看数据库,发现规则持久化到数据库中了。