手把手教你搭建SpringCloudAlibaba之Sentinel实现流量控制

SpringCloud Alibaba全集文章目录:

零、手把手教你搭建SpringCloudAlibaba项目

一、手把手教你搭建SpringCloud Alibaba之生产者与消费者

二、手把手教你搭建SpringCloudAlibaba之Nacos服务注册中心

三、手把手教你搭建SpringCloudAlibaba之Nacos服务配置中心

四、手把手教你搭建SpringCloudAlibaba之Nacos服务集群配置

五、手把手教你搭建SpringCloudAlibaba之Nacos服务持久化配置

六、手把手教你搭建SpringCloudAlibaba之Sentinel实现流量实时监控

七、手把手教你搭建SpringCloudAlibaba之Sentinel实现流量控制

八、手把手教你搭建SpringCloudAlibaba之Sentinel服务熔断降级

九、手把手教你搭建SpringCloudAlibaba之Sentinel热点key限流

十、手把手教你搭建SpringCloudAlibaba之Sentinel系统自适应保护

十一、手把手教你搭建SpringCloudAlibaba之Sentinel注解SentinelResource

十二、手把手教你搭建SpringCloudAlibaba之Sentinel规则持久化

十三、手把手教你搭建SpringCloudAlibaba之Seata分布式事务

点击跳转学习 -------------->手把手教你搭建SpringCloud项目

流量控制就是限制系统的输入和输出流量已达到保护系统的目的。为了保证系统的稳固运行,一旦达到需要限制的阈值,就需要限制流量并采取少量措施以完成限制流量的目的。

我们访问的接口http://localhost:8401/testA和http://localhost:8401/testB,在sentinel的控制台就可以看到的簇点链路菜单,如下所示。
 

 我们点击接口testA接口的流控按钮,可以看到如下的界面:

1、流量控制的几种模式

资源名

唯一名称,默认是请求路径,可自定义,Sentinel默认只标记Controller中的方法为资源,如果要标记其它方法,需要利用@SentinelResource注解。

针对来源

指定对哪个微服务进行限流,默认指default,意思是不区分来源,全部限制

阈值类型/单机阈值

QPS(每秒请求数量):

当调用该接口的QPS达到阈值的时候,进行限流

线程数:

当调用该接口的线程数达到阈值的时候,进行限流

是否集群:

暂不需要集群

流控模式

直接(默认)

接口达到限流条件时,开启限流

关联

当关联的资源达到限流条件时,开启限流

链路

当从某个接口过来的资源达到限流条件时,开启限流

流控效果

快速失败(默认):

直接失败,抛出异常,不做任何额外的处理,是最简单的效果

Warm Up:

它从开始阈值到最大QPS阈值会有一个缓冲阶段,一开始的阈值是最大QPS阈值的 1/3,然后慢慢增长,直到最大阈值,适用于将突然增大的流量转换为缓步增长的场景。

排队等待:

让请求以均匀的速度通过,单机阈值为每秒通过数量,其余的排队等待; 它还会让设 置一个超时时间,当请求超过超时间时间还未处理,则会被丢弃

2、直接模式

我们先演示流控模式为直接的,也是默认的模式。可以看到阈值的类型分为QPS和线程数两种,我们先设置一下QPS类型的,单机阈值直接填写1。新增完毕后我们就可以看到控制台流量规则的菜单里看到我们新增的那条流控规则,如下图:

我们访问接口testA接口,当前的QPS为1,每秒访问1次。如果每秒访问的次数超过1次,则会被Sentinel限流。看下我们刚刚设置的是否会成功。可以看到成功限流了。

那接下来我们设置下阈值的类型分为线程数的这种类型,单机阈值为1,就是每秒需要只允许一个线程访问,否则则会被Sentinel限流。看下我们刚刚设置的是否会成功。

 这个可以用Jmeter软件来协助我们测试。

3、关联模式

我们把之前配置的流控规则都删掉,我们重新配置关联流控模式testA接口关联testB接口,流控效果为快速失败,意思就是当我们指定的testA接口关联的testB接口达到限流条件时,开启对指定接口testA开启限流(就是B惹事,A来处理)。

我们狂点testB接口,超过每秒1次,然后接着访问testA接口,可以看到已经限流了,如下图:

4、链路模式

根据调用链路入口限流。是对链路之间树结构进行流控,各个资源之间进行相互调用,这些资源通过调用关系,相互之间构成一颗树。这课树的根节点是一个名为getUser的虚拟节点,调用链路的入口都是这个虚节点的子子节点。如下图:

 上图中来自入口的testA和testB的请求都调用了资源getUser,Sentinel允许只根据某个入口的统计信息对资源进行限流。

不但可以对接口进行流控,还可以对业务方法进行限流。我们新建getUser的方法,如下图:

@Service
public class UserServiceImpl implements UserService {
    @Override
    @SentinelResource(value = "getUserName")
    public String getUserName() {
        return "一直tom猫";
    }
}

分别将接口testA和testB接口调用getUser方法,代码如下:

@RestController
public class FlowLimitController {
    @Autowired
    private UserService userService;
    @GetMapping("/testA")
    public String testA() {

        return userService.getUserName();
    }

    @GetMapping("/testB")
    public String testB() {

        return userService.getUserName();
    }
}

重新方法接口testA和testB接口,可以看到业务方法getUser也注入到了sentinel当中,如下图:

 可以看到我们的资源getUserName,我们针对进行链路限流,入口资源我们限制testA,如下图。

我们的链路模式就建好了,记得把之前限流配置删掉,如下图:

我们访问testA接口发现不生效,并没有限流,如下图:

这是为什么呢?

因为我们sentinel的版本较高,直接使用链路模式是不生效的,那该如何解决呢?

 

我们需要在pom.xml中增加sentinel-web-servlet的依赖,如下图:

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-web-servlet</artifactId>
</dependency>

在项目中添加一个FilterContextConfig配置类,代码如下:

@Configuration
public class FilterContextConfig {
    @Bean
    public FilterRegistrationBean sentinelFilterRegistration() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        registrationBean.setFilter(new CommonFilter());
        registrationBean.addUrlPatterns("/*");
        registrationBean.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY,"false");
        registrationBean.setName("sentinelFilter");
        registrationBean.setOrder(1);
        return  registrationBean;
    }
}

重启项目,我们再次访问testA和testB接口,在看seninel的控制台,如下图:

可以发现现在的控制台的接口层级关系和之前不成功的时候层级关系是不一样的,可以看到现在可以看到正确的链路。接下来对testA接口中的getUser方法进行限流,配置如下:

访问接口testA,每秒没疯狂点击会出现如下的错误;

 访问接口testB,每秒没疯狂点击可以正确访问,如下图:

 出现如上的错误是因为我们使用了@SentinelResource,注解,使用了该注解就不会使用我们设置的全局的使用统一的异常错误处理里,就需要@SentinelResource注解当中的blockHandler参数进行单独的处理,需要写一个流控处理的方法,代码如下:

@Service
public class UserServiceImpl implements UserService {
    @Override
    @SentinelResource(value = "getUserName",blockHandler = "blockHandlerGetUser")
    public String getUserName() {
        return "一直tom猫";
    }

    public String blockHandlerGetUser() {
        return "请稍后再试";
    }
}

重启项目,再次访问testA接口,会出现我们自定义的处理限流的方法,如下图:

5、流控效果

流控效果一共分为三种:

直接失败:

是默认的流量控制模式,当QPS超过任意规则的阈值后,新请求就会被立即拒绝,拒绝的方式是抛出FlowException。这种方式适用于读系统处理能力确切已知的情况下,比如通压测确定了系统的准确水位时。其源码为:com.alibaba.csp.sentinel.slots.block.flow.controller.DefaultController

Warm Up(预热)

Warm Up方式,即预热/冷启方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过“冷启动”,让通过的流量缓慢增加,在一定时间内逐渐上限,给冷系统一个预热的时间,避免冷系统被压垮。

冷加载因子:codeFactor默认3,即请求PQS从threshold/3开始,经预热时长逐渐升至设定QPS阈值。

我们以接口testA来演示一下预热模式,我们的阈值设置为10,预热时长为5,根据冷加载因子计算,系统的初始化的阈值为10/3约等于3,即阈值刚开始为3,然后通过5秒后阈值才慢慢升高恢复到10。

适用场景:电商系统中的秒杀活动,在秒杀系统的开始的瞬间,会有很多流量上来,很有可能把系统打死,预热方式就是为了保护系统,可慢慢的把流量放进来,慢慢的把阈值增长到设置的阈值。

排队等待

匀速排队方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,阈值类型必须设置为QPS,否则无效。对应的是漏铜算法。

适合处理间隔性突发的流量,例如消息队列。想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求。

我们以接口testB来演示一下排队等待模式,QPS的阈值设置为1,超时时间为20000毫秒,我们进行访问可以看到每秒通过一次请求,也不会把系统压垮。如下图:

 至此sentinel流量控制就学完了。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值