首页 > 数据库 >Java Redis多限流

Java Redis多限流

时间:2025-01-03 12:33:30浏览次数:1  
标签:Java String int Redis private 限流 jedis static

在现代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
​
   

2. 添加依赖

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

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>3.6.0</version>
</dependency>
​
   

二、固定窗口限流

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

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));
        }
    }
}
​
   

三、滑动窗口限流

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

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));
        }
    }
}
​
   

四、令牌桶算法

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

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));
        }
    }
}
​
   

五、总结

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

标签:Java,String,int,Redis,private,限流,jedis,static
From: https://www.cnblogs.com/mybook000/p/18649909

相关文章

  • HTML5期末大作业:基于HTML+CSS+JavaScript仿蘑菇街购物商城设计毕业论文源码 (1)
    常见网页设计作业题材有个人、美食、公司、学校、旅游、电商、宠物、电器、茶叶、家居、酒店、舞蹈、动漫、服装、体育、化妆品、物流、环保、书籍、婚纱、游戏、节日、戒烟、电影、摄影、文化、家乡、鲜花、礼品、汽车、其他等网页设计题......
  • 大二Web课程设计——张家界旅游网站设计与实现(HTML+CSS+JavaScript)
    ......
  • springboot3 redis 常用操作工具类
    在SpringBoot3中,操作Redis通常使用SpringDataRedis提供的工具类,如RedisTemplate和StringRedisTemplate。以下是一个详细的Redis操作工具类的实现,涵盖了常用功能。完整的Redis工具类以下工具类可以实现基本的Redis操作,例如字符串、哈希、列表、集合和有......
  • 快速排序算法的 Java 实现与性能调优
    目录一、快速排序的基本原理二、快速排序的Java实现三、时间复杂度与空间复杂度四、总结引言排序是计算机科学中的基础问题之一,无论是在数据库查询、数据分析,还是在日常编程中,排序算法的选择都对性能有着重要的影响。快速排序(QuickSort)是最广泛使用的排序算法之一,......
  • 《刚刚问世》系列初窥篇-Java+Playwright自动化测试-9- 浏览器的相关操作 (详细教程)
    1.简介在自动化测试领域,元素定位是非常重要的一环。正确定位页面元素是测试用例能否成功执行的关键因素之一。playwright是一种自动化测试工具,它提供了丰富的元素定位方法,可以满足不同场景下的定位需求。前边宏哥已经通过不少的篇幅将playwright的元素定位的一些常用的基本方法和......
  • 基于Java异步处理的 USB 设备监控系统设计与实现:技术架构与业务场景分析
    1.引言随着智能设备和物联网技术的快速发展,USB设备在各行各业中的应用越来越广泛。从工业设备到个人电子产品,USB设备已经成为数据传输和设备连接的主流方式。然而,设备的动态插拔和状态变化的检测,成为了许多业务系统中的一个重要挑战。特别是在需要实时响应设备插拔事件......
  • Java反射机制与动态代理
    软件开发中,灵活性与扩展性是非常重要的需求,而Java的反射机制与动态代理正是实现这些特性的强大工具。反射机制让程序在运行时能够检查和操作类的信息,而动态代理则为方法调用提供了一种灵活的拦截机制。本文将深入探讨这两种机制的概念、原理、应用场景,并通过具体示例展示它......
  • nodejs+vue+expressd协同过滤算法的毕业生租房平台java+python+php-计算机毕业设计
    目录技术栈和环境说明具体实现截图预期达到的目标系统设计详细视频演示技术路线解决的思路性能/安全/负载方面可行性分析论证python-flask核心代码部分展示python-django核心代码部分展示研究方法感恩大学老师和同学源码获取技术栈和环境说明本系统以Python开发语言......
  • 浏览器在渲染时遇到javascript文件要怎么处理?
    在前端开发中,当浏览器在渲染网页时遇到JavaScript文件,它会按照一系列步骤来处理这些文件。以下是浏览器处理JavaScript文件的主要步骤:解析HTML文档:浏览器从服务器下载HTML文档,并开始解析它。当浏览器遇到<script>标签时,它会根据标签的属性(如src、async、defer、t......
  • 【Java中BigDecimal和Long对比】
    Java中BigDecimal和Long对比概述BigDecimal定义:BigDecimal是Java中提供的一个不可变的、任意精度的有符号十进制数类。它适合用于需要高精度和控制舍入行为的场景,例如货币计算。特点:支持任意精度的小数运算。提供了多种舍入模式。不可变性(immutable),每次操作都会返......