Java实现接口限流方案

Java实现接口限流,通常有三种方案,分别是计数器算法、令牌桶算法和漏桶算法。下面分别介绍这三种方案的实现方法和代码示例。

1. 计数器算法

计数器算法的核心思想是,对窗口内的API请求进行计数,当计数超过设定的阈值时,拒绝请求。其中,窗口有两种实现方式:滑动窗口和计时窗口。

滑动窗口的实现方法如下(以限制1秒内请求不超过5次为例):

1.1 代码实现

import java.util.concurrent.ArrayBlockingQueue;

public class SlidingWindowRateLimiter {
    private int permitsPerSecond;
    private int maxPermits;
    private volatile int count;
    private ArrayBlockingQueue<Long> timestamps;

    public SlidingWindowRateLimiter(int permitsPerSecond, int maxPermits) {
        this.permitsPerSecond = permitsPerSecond;
        this.maxPermits = maxPermits;
        this.count = 0;
        this.timestamps = new ArrayBlockingQueue<>(maxPermits);
        for (int i = 0; i < maxPermits; i++) {
            this.timestamps.offer(System.currentTimeMillis() / 1000);
        }
    }

    public synchronized boolean tryAcquire() {
        long now = System.currentTimeMillis() / 1000;
        long last = this.timestamps.poll();
        this.timestamps.offer(now);
        this.count += this.permitsPerSecond * (now - last);
        if (this.count > this.maxPermits) {
            this.count = this.maxPermits;
        }
        if (this.count <= 0) {
            return false;
        } else {
            this.count--;
            return true;
        }
    }
}

1.2 示例说明

public class TestSlidingWindowRateLimiter {
    public static void main(String[] args) throws InterruptedException {
        int permitsPerSecond = 5;
        int maxPermits = 10;
        SlidingWindowRateLimiter rateLimiter = new SlidingWindowRateLimiter(permitsPerSecond, maxPermits);
        while (true) {
            if (rateLimiter.tryAcquire()) {
                System.out.println("请求成功");
            } else {
                System.out.println("请求失败");
            }
            Thread.sleep(200);
        }
    }
}

运行上述示例,可以看到程序每隔200毫秒尝试向接口发送请求,当请求次数超过10次时,接口将返回“请求失败”的提示信息。

2. 令牌桶算法

令牌桶算法的核心思想是,维护一个令牌桶,每秒钟往桶中添加一定数量的令牌,API请求从桶中获取令牌,如果桶中没有令牌,则拒绝请求。

2.1 代码实现

import java.util.concurrent.*;

public class TokenBucketRateLimiter {
    private int permitsPerSecond;
    private int maxPermits;
    private volatile int count;
    private final ScheduledExecutorService scheduler;
    private ScheduledFuture<?> scheduledFuture;

    public TokenBucketRateLimiter(int permitsPerSecond, int maxPermits) {
        this.permitsPerSecond = permitsPerSecond;
        this.maxPermits = maxPermits;
        this.count = maxPermits;
        this.scheduler = Executors.newScheduledThreadPool(1);
        this.scheduledFuture = this.scheduler.scheduleAtFixedRate(() -> {
            int newCount = count + permitsPerSecond;
            if (newCount > maxPermits) {
                count = maxPermits;
            } else {
                count = newCount;
            }
        }, 0, 1, TimeUnit.SECONDS);
    }

    public synchronized boolean tryAcquire() {
        if (this.count <= 0) {
            return false;
        } else {
            this.count--;
            return true;
        }
    }

    public void shutdown() {
        this.scheduledFuture.cancel(true);
        this.scheduler.shutdownNow();
    }
}

2.2 示例说明

public class TestTokenBucketRateLimiter {
    public static void main(String[] args) throws InterruptedException {
        int permitsPerSecond = 1;
        int maxPermits = 10;
        TokenBucketRateLimiter rateLimiter = new TokenBucketRateLimiter(permitsPerSecond, maxPermits);
        while (true) {
            if (rateLimiter.tryAcquire()) {
                System.out.println("请求成功");
            } else {
                System.out.println("请求失败");
            }
            Thread.sleep(500);
        }
    }
}

运行上述示例,可以看到程序每隔0.5秒尝试向接口发送请求,当桶中没有令牌时,接口将返回“请求失败”的提示信息。

3. 漏桶算法

漏桶算法的核心思想是,限制请求发送速率,即将API请求压入一个漏桶中,漏桶以固定速率将请求处理,当API请求超过漏桶最大容量时,拒绝请求。

3.1 代码实现

import java.util.concurrent.TimeUnit;

public class LeakyBucketRateLimiter {
    private int permitsPerSecond;
    private int maxPermits;
    private volatile int count;
    private long lastLeakTime;

    public LeakyBucketRateLimiter(int permitsPerSecond, int maxPermits) {
        this.permitsPerSecond = permitsPerSecond;
        this.maxPermits = maxPermits;
        this.count = 0;
        this.lastLeakTime = System.currentTimeMillis();
    }

    public boolean tryAcquire() {
        long now = System.currentTimeMillis();
        long leakTime = (now - lastLeakTime) / 1000;
        lastLeakTime = now;
        int leakCount = (int) (leakTime * permitsPerSecond);
        count = Math.max(0, count - leakCount);
        if (count >= maxPermits) {
            return false;
        } else {
            count++;
            return true;
        }
    }
}

3.2 示例说明

public class TestLeakyBucketRateLimiter {
    public static void main(String[] args) throws InterruptedException {
        int permitsPerSecond = 1;
        int maxPermits = 10;
        LeakyBucketRateLimiter rateLimiter = new LeakyBucketRateLimiter(permitsPerSecond, maxPermits);
        while (true) {
            if (rateLimiter.tryAcquire()) {
                System.out.println("请求成功");
            } else {
                System.out.println("请求失败");
            }
            Thread.sleep(500);
        }
    }
}

运行上述示例,可以看到程序每隔0.5秒尝试向接口发送请求,当请求数量超过漏桶的最大容量时,接口将返回“请求失败”的提示信息。

以上三种接口限流算法均有各自的优缺点,可根据具体需求选择适合的实现方式。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java实现接口限流方案 - Python技术站

(0)
上一篇 2023年5月19日
下一篇 2023年5月19日

相关文章

  • Java中为何要使用ArrayList

    Java 是一门面向对象的编程语言,封装、继承和多态等特性是其特色。在实际应用中,常常需要使用到集合类来存储和操作对象集合。而 ArrayList 就是 Java 中比较常见、使用广泛的一种集合类。 ArrayList 的概述 ArrayList 是基于数组实现的动态数组,可以随时根据实际情况调整容量大小。ArrayList 实现了 List 接口,因此它还…

    Java 2023年5月26日
    00
  • Java迭代器与Collection接口超详细讲解

    Java迭代器与Collection接口超详细讲解 什么是Java迭代器? Java中的迭代器是一种访问集合元素的方式,它提供了一种遍历集合的统一方法,可以不用关心底层集合的实现。迭代器可以依次访问集合中的每个元素,并且支持在遍历过程中进行元素的删除操作。 Java中的迭代器是通过java.util.Iterator接口实现的。Iterator接口实际上是一…

    Java 2023年5月26日
    00
  • springmvc集成shiro登录失败处理操作

    要将SpringMVC和Shiro集成起来,需要进行以下步骤: 1. 导入相关依赖 在项目的pom.xml文件中,需要添加spring-boot-starter-web、shiro-spring、shiro-core和thymeleaf等相关依赖。具体依赖版本可以自行选择,这里我给出一个示例: <dependencies> <depende…

    Java 2023年6月15日
    00
  • Java在长字符串中查找短字符串的实现多种方法

    下面我会详细讲解Java在长字符串中查找短字符串的实现多种方法。 目录 需求背景 传统字符串查找方式 String类的indexOf方法 Pattern类的matcher方法 优化的字符串查找方式 Boyer-Moore算法 KMP算法 总结 需求背景 在Java程序中处理长字符串时,经常需要进行短字符串的查找。例如,在字符串中查找单词、检查字符串中是否包含…

    Java 2023年5月26日
    00
  • Spring jackson原理及基本使用方法详解

    Spring Jackson原理及基本使用方法详解 什么是Jackson? Jackson是一个开源的Java库,用于处理JSON格式的文本数据。它可以将Java对象序列化为JSON格式的数据,也可以将JSON格式的数据反序列化为Java对象。 什么是Spring Jackson? Spring Jackson是Spring框架中对Jackson的集成。通过…

    Java 2023年5月26日
    00
  • Java操作MongoDB数据库的示例代码

    以下是“Java操作MongoDB数据库的示例代码”的完整攻略: 安装MongoDB和Java驱动 首先需要安装MongoDB和Java驱动程序。可以在MongoDB官网下载最新版MongoDB,然后安装到本地计算机上。接下来,需要下载MongoDB的Java驱动jar文件,在项目中引入。 连接MongoDB数据库 连接MongoDB数据库需要使用Mongo…

    Java 2023年5月20日
    00
  • 编写线程安全的JSP程序

    编写线程安全的 JSP 程序需要注意以下几个方面: 避免使用 JavaBean、Session 和 Application 等共享对象作为局部变量。这些对象可能成为多个线程访问的共享资源,从而发生同步问题。 小心使用 JSP 默认的线程同步机制。JSP 的默认行为是重用已编译的页面实例,从而提高性能。但这会导致多个线程共享同一页面实例,如果在页面中使用了共享…

    Java 2023年6月15日
    00
  • Kafka 安装与配置详细过程

    下面是 Kafka 安装与配置的详细攻略: 安装 Kafka 下载 Kafka 压缩包: wget http://mirrors.ocf.berkeley.edu/apache/kafka/2.8.0/kafka_2.13-2.8.0.tgz 解压缩 Kafka 压缩包: tar -xzf kafka_2.13-2.8.0.tgz 进入解压后的 Kafka …

    Java 2023年5月20日
    00
合作推广
合作推广
分享本页
返回顶部