Java Redis多限流

简介: 通过本文的介绍,我们详细讲解了如何在Java中使用Redis实现三种不同的限流策略:固定窗口限流、滑动窗口限流和令牌桶算法。每种限流策略都有其适用的场景和特点,根据具体需求选择合适的限流策略可以有效保护系统资源和提高服务的稳定性。

在现代Web应用中,限流(Rate Limiting)是保护系统资源和防止滥用的重要机制。Redis由于其高性能和原子操作特性,成为实现限流的理想选择。本文将详细介绍如何在Java中使用Redis实现多种限流策略,包括固定窗口限流、滑动窗口限流和令牌桶算法。

一、准备工作

1. 安装Redis

确保Redis已经安装并正在运行。可以通过以下命令安装Redis:

sudo apt-get update
sudo apt-get install redis-server
sudo service redis-server start
AI 代码解读

2. 添加依赖

在Java项目中使用Redis,推荐使用Jedis库。以下是Maven依赖:

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>3.6.0</version>
</dependency>
AI 代码解读

二、固定窗口限流

固定窗口限流是最简单的限流算法。它将时间划分为固定的窗口,每个窗口内限制请求次数。

1. 实现逻辑

每当一个请求到达时,检查当前窗口内的请求数量是否超过限制。如果未超过,则允许请求并增加计数;否则,拒绝请求。

2. 示例代码

import redis.clients.jedis.Jedis;

public class FixedWindowRateLimiter {
    private static final String REDIS_HOST = "localhost";
    private static final int REDIS_PORT = 6379;
    private static final int LIMIT = 10; // 每窗口的最大请求数
    private static final int WINDOW_SIZE = 60; // 窗口大小(秒)

    private Jedis jedis;

    public FixedWindowRateLimiter() {
        this.jedis = new Jedis(REDIS_HOST, REDIS_PORT);
    }

    public boolean isAllowed(String userId) {
        String key = "rate_limit:" + userId;
        long currentWindow = System.currentTimeMillis() / 1000 / WINDOW_SIZE;
        String windowKey = key + ":" + currentWindow;

        if (jedis.exists(windowKey)) {
            if (Integer.parseInt(jedis.get(windowKey)) < LIMIT) {
                jedis.incr(windowKey);
                return true;
            } else {
                return false;
            }
        } else {
            jedis.setex(windowKey, WINDOW_SIZE, "1");
            return true;
        }
    }

    public static void main(String[] args) {
        FixedWindowRateLimiter limiter = new FixedWindowRateLimiter();
        String userId = "user123";

        for (int i = 0; i < 15; i++) {
            System.out.println("Request " + (i + 1) + ": " + limiter.isAllowed(userId));
        }
    }
}
​
AI 代码解读

三、滑动窗口限流

滑动窗口限流能够更精确地控制请求速率,避免固定窗口算法中临界点的突发流量问题。

1. 实现逻辑

滑动窗口限流记录每个请求的时间戳,并在每次请求时清理过期的记录。

2. 示例代码

import redis.clients.jedis.Jedis;
import java.util.stream.Collectors;
import java.util.List;

public class SlidingWindowRateLimiter {
    private static final String REDIS_HOST = "localhost";
    private static final int REDIS_PORT = 6379;
    private static final int LIMIT = 10; // 每窗口的最大请求数
    private static final int WINDOW_SIZE = 60; // 窗口大小(秒)

    private Jedis jedis;

    public SlidingWindowRateLimiter() {
        this.jedis = new Jedis(REDIS_HOST, REDIS_PORT);
    }

    public boolean isAllowed(String userId) {
        String key = "sliding_rate_limit:" + userId;
        long currentTime = System.currentTimeMillis() / 1000;
        long windowStart = currentTime - WINDOW_SIZE;

        // 清理过期请求
        jedis.zremrangeByScore(key, 0, windowStart);

        // 获取当前窗口内的请求数量
        long count = jedis.zcard(key);
        if (count < LIMIT) {
            jedis.zadd(key, currentTime, String.valueOf(currentTime));
            jedis.expire(key, WINDOW_SIZE);
            return true;
        } else {
            return false;
        }
    }

    public static void main(String[] args) {
        SlidingWindowRateLimiter limiter = new SlidingWindowRateLimiter();
        String userId = "user123";

        for (int i = 0; i < 15; i++) {
            System.out.println("Request " + (i + 1) + ": " + limiter.isAllowed(userId));
        }
    }
}
​
AI 代码解读

四、令牌桶算法

令牌桶算法是一种常用的流量整形算法,能够控制数据的流入速率。

1. 实现逻辑

令牌桶算法通过定时向桶中添加令牌,每次请求消耗一个令牌,如果桶为空则拒绝请求。

2. 示例代码

import redis.clients.jedis.Jedis;

public class TokenBucketRateLimiter {
    private static final String REDIS_HOST = "localhost";
    private static final int REDIS_PORT = 6379;
    private static final int MAX_TOKENS = 10; // 最大令牌数
    private static final int REFILL_RATE = 1; // 每秒添加令牌数

    private Jedis jedis;

    public TokenBucketRateLimiter() {
        this.jedis = new Jedis(REDIS_HOST, REDIS_PORT);
    }

    public boolean isAllowed(String userId) {
        String key = "token_bucket:" + userId;
        long currentTime = System.currentTimeMillis() / 1000;

        // 获取最后更新时间和当前令牌数
        String[] bucketInfo = jedis.hmget(key, "tokens", "timestamp").toArray(new String[0]);
        int tokens = bucketInfo[0] != null ? Integer.parseInt(bucketInfo[0]) : MAX_TOKENS;
        long lastRefillTime = bucketInfo[1] != null ? Long.parseLong(bucketInfo[1]) : currentTime;

        // 计算需要添加的令牌数
        long timeDiff = currentTime - lastRefillTime;
        int newTokens = (int) Math.min(MAX_TOKENS, tokens + timeDiff * REFILL_RATE);

        if (newTokens > 0) {
            jedis.hmset(key, Map.of("tokens", String.valueOf(newTokens - 1), "timestamp", String.valueOf(currentTime)));
            jedis.expire(key, MAX_TOKENS / REFILL_RATE); // 设置过期时间
            return true;
        } else {
            return false;
        }
    }

    public static void main(String[] args) {
        TokenBucketRateLimiter limiter = new TokenBucketRateLimiter();
        String userId = "user123";

        for (int i = 0; i < 15; i++) {
            System.out.println("Request " + (i + 1) + ": " + limiter.isAllowed(userId));
        }
    }
}
​
AI 代码解读

五、总结

通过本文的介绍,我们详细讲解了如何在Java中使用Redis实现三种不同的限流策略:固定窗口限流、滑动窗口限流和令牌桶算法。每种限流策略都有其适用的场景和特点,根据具体需求选择合适的限流策略可以有效保护系统资源和提高服务的稳定性。

目录
打赏
0
16
20
0
465
分享
相关文章
Redis 实操要点:Java 最新技术栈的实战解析
本文介绍了基于Spring Boot 3、Redis 7和Lettuce客户端的Redis高级应用实践。内容包括:1)现代Java项目集成Redis的配置方法;2)使用Redisson实现分布式可重入锁与公平锁;3)缓存模式解决方案,包括布隆过滤器防穿透和随机过期时间防雪崩;4)Redis数据结构的高级应用,如HyperLogLog统计UV和GeoHash处理地理位置。文章提供了详细的代码示例,涵盖Redis在分布式系统中的核心应用场景,特别适合需要处理高并发、分布式锁等问题的开发场景。
157 38
Java Redis 面试题集锦 常见高频面试题目及解析
本文总结了Redis在Java中的核心面试题,包括数据类型操作、单线程高性能原理、键过期策略及分布式锁实现等关键内容。通过Jedis代码示例展示了String、List等数据类型的操作方法,讲解了惰性删除和定期删除相结合的过期策略,并提供了Spring Boot配置Redis过期时间的方案。文章还探讨了缓存穿透、雪崩等问题解决方案,以及基于Redis的分布式锁实现,帮助开发者全面掌握Redis在Java应用中的实践要点。
106 6
|
3月前
|
在Java环境下如何进行Redis数据库的操作
总的来说,使用Jedis在Java环境下进行Redis数据库的操作,是一种简单而高效的方法。只需要几行代码,就可以实现复杂的数据操作。同时,Jedis的API设计得非常直观,即使是初学者,也可以快速上手。
233 94
尼恩一键开发环境: vagrant+java+springcloud+redis+zookeeper镜像下载(&制作详解)
尼恩提供了一系列文章,旨在帮助开发者轻松搭建一键开发环境,涵盖Java分布式、高并发场景下的多种技术组件安装与配置。内容包括但不限于Windows和CentOS虚拟机的安装与排坑指南、MySQL、Kafka、Redis、Zookeeper等关键组件在Linux环境下的部署教程,并附带详细的视频指导。此外,还特别介绍了Vagrant这一虚拟环境部署工具,
尼恩一键开发环境: vagrant+java+springcloud+redis+zookeeper镜像下载(&制作详解)
java连接redis和基础操作命令
通过以上内容,您可以掌握在Java中连接Redis以及进行基础操作的基本方法,进而在实际项目中灵活应用。
259 30
Liunx部署java项目Tomcat、Redis、Mysql教程
本文详细介绍了如何在 Linux 服务器上安装和配置 Tomcat、MySQL 和 Redis,并部署 Java 项目。通过这些步骤,您可以搭建一个高效稳定的 Java 应用运行环境。希望本文能为您在实际操作中提供有价值的参考。
456 26
使用Java操作Redis数据类型的详解指南
通过使用Jedis库,可以在Java中方便地操作Redis的各种数据类型。本文详细介绍了字符串、哈希、列表、集合和有序集合的基本操作及其对应的Java实现。这些示例展示了如何使用Java与Redis进行交互,为开发高效的Redis客户端应用程序提供了基础。希望本文的指南能帮助您更好地理解和使用Redis,提升应用程序的性能和可靠性。
156 1
|
8月前
|
Java 使用 Redis
10月更文挑战第22天
171 0
借助Redis做秒杀和限流的思考
原文:借助Redis做秒杀和限流的思考 最近群里聊起秒杀和限流,我自己没有做过类似应用,但是工作中遇到过更大的数据和并发。 于是提出了一个简单的模型: var count = rds.inc(key); if(count > 1000) throw "已抢光!" 借助Redis单线程模型,它的inc是安全的,确保每次加一,然后返回加一后的结果。
1065 0

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问