深入浅出限流之Sentinel

1、背景
在系统/服务的实例数一定的前提下,系统/服务的处理能力是有限的,但是用户的流量具备随机性,在一天的任意一段时间内都随时可能会发生激增流量,且该流量远远超过了系统能够负载的流量,在这种情况下如果我们Do Nothing,则带来的后果就是系统/服务宕机,而且你不断重启或者增加机器扩容对这种情况可能都无效,此时就需要对流量进行整形,进行限流,让系统/服务负载在一定合理范围内。

2、常见的限流算法
2.1 漏桶算法

当有请求到来时先放到木桶中,处理请求的worker以固定的速度从木桶中取出请求进行相应。如果木桶已经满了,直接返回请求频率超限的错误码或者页面。
在这里插入图片描述
适用场景:漏桶算法是流量均匀的限流实现方式,一般用于流量“整形”

问题:面对突发流量时会有大量请求失败,无法处理突发流量,不适合电商抢购和微博出现热点事件等场景的限流。

2.2 令牌桶算法
令牌桶是反向的"漏桶",它是以恒定的速度往木桶里加入令牌,木桶满了则不再加入令牌。服务收到请求时尝试从木桶中取出一个令牌,如果能够得到令牌则继续执行后续的业务逻辑。如果没有得到令牌,直接返回访问频率超限的错误码或页面等,不继续执行后续的业务逻辑。

在这里插入图片描述
适合电商抢购或者微博出现热点事件这种场景,因为在限流的同时可以应对一定的突发流量

2.3 计数器(固定窗口)
使用计数器在周期内累加访问次数,当达到设定的限流值时,触发限流策略。下一个周期开始时,进行清零,重新计数。

固定窗口算法简单粗暴
设置一个时间段,例如1s
设置一个限流QPS,例如100
意思就是每秒只允许100个请求通过
如果一秒内请求数量不到100,每请求一次,总数+1,不限量
如果一秒内请求数量达到100,限流
等到1s结束后,把计数恢复成0,重新开始计数

这种算法最大的问题就是会出现临界问题,例如在0:59的时候接收到100个请求,在1:01的时候又接收到100个请求,因为是在两个不同的1s时间段,所以都不会被限流,但是在连续的1s内却接收到200个请求,可能会拖垮服务。
2.4 滑动窗口算法
滑动窗口算法是在给定特定窗口大小的数组或字符串上执行要求的操作。
在这里插入图片描述
可以用来解决一些查找满足一定条件的连续区间的性质(长度等)的问题。由于区间连续,因此当区间发生变化时,可以通过旧有的计算结果对搜索空间进行剪枝,这样便减少了重复计算,降低了时间复杂度。往往类似于“ 请找到满足 xx 的最 x 的区间(子串、子数组)的 xx ”这类问题都可以使用该方法进行解决。
需要注意的是,滑动窗口算法更多的是一种思想,而非某种数据结构的使用。
3、常见限流框架
3.1 Java Semaphore(并发数限流,Sentinel线程数限流基于此思想实现)


    /**
     * 初始化10个信号量  最大并发数10
     */
    private static final Semaphore SEMAPHORE = new Semaphore(10);


    public <T> T executeWithSemaphore(Supplier<T> supplier) {
        boolean acquire = false;
        try {
            acquire = SEMAPHORE.tryAcquire();
            if (acquire){
                return supplier.get();
            }else {
                throw new RuntimeException("请求过于频繁");
            }
        } finally {
            if (acquire){
                SEMAPHORE.release();
            }
        }
    }

}

3.2 Guava RateLimiter(基于令牌桶算法实现)

public static void main(String[] args) throws InterruptedException {
    //每1s产生0.5个令牌,也就是说该接口2s只允许调用1次
    RateLimiter rateLimiter = RateLimiter.create(0.5, 1, TimeUnit.SECONDS);
    ExecutorService executor = Executors.newFixedThreadPool(100);
    for (int i = 0; i < 10; i++) {
        executor.execute(new Runnable() {
            @Override
            public void run() {
                //获取令牌桶中一个令牌,最多等待10秒
                if (rateLimiter.tryAcquire(1, 10, TimeUnit.SECONDS)) {
                    System.out.println(Thread.currentThread().getName() + " " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
                } else {
                    System.out.println("请求频繁");
                }
            }
        });
    }
    executor.shutdown();
}

}

4、Sentinel
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何代码段,例如,由应用程序提供的服务,或由应用程序调用的其它应用提供的服务,甚至可以是一段代码。
4.1资源
只要通过 Sentinel API 定义的代码,就是资源,能够被 Sentinel 保护起来。大部分情况下,可以使用方法签名,URL,甚至服务名称作为资源名来标示资源

public class SentinelDemo {

    public void sentinelResourceName(){
        // HelloWorld = 资源名称
        try (Entry entry = SphU.entry("HelloWorld1")) {
            // 受保护的资源1
            System.out.println("hello world");
        } catch (BlockException e) {
            // 被限流后执行的逻辑
            e.printStackTrace();
        }
        // HelloWorld = 资源名称
        try (Entry entry = SphU.entry("HelloWorld2")) {
            // 受保护的资源2
            System.out.println("hello world");
        } catch (BlockException e) {
            // 被限流后执行的逻辑
            e.printStackTrace();
        }
    }

}
4.2规则

围绕资源的实时状态设定的规则,可以包括流量控制规则、熔断降级规则以及系统保护规则、访问控制规则、热点参数规则

public class SentinelDemo {
    
    public void initRules(){
        List<FlowRule> rules = new ArrayList<>();
        FlowRule rule = new FlowRule();
        rule.setResource("HelloWorld");
        // QPS阈值=20
        rule.setCount(20);
        // QPS限流
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rules.add(rule);
        FlowRuleManager.loadRules(rules);
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值