JAVA开发中的限流策略

  在开发高并发系统时,一般都需要一些手段来保护系统。比如缓存,降级,限流等。
缓存用于提升系统访问速度和增大系统处理能力;降级一般当服务出现问题或者影响到核心流程的性能,需要暂时屏蔽掉一些功能,待高峰过去或问题解决后再重新打开。而对于稀缺资源的访问,频繁调用复杂查询等需要大量计算资源的请求等,需要一种手段来限制这些场景下的并发量或请求量,此时需要使用的手段就是限流。
  限流的目的是通过对并发访问、请求进行限速或者限制在一个时间窗口内的请求数量来保护系统。一旦达到限流上限,可以拒绝服务,也可以采取将请求放入缓存队列等待等手段进行处理。
  一般高并发系统常见的限流有:限制并发总数(数据库连接池,线程池)、限制瞬间并发数、显示时间窗口内的平均速率,以及限制远程接口调用速率,限制MQ消费速度等。限流的使用需要做好评估,否则有可能出现一些奇怪的问题,或者造成不好的用户体验。

限流算法

  常见的限流算法有:令牌桶,漏桶。也可以简单的使用计数器来实现。

令牌桶

  令牌桶是指将令牌存放到一个固定容量的桶中,按照固定速率向桶中添加令牌。如果桶被填满后,新增令牌会被丢弃。当请求到来时,需要消耗指定数量的令牌(例如每个请求需要1个令牌),方可进入之后的处理流程,若桶中没有组够的令牌,请求将会被抛弃或进入等待队列。

漏桶

  漏桶,首先也存在一个令牌桶,同样是将令牌存放到桶中,按照固定速率向桶中添加令牌。然后将所有的请求都放入漏桶(可以是一个队列),进入漏桶的速度随意,当漏桶被填满之后,请求将被抛弃。漏桶中的请求消耗令牌,然后从漏桶中移除,请求被处理。
令牌桶的作用是限制流入速度,但是允许一定程度的突发流量。
漏桶限制的是请求的流出速率,对突发流量进行平滑处理。
  与令牌桶其实是一样的,只是发生作用的方向相反。对于相同的参数,起到的效果是一样的。
  有时我们还可以使用计数器来对并发总数进行限制。当在单位时间内请求达到了预设的阈值,则进行限流。这种限流是对请求总数的限制,而不是限制平均速率。

应用级限流

  我们在使用Tomcat时,以 下几个参数都与限流有关
acceptCount:如果Tomcat的处理线程都被占用,新来的连接请求将会进入队列,如果超出排队大小,则拒绝连接。
MaxConnections:瞬时最大连接数,超出的会排队等待。
maxThreads:tomcat能启动用来处理请求的最大线程数如果请求处理量远大于最大线程数,则会引起相应变慢或请求假死。

限制某个接口的总并发数/请求数

  如果接口有可能会有突发访问的情况,又担心访问量过大造成系统崩溃,就需要限制这个接口的总并发/请求数。因为粒度比较细,所以需要在有必要的接口上都设置相应的阈值。

private static final Long limit = 100L;
static AtomicLong atomic = new AtomicLong(1);
.
.
.        
try{
    if (atomic.incrementAndGet() > limit) {
        //拒绝请求 
    }
    //执行请求
}

  这种方式适合对可降级业务或需要过载保护的服务进行限流。一旦请求拒绝,或者让请求排队,或者直接告诉用户请求条件不满足。此时有一个前提条件是用户对于这种结果是可以接受的。

限制某个时间窗口内的请求数量

  如果想在某个时间窗口内限制某个接口的请求数量,此时我们可以对每秒/分钟/小时等的请求总量进行限制,以下是一种实现方式。

LoadingCache<Long,AtomicLong> counter = CacheBuilder.newBuilder()
        .expireAfterAccess(2.TimeUnit.SECONDS)
        .build(new CacheLoader<Long, AtomicLong>() {
            @Override
            public AtomicLong load(Long aLong) throws Exception {
                return new AtomicLong(0);
            }
        });
long limit = 1000;
while(true){
    long currentSeconds = System.currentTimeMillis()/1000;
    if(counter.get(currentSeconds).incrementAndGet() > limit){
        //被限流了
        continue;
    }
    //处理请求
}

  这里使用Guava的Cache来做一个计数器,过期时间设置为2秒,确保1秒内都可以正确访问。然后我们获取当前的时间戳,以秒为key来进行统计和限流,虽然简单粗暴,但是也可以满足某些场景。

平滑某个接口的请求

  之前限流的方式都只是从总量上做了控制,并不能够很好的处理突发请求,即瞬间请求都可能被允许。在一些场景中,我们需要对流量进行平滑,比如每50毫秒处理一个请求。这个时候就需要用令牌桶或漏桶算法来实现。Guava提供了令牌桶的算法实现,可以直接使用。

RateLimiter limter = RateLimiter.create(20);
while(true){
    limter.acquire();
    System.out.println(System.currentTimeMillis());
}

可以得到类似下边的结果
1520751900133
1520751900189
1520751900237
1520751900287
1520751900339
1520751900387
1520751900439
1520751900488
1520751900537
  可以看到每个输出间隔近似为50毫秒。RateLimiter.create(20)指令牌桶中每秒生成20个令牌。limter.acquire()默认消费一个令牌,如果代码改为下边这样,就可以看到不同的结果。

RateLimiter limter = RateLimiter.create(20);
while(true){
    limter.acquire(2);
    System.out.println(System.currentTimeMillis());
}

输出结果类似于
1520752107225
1520752107329
1520752107427
1520752107527
1520752107631
1520752107728
每个通过的请求间隔大约是100毫秒,即消耗2个令牌。

  以上限流方式都仅限于在单个应用内进行请求限流,如果多点部署的话,就需要进行分布式全局限流。关于分布式限流以后再聊。

以上内容为《亿级流量网站架构核心技术》的读书笔记,如对相关内容感兴趣,大家可以购买实体书进行阅读。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351

推荐阅读更多精彩内容