sentinel原理分析及源码剖析

sentinel功能

sentinel功能可参考官网
可以从sentinel的dashboard中了解到sentinel的核心功能包括

流控规则

  • 阈值类型:QPS、并发线程数
  • 流控模式:直接,关联,链路
  • 流控效果:快速失败(滑动时间窗算法DefaultController),Warm Up(令牌桶算法WarmUpController),排队等待(漏桶算法RateLimiterController)
    熔断规则

熔断规则

熔断策略分为3种:

  • 慢调用比例(ResponseTimeCircuitBreaker):设置相关资源在1秒内最大响应时间为100ms、比例阈值为0.5、最小请求数为5,熔断时长5s的规则。案例:测试接口睡眠100ms,1秒内发出10个请求。断路器的开关状态:初始状态为关闭,因为每个请求进来都会成为慢调用,所以比例阈值肯定超过0.5,当第5个请求进来以后,大于最小请求数,回调方法onRequestComplete()将断路器的状态从关闭状态设置为打开状态;当第6个请求进来以后,由于熔断时间为5s,所以会被限流直接调用handleBlockException处理方法。过了5s后,其他请求来了,那么断路器试探性的将开关从打开状态置为半开状态。当又有其他请求进来后,执行回调方法onRequestComplete()时,判断本次请求响应时间是否大于最大允许响应时间,是则将开关设置为打开状态,否则设置为关闭状态

  • 异常比例(ExceptionCircuitBreaker)

  • 异常数(ExceptionCircuitBreaker)

热点规则

何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:

  • 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
  • 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制

系统规则

  • LOAD(BBR algorithm) 系统负载,从操作系统复制
  • RT 平均响应时间,从滑动时间窗算法中统计
  • 线程数
  • 入口 QPS 滑动时间窗算法中统计
  • CPU 使用率 从操作系统得来

授权规则

  • 白名单
  • 黑名单

集群流控

原理

核心架构

  • 责任链模式
    sentinel核心架构就是围绕责任链的设计模式展开的,非常好理解。下图摘自官网,sentinel默认有8个插槽,他们分工明确,有各自的责任。

在这里插入图片描述

  • 源码流程

在这里插入图片描述

  • 限流算法

a 滑动事件窗
原理是将某段时间分为若干个时间段,通过控制每个时间段的请求数来进行限流,比如qps控制在100以内,可以将1秒分为5个200ms,当时间窗内所有请求数超过100个时其他请求将被限流。如图
在这里插入图片描述

伪代码:

public class SlidingTimeWindow {

    private Long counter = 0l;

    //时间窗
    private LinkedList<Long> list = new LinkedList<>();

    public static void main(String[] args) throws InterruptedException {
        SlidingTimeWindow timeWindow = new SlidingTimeWindow();
        new Thread(() -> {
            try {
                timeWindow.doCheck();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }).start();
        
        while (true) {
            timeWindow.counter++;
            Thread.sleep(new Random().nextInt(18));
        }

    }

    public void doCheck() throws InterruptedException {
        while (true) {
            list.addLast(counter);
            if (list.size() > 10) {
                list.removeFirst();
            }
            if (list.peekLast().longValue() - list.peekFirst().longValue() > 100) {
                System.out.println("限流了");
            } else {
                System.out.println("通过了");
            }
            Thread.sleep(100l);
        }
    }
}
b 漏桶

漏桶限流算法的原理,有一个装水的桶,不控制进水的速度,而是控制出水的速度,当桶满了以后还有进水则进行限流。
伪代码:

**
 * 漏桶算法:控制系统QPS为100
 * 1、系统的峰值表示桶的阈值:300,超过300直接拒绝
 * 210ms一个请求出去,桶的水滴数-1
 * 3*/
public class LeakyBucket2 {

    public long timeStamp = System.currentTimeMillis();  // 当前时间
    public long capacity = 150; // 桶的容量
    public long rate = 100; // 水漏出的速度(每秒系统能处理的请求数)
    public long water; // 当前水量(当前累积请求数)

    public static void main(String[] args) {
        LeakyBucket2 bucket = new LeakyBucket2();
        while (true) {
            bucket.limit();
            try {
                if (bucket.water >= bucket.capacity) {
                    Thread.sleep(1000l);
                } else {
                    Thread.sleep(50l);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public boolean limit() {
        long now = System.currentTimeMillis();
        //0.050 * 100=5
        water = Math.max(0, water - ((now - timeStamp) / 1000) * rate); // 先执行漏水,计算剩余水量
        timeStamp = now;
        if ((water + 1) < capacity) {
            // 尝试加水,并且水还未满
            water += 1;
            return true;
        } else {
            // 水满,拒绝加水
            System.out.println("限流");
            return false;
        }
    }
}
c 令牌桶

令牌桶限流算法是通过匀速向令牌桶里放入令牌,当令牌桶满了以后,令牌直接丢弃;当请求进来时先去令牌桶获取令牌,如果能获取到令牌则请求通过,否则限流。
伪代码:

public class TokenBucket2 {

    long start = System.currentTimeMillis();

    long tokens;  //token的数量

    long rate = 10;  //放入token的速率

    long capacity = 20;  //桶的容量

    public static void main(String[] args) {
        TokenBucket2 bucket = new TokenBucket2();
        while (true) {
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            bucket.check();
        }
    }

    public void check() {
        long now = System.currentTimeMillis();
        //先按一定速率加令牌,
        tokens = Math.min(capacity, tokens + (now - start)*rate);
        start = now;
        if (tokens < 1) {
            System.out.println("限流");
        } else {
            tokens =- 1;
            System.out.println("通过");
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值