高并发场景下限流,常见的限流算法、方案解析!

作者:微信小助手

发布时间:2020-01-15T17:04:55

点击蓝色“架构文摘”关注我哟

加个“星标”,每天上午 09:25,干货推送!



  作者:nick hao

  来源:cnblogs.com/haoxinyue/p/6792309.html

开涛大神在博客中说过:在开发高并发系统时有三把利器用来保护系统:缓存、降级和限流。本文结合作者的一些经验介绍限流的相关概念、算法和常规的实现方式。


缓存

缓存比较好理解,在大型高并发系统中,如果没有缓存数据库将分分钟被爆,系统也会瞬间瘫痪。

使用缓存不单单能够提升系统访问速度、提高并发访问量,也是保护数据库、保护系统的有效方式。

大型网站一般主要是“读”,缓存的使用很容易被想到。 在大型“写”系统中,缓存也常常扮演者非常重要的角色。

比如累积一些数据批量写入,内存里面的缓存队列(生产消费),以及HBase写数据的机制等等也都是通过缓存提升系统的吞吐量或者实现系统的保护措施。 甚至消息中间件,你也可以认为是一种分布式的数据缓存。

降级

服务降级是当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行。

降级往往会指定不同的级别,面临不同的异常等级执行不同的处理。

根据服务方式: 可以拒接服务,可以延迟服务,也有时候可以随机服务。 根据服务范围: 可以砍掉某个功能,也可以砍掉某些模块。

总之服务降级需要根据不同的业务需求采用不同的降级策略。 主要的目的就是服务虽然有损但是总比没有好。

限流

限流可以认为服务降级的一种,限流就是限制系统的输入和输出流量已达到保护系统的目的。

一般来说系统的吞吐量是可以被测算的,为了保证系统的稳定运行,一旦达到的需要限制的阈值,就需要限制流量并采取一些措施以完成限制流量的目的。比如:延迟处理,拒绝处理,或者部分拒绝处理等等。
 

限流的算法

常见的限流算法有:计数器、漏桶和令牌桶算法。

计数器

计数器是最简单粗暴的算法。

比如某个服务最多只能每秒钟处理100个请求。我们可以设置一个1秒钟的滑动窗口,窗口中有10个格子,每个格子100毫秒,每100毫秒移动一次,每次移动都需要记录当前服务请求的次数。

内存中需要保存10次的次数。可以用数据结构LinkedList来实现。格子每次移动的时候判断一次,当前访问次数和LinkedList中最后一个相差是否超过100,如果超过就需要限流了。

很明显,当滑动窗口的格子划分的越多,那么滑动窗口的滚动就越平滑,限流的统计就会越精确。

示例代码如下:

//服务访问次数,可以放在Redis中,实现分布式系统的访问计数
Long counter = 0L;
//使用LinkedList来记录滑动窗口的10个格子。
LinkedList<Long> ll = new LinkedList<Long>();
public static void main(String[] args)
{
  Counter counter = new Counter();
  counter.doCheck();
}
private void doCheck()
{
  while (true)
  {
    ll.addLast(counter);
    if (ll.size() > 10)
    {
      ll.removeFirst();
    }
    //比较最后一个和第一个,两者相差一秒
    if ((ll.peekLast() - ll.peekFirst()) > 100)
    {
      //To limit rate
    }
    Thread.sleep(100);
  }
}


漏桶算法
漏桶算法即leaky bucket是一种非常常用的限流算法,可以用来实现流量整形(Traffic Shaping)和流量控制(Traffic Policing)。