如何使用JAVA实现限流

背景说明

限流在微服务架构的系统中是十分常见的需求,同样限流也是各个服务接入阶段也是不得不考虑的问题。在面对流量激增的情况下,我们要考虑给程序做限流控制,避免短时间过多的流量直接击垮系统。

所谓的限流指的是什么呢?可以这么理解,在一个时间周期内请求的次数,不得超过我们给定的一个预期值。如果超过了必须做出拒绝的策略,拒绝策略可以是丢弃,或者阻塞。那么这种需求的常见的实现方案有哪些呢?

常见的实现方案

限流功能常见的实现方案包括:

  • 固定窗口法。
  • 滑动窗口法
  • 滑动日志法
  • 漏桶法
  • 令牌法

对于固定窗口和滑动窗口的理解

假定我们的限流要求是4秒内只能通过20个请求,那么固定窗口是将4秒的时间跨度视作一个整体窗口。要求在这一个窗口内,请求的次数不得超过20次。并且当时间经过4秒后,整个窗口会重置,窗口的计数器置为0。

这种做法在实现上很简单,但是会有一些问题无法很好的处理,比如窗口边界发生请求突增导致限流的结果超过预期设置的QPS。怎么理解这个现象呢?比如周期的最后一秒交易数量到了20次,在下一周期的第1秒交易数量也达到了20次。那么将两部分合起来,它的QPS其实是超过我们的预期。

为了解决边界请求突增的问题,我们可以使用滑动窗口法。滑动窗口法的一个核心思想是,它基于固定窗口法做了改进,固定窗口的问题是将整个时间跨度视为一个窗口,划分的粒度太粗了。那么滑动窗口呢,它的做法是划分出多个窗口,每个窗口内各自持有一个计数器。还是在刚刚的场景,划分出4个窗口,4个窗口各自都持有计数器。这种做法就解决了刚刚固定窗口的问题,在第4秒虽然来了20个请求,那么属于第4秒的窗口的计数器达到了20。现在时间来到4.5秒,这个时候第4秒的窗口是不会被回收的。那么4.5秒的时候进来的交易同样会被限流住,故此问题解决。滑动窗口就是通过这种方式让限流效果更加的平滑。

结合漏桶和滑动日志的特点实现限流器

漏桶中只能以恒定的速率剔除过期元素,而滑动日志的做法中让每一个元素都记录了请求的时间,那么我可以将这两者结合起来。在剔除的阶段,我可以拿到每个元素的请求时间并计算出过期时间,与当前时间进行实时比较,这样就能准确剔除真正到期了的元素。

通过这种方式,能够应对流量突增的情况。

下面附上我实现的限流算法的代码。

package com.hhdd.demos.rateLimitter;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalTime;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 简单的限流器实现
 * 实现思想和漏桶思路有点像,但略有变形
 * 漏桶是按照恒定速率清除桶内的元素
 * 本实现因桶内记录了时间戳故可更灵活的剔除过期成员
 *
 * @Author huanghedidi
 * @Date 2025/2/7 21:12
 */
public class QueueTimeLogRateLimiter<T extends RateLimiterRequest> {
   
    /**
     * 限流器的名称,如针对每个接口设置一个限流器
     * 则限流器名称可赋值为接口名称
     */
    private String name;
    /**
     * 漏桶思想中桶的容积
     */
    private int capacity;
    /**
     * 时间跨度,单位为ms
     */
    private long timeSpan;
    /**
     * 漏桶内的元素用queue记录
     * queue数据结构是有序的,方便剔除过期元素
     */
    private Queue<T> queue;
    /**
     * 限流器是共享资源,存在并发问题,操作需要用锁
     */
    private Lock lock;

    private Atom
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值