Sentinel流量控制

前面我们完成了对Sentinel的搭建与连接,接着我们来看看Sentinel的第一个功能,流量控制。

我们的机器不可能无限制的接受和处理客户端的请求,如果不加以限制,当发生高并发情况时,系统资源将很快被耗尽。为了避免这种情况,我们就可以添加流量控制(也可以说是限流)当一段时间内的流量到达一定的阈值的时候,新的请求将不再进行处理,这样不仅可以合理地应对高并发请求,同时也能在一定程度上保护服务器不受到外界的恶意攻击。

那么要实现限流,正常情况下,我们该采取什么样的策略呢?

  • 方案一:快速拒绝,既然不再接受新的请求,那么我们可以直接返回一个拒绝信息,告诉用户访问频率过高。
  • 方案二:预热,依然基于方案一,但是由于某些情况下高并发请求是在某一时刻突然到来,我们可以缓慢地将阈值提高到指定阈值,形成一个缓冲保护。
  • 方案三:排队等待,不接受新的请求,但是也不直接拒绝,而是进队列先等一下,如果规定时间内能够执行,那么就执行,要是超时就算了。

针对于是否超过流量阈值的判断,这里我们提4种算法:

  1. 漏桶算法
    顾名思义,就像一个桶开了一个小孔,水流进桶中的速度肯定是远大于水流出桶的速度的,这也是最简单的一种限流思路:


    我们知道,桶是有容量的,所以当桶的容量已满时,就装不下水了,这时就只有丢弃请求了。
    利用这种思想,我们就可以写出一个简单的限流算法。
  1. 令牌桶算法
    只能说有点像信号量机制。现在有一个令牌桶,这个桶是专门存放令牌的,每隔一段时间就向桶中丢入一个令牌(速度由我们指定)当新的请求到达时,将从桶中删除令牌,接着请求就可以通过并给到服务,但是如果桶中的令牌数量不足,那么不会删除令牌,而是让此数据包等待。


    可以试想一下,当流量下降时,令牌桶中的令牌会逐渐积累,这样如果突然出现高并发,那么就能在短时间内拿到大量的令牌。
  1. 固定时间窗口算法
    我们可以对某一个时间段内的请求进行统计和计数,比如在14:1514:16这一分钟内,请求量不能超过100,也就是一分钟之内不能超过100次请求,那么就可以像下面这样进行划分:


    虽然这种模式看似比较合理,但是试想一下这种情况:
    • 14:15:59的时候来了100个请求
    • 14:16:01的时候又来了100个请求

出现上面这种情况,符合固定时间窗口算法的规则,所以这200个请求都能正常接受,但是,如果你反应比较快,应该发现了,我们其实希望的是60秒内只有100个请求,但是这种情况却是在3秒内出现了200个请求,很明显已经违背了我们的初衷。
因此,当遇到临界点时,固定时间窗口算法存在安全隐患。

  1. 滑动时间窗口算法
    相对于固定窗口算法,滑动时间窗口算法更加灵活,它会动态移动窗口,重新进行计算:


    虽然这样能够避免固定时间窗口的临界问题,但是这样显然是比固定窗口更加耗时的。

好了,了解完了我们的限流策略和判定方法之后,我们在Sentinel中进行实际测试一下,打开管理页面的簇点链路模块:

这里演示对我们的借阅接口进行限流,点击流控,会看到让我们添加流控规则:

  • 阈值类型:QPS就是每秒钟的请求数量,并发线程数是按服务当前使用的线程数据进行统计的。
  • 流控模式:当达到阈值时,流控的对象,这里暂时只用直接。
  • 流控效果:就是我们上面所说的三种方案。

这里我们选择QPS、阈值设定为1,流控模式选择直接、流控效果选择快速失败,可以看到,当我们快速地进行请求时,会直接返回失败信息:

这里各位最好自行尝试一下其他的流控效果,熟悉和加深印象。

最后我们来看看这些流控模式有什么区别:

  • 直接:只针对于当前接口。
  • 关联:当其他接口超过阈值时,会导致当前接口被限流。
  • 链路:更细粒度的限流,能精确到具体的方法。

我们首先来看看关联,比如现在我们对自带的/error接口进行限流:

注意限流是作用于关联资源的,一旦发现关联资源超过阈值,那么就会对当前的资源进行限流,我们现在来测试一下,这里使用PostMan的Runner连续对关联资源发起请求:

开启Postman,然后我们会发现借阅服务已经凉凉:

当我们关闭掉Postman的任务后,恢复正常。

最后我们来讲解一下链路模式,它能够更加精准的进行流量控制,链路流控模式指的是,当从指定接口过来的资源请求达到限流条件时,开启限流,这里得先讲解一下@SentinelResource的使用。

我们可以对某一个方法进行限流控制,无论是谁在何处调用了它,这里需要使用到@SentinelResource,一旦方法被标注,那么就会进行监控,比如我们这里创建两个请求映射,都来调用Service的被监控方法:

@RestController
public class BorrowController {

    @Resource
    BorrowService service;

    @RequestMapping("/borrow/{uid}")
    UserBorrowDetail findUserBorrows(@PathVariable("uid") int uid){
        return service.getUserBorrowDetailByUid(uid);
    }

    @RequestMapping("/borrow2/{uid}")
    UserBorrowDetail findUserBorrows2(@PathVariable("uid") int uid){
        return service.getUserBorrowDetailByUid(uid);
    }
}

@Service
public class BorrowServiceImpl implements BorrowService{

    @Resource
    BorrowMapper mapper;

    @Resource
    UserClient userClient;

    @Resource
    BookClient bookClient;

    @Override
    @SentinelResource("getBorrow")   //监控此方法,无论被谁执行都在监控范围内,这里给的value是自定义名称,这个注解可以加在任何方法上,包括Controller中的请求映射方法,跟HystrixCommand贼像
    public UserBorrowDetail getUserBorrowDetailByUid(int uid) {
        List<Borrow> borrow = mapper.getBorrowsByUid(uid);
        User user = userClient.getUserById(uid);
        List<Book> bookList = borrow
                .stream()
                .map(b -> bookClient.getBookById(b.getBid()))
                .collect(Collectors.toList());
        return new UserBorrowDetail(user, bookList);
    }
}

接着添加配置:

spring:
  application:
    name: borrowservice
  cloud:
    sentinel:
      transport:
        dashboard: localhost:8858
      # 关闭Context收敛,这样被监控方法可以进行不同链路的单独控制
      web-context-unify: false

然后我们在Sentinel控制台中添加流控规则,注意是针对此方法,可以看到已经自动识别到borrow接口下调用了这个方法:

最后我们在浏览器中对这两个接口都进行测试,会发现,无论请求哪个接口,只要调用了Service中的getUserBorrowDetailByUid这个方法,都会被限流。注意限流的形式是后台直接抛出异常,至于怎么处理我们后面再说。

那么这个链路选项实际上就是决定只限流从哪个方向来的调用,比如我们只对borrow2这个接口对getUserBorrowDetailByUid方法的调用进行限流,那么我们就可以为其指定链路:

然后我们会发现,限流效果只对我们配置的链路接口有效,而其他链路是不会被限流的。

除了直接对接口进行限流规则控制之外,我们也可以根据当前系统的资源使用情况,决定是否进行限流:

系统规则支持以下的模式:

  • 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 达到阈值即触发系统保护。

这里就不进行演示了。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值