1. 基本介绍

- 资源名:唯一名称,默认请求路径。
- 针对来源:Sentinel可以针对调用者进行限流,填写微服务名,默认default(不区分来源)。
- 阈值类型/单机阈值:
- QPS(每秒钟的请求数量)︰当调用该API的QPS达到阈值的时候,进行限流。
- 线程数:当调用该API的线程数达到阈值的时候,进行限流。
- 是否集群:不需要集群。
- 流控模式:
- 直接:API达到限流条件时,直接限流。
- 关联:当关联的资源达到阈值时,就限流自己。
- 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)【API级别的针对来源】。
- 流控效果:
- 快速失败:直接失败,抛异常。
- Warm up:根据Code Factor(冷加载因子,默认3)的值,从阈值/codeFactor,经过预热时长,才达到设置的QPS阈值。
- 排队等待:匀速排队,让请求以匀速的速度通过,阈值类型必须设置为QPS,否则无效。
2. 流控模式
2.1 直接(默认)
直接 -> 快速失败(系统默认)
(1)配置及说明
QPS:表示1秒钟内查询1次就是OK,若超过次数1,就直接->快速失败,报默认错误
线程数:当调用该API的线程数达到阈值的时候,进行限流。
(2)测试
快速多次点击访问http://localhost:8401/testA
(3)结果
返回页面 Blocked by Sentinel (flow limiting)
(4)源码
com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController
(5)思考
直接调用默认报错信息,技术方面OK,但是,是否应该有我们自己的后续处理?类似有个fallback的兜底方法?
2.2 关联
(1)是什么
- 当自己关联的资源达到阈值时,就限流自己
- 当与A关联的资源B达到阀值后,就限流A自己(B惹事,A挂了)
(2)配置A
当关联资源/testB的QPS阀值超过1时,就限流/testA的Rest访问地址,当关联资源到阈值后限制配置好的资源名。
(3)Postman模拟并发密集访问testB

Run - 大批量线程高并发访问http://localhost:8401/testB
Postman运行后,点击访问http://localhost:8401/testA,发现testA挂了
只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)【API级别的针对来源】
NodeSelectorSlot 中记录了资源之间的调用链路,这些资源通过调用关系,相互之间构成一棵调用树。这棵树的根节点是一个名字为 machine-root 的虚拟节点,调用链的入口都是这个虚节点的子节点。
一棵典型的调用树如下图所示:
machine-root/ \/ \Entrance1 Entrance2/ \/ \DefaultNode(nodeA) DefaultNode(nodeA)
上图中来自入口 Entrance1 和 Entrance2 的请求都调用到了资源 NodeA,Sentinel 允许只根据某个入口的统计信息对资源限流。比如我们可以设置 strategy 为 RuleConstant.STRATEGY_CHAIN,同时设置 refResource 为 Entrance1 来表示只有从入口 Entrance1 的调用才会记录到 NodeA 的限流统计当中,而不关心经 Entrance2 到来的调用。
调用链的入口(上下文)是通过 API 方法 ContextUtil.enter(contextName) 定义的,其中 contextName 即对应调用链路入口名称。详情可以参考 ContextUtil 文档。
相关博客https://blog.csdn.net/qq_42362240/article/details/105861463
(1)业务类
package com.atguigu.speingcloud.service;
import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.stereotype.Service;
@Service
public class SentinelSerice {
//@SentinelResource(value = "testA")
public String testLianLu(){
return "链路";
}
}
package com.atguigu.speingcloud.controller;
import com.atguigu.speingcloud.service.SentinelSerice;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@Slf4j
public class FlowLimitController {
@Autowired
private SentinelSerice serice;
@GetMapping("/testA")
public String testA()
{
return serice.testLianLu() + "------testA";
}
@GetMapping("/testB")
public String testB()
{
log.info(Thread.currentThread().getName()+"\t"+"...testB");
return serice.testLianLu() + "------testB";
}
}
(2)新增流控规则
当前链路关系
新增规则
资源/testB的入口资源为sentinel_web_servlet_context
(3)测试
http://localhost:8401/testB请求超过阈值会报错
http://localhost:8401/testA则没影响
(4)结论
新增的流控规则入口资源配置为sentinel_web_servlet_context,意思为对从sentinel_web_servlet_context入口进来的调用到资源/testB的请求做限制,调用/testA则没影响
需要加@SentinelResource注解,资源才可生效,去除该注解后,流控规则失效(暂时不管,改代码了)
3. 流控效果
3.1 直接
直接->快速失败(默认的流控处理)
Blocked by Sentinel (flow limiting)
3.2 预热 Warm Up
Warm Up(RuleConstant.CONTROL_BEHAVIOR_WARM_UP)方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过”冷启动”,让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。详细文档可以参考 流量控制 - Warm Up 文档,具体的例子可以参见 WarmUpFlowDemo。
(1)公式
默认coldFactor为3,即请求QPS 从 threshold / 3开始,经预热时长逐渐升至设定的QPS阈值。
(2)源码
com.alibaba.csp.sentinel.slots.block.flow.controller.WarmUpController
(3)WarmUp配置
**
案例,阀值为10+预热时长设置5秒。
系统初始化的阀值为10/ 3约等于3,即阀值刚开始为3;然后过了5秒后阀值才慢慢升高恢复到10
(4)测试
多次快速点击http://localhost:8401/testB - 刚开始(前五秒)不行,后续慢慢OK
(5)应用场景
**
如:秒杀系统在开启的瞬间,会有很多流量上来,很有可能把系统打死,预热方式就是把为了保护系统,可慢慢的把流量放进来,慢慢的把阀值增长到设置的阀值。
3.3 排队等待
匀速排队(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。详细文档可以参考 流量控制 - 匀速器模式,具体的例子可以参见 PaceFlowDemo。
该方式的作用如下图所示:
这种方式主要用于处理间隔性突发的流量,例如消息队列。想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求。
注意:匀速排队模式暂时不支持 QPS > 1000 的场景。
(1)设置:
/testA每秒1次请求,超过的话就排队等待,等待的超时时间为20000毫秒。
(2)源码 -
com.alibaba.csp.sentinel.slots.block.flow.controller.RateLimiterController
(3)测试
添加日志记录代码到FlowLimitController的testA方法
@RestController
@Slf4j
public class FlowLimitController {
@GetMapping("/testA")
public String testA()
{
log.info(Thread.currentThread().getName()+"\t"+"...testA");//<----
return "------testA";
}
...
}
- Postman模拟并发密集访问testA。

- 后台结果

