计数器算法: 指定周期内限制最大值,到达下个周期时从0开始计数。 缺陷:临界值问题00:01:59和00:02:01分别出现最大值的流量,导致这2s内总流量达到最大值流量的2倍 滑动窗口算法(Sentinel采用此算法): 滑动窗口的大小为若干个小时间窗的和,每个小时间窗可限x个请求, 滑动窗口随着时间移动,滑动时间窗口的流量等于其包含的完整小时间窗中的流量和 令牌桶限流算法: 系统以恒定的速率生产令牌放到令牌桶中,若桶已满则不放,可应对突发流量 每个请求处理前都需要从令牌桶中获取令牌,若获取不到则触发限流策略 漏桶限流算法: 系统维护一个固定大小的容器,同时以固定速率漏水 每次请求时先看当前桶中的水满没满(当前水量=上次更新后的水量-时间跨度*漏水速率),满了就限流,没满就正常处理 https://baijiahao.baidu.com/s?id=1666902623332115966&wfr=spider&for=pc
Sentinel三种熔断策略: 1. 平均响应时长:1s内累计有5个请求的平均响应时长超过阈值,触发熔断,在接下来的熔断时间窗内的请求直接降级 2. 异常比例:1s内请求数>=5,且1s内异常请求数占总请求数的比例超过阈值,触发熔断,在接下来的熔断时间窗内的请求直接降级 3. 异常数:1min内异常请求数超过阈值,触发熔断,在接下来的熔断时间窗内的请求直接降级
流控的两种类型:QPS和线程数,QPS是资源每秒查询数,线程数是资源占用的线程上限,防止线程耗尽服务雪崩 P180
Sentinel Dashboard中配置的流控规则是存储于内存中的,Dashboard服务重启后规则全部丢失,需要集成动态数据源提供规则持久化功能
Sentinel集成Nacos作为数据源,实现动态流控:P190
1. 在服务的application.yml文件中配置服务名、dashboard服务地址、数据源地址及指定配置的data-id、group-id、data-type、rule-type(流控、降级、热点、授权 P188)
2. 登录Nacos Console,根据1中指定的配置参数创建配置,在配置内容中配置7项规则条件,即完成Sentinel规则的创建
{ "resource": "/dynamic", #资源名 "limitApp": "default", #针对来源 "grade": 1, #阈值类型 1-QPS 0-线程数 "count": 1, #单机阈值 "strategy": 0, "controlBehavior": 0, "clusterMode": false #是否集群 }
3. 登录Sentinel Dashboard,2中创建的规则已自动加载
Sentinel集成Nacos作为数据源,在Nacos中修改流控规则后,Dashboard从Nacos中读取到的规则就是最新的
Sentinel Dashboard中修改流控规则后,Dashboard不支持自动同步到Nacos做持久化更新
Nacos作为配置中心,并没有Dashboard提供修改规则专用的UI界面,如果使用Nacos修改规则容易出错
Dashboard进行规则的CRUD时,后台都是通过FlowControllerV1这个类进行处理
还有一个FlowControllerV2类,有两个功能:
1. DynamicRuleProvider:负责从数据源中拉取配置规则,在Dashboard中展示
2. DynamicRulePublisher:负责将Dashboard中修改的规则推送给数据源,最持久化更新存储
修改Sentinel Dashboard源码,支持Dashboard-Nacos同步,步骤:
1. 下载Sentinel Dashboard源码
2. 创建FlowControllerV2中DynamicRuleProvider接口的实现类,重写getRules方法从Nacos中获取配置规则
3. 创建FlowControllerV2中DynamicRulePublisher接口的实现类,重写publish方法,建立与Nacos的HTTP连接,将规则Post给它
4. 在FlowControllerV2类注入DynamicRuleProvider和DynamicRulePublisher接口的上面,用@Qualifier指定2、3中的实现类名(首字母小写)
5. 修改Dashboard的pom.xml中配置、一个html中将V1去掉
6. 打jar包启动Dashboard
Sentinel处理链
Slot链,责任链模式,比如LogSlot (日志处理槽) -> StatisticSlot (统计槽) -> ParamFlowSlot (根据统计槽的数据进行热点参数规则校验) ->
FlowSlot (根据统计槽的数据进行流控规则校验) -> DegradeSlot (根据统计槽的数据进行降级规则校验)等
实时指标统计流程(StatisticSlot-StatisticNode实现统计)
底层根据LongAdder.add()这种CAS操作进行累计请求通过数、线程数
滑动计数器ArrayMetric,当进行累计时,先获取当前时间窗口,再做累计
ArrayMetric中通过LeapArray来存储数据,是环形数据结构,只存储最近固定个数的时间窗口,过期的窗口内存会被覆盖
LeapArray中获取当前时间窗对象的流程:
先根据当前时间换算得到当前时间窗的下标,然后获取对应时间窗统计对象WindowWrap,这时有三种情况:
1. 时间窗不存在,新建时间窗,并用CAS操作(只一次,不循环)添加到存储所有窗口的AtomicReferenceArray<WindowWrap<T>>原子数组的对应下标位置中
1.1 若CAS成功,返回新建的时间窗
1.2 若CAS失败,说明有其他线程在同时向原子数组的对应下标位置放新窗口,
调用Thread.yeild()释放CPU占用,接着会进while继续判断,这时候一般就进入2.1的情况了
2. 时间窗存在,然后判断这个时间窗的开始时间 与 当前时间换算得到的时间窗开始时间 是否相同
2.1 若相同直接返回此时间窗
2.2 若不相同证明时间窗已过期,使用ReentrantLock.tryLock()只尝试加一下锁,
若拿到锁就重置窗口,若没拿到调用Thread.yeild()释放CPU占用,接着会进while继续判断,这时候一般就进入2.1的情况了
热点限流(ParamFlowSlot)
场景:防止网络爬虫和恶意攻击,限制客户端IP,客户端IP地址就是一种热点参数;
高并发修改数据库同一行,mysql需要加行锁,这行数据也是一种热点参数
原理:滑动窗口算法+LRU策略(最近最少使用)实现热点参数的统计,LRU策略统计单位时间内最常访问的热点数据,滑动窗口统计每个参数的QPS
流量控制(FlowSlot)
一个接口可以配置多个限流规则,有三种情况 P215:
1. 不区分流量来源,对所有调用此接口的应用做整体限流
2. 可针对同一个接口配置多个限流规则,每个规则配置不同的来源,可保证某些关键流量来源服务的并发量
3. 配一个总体限流规则,在针对某个来源配置一个单独的限流规则,配合使用
服务降级(DegradeSlot)
1. 请求达到DegradeSlot槽进行处理
2. 先根据请求资源获取资源所有已配置的降级规则Set集合
3. 对Set遍历,逐个进行降级校验,根据规则降级类型(平均响应时间、失败率、失败数),从StatisticNode中获取需要的统计数据进行计算并判断