8. 基于 Redis 实现限流

news/2024/11/18 13:45:34/

在高并发的分布式系统中,限流是保证服务稳定性的重要手段之一。通过限流机制,可以控制系统处理请求的频率,避免因瞬时流量过大导致系统崩溃。Redis 是一种高效的缓存数据库,具备丰富的数据结构和原子操作,适合用来实现分布式环境下的限流。

本文将结合 Spring Boot 和 Redis,详细讲解如何实现基于 Redis 的限流功能,包括应用场景、实现原理、具体过程以及效果分析。

一、限流的应用场景

限流在各种场景中扮演着重要角色,以下是几个典型的使用场景:

  1. 接口防刷:防止恶意用户或爬虫频繁访问某些接口,导致服务负载过高。
  2. API 调用频率控制:对外部 API 提供服务时,限制用户调用频率,避免超出系统处理能力。
  3. 短信验证码:发送短信验证码时限制同一用户的发送频率,防止滥用。
  4. 交易场景:在抢购或秒杀系统中,限制用户请求的频次,防止瞬时高并发请求导致服务器宕机。
二、限流的实现原理

Redis 实现限流通常采用以下几种方式:

  1. 固定窗口限流:在固定的时间窗口内,限制请求的次数。例如每分钟最多允许 100 次请求。
  2. 滑动窗口限流:将固定时间窗口划分为多个小的时间段,保证限流更平滑和公平。
  3. 令牌桶算法:限制访问速率,按照固定的速率往令牌桶中放置令牌,用户每次请求必须获取一个令牌才能通过。
  4. 漏桶算法:按照固定的速率处理请求,若请求过多则溢出丢弃。

本文主要使用固定窗口和滑动窗口两种方法进行 Redis 限流的实现。

三、基于 Redis 实现限流的步骤
1. 项目配置

首先,创建一个 Spring Boot 项目,并引入 Redis 相关依赖。

<dependencies><!-- Spring Boot Starter for Redis --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- Spring Boot Web Starter --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency>
</dependencies>

application.properties 中配置 Redis 连接:

spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=yourpassword
2. 实现固定窗口限流

固定窗口限流的核心思路是,每个用户在一个固定时间窗口(如 1 分钟)内只能发起 N 次请求。Redis 提供的 INCREXPIRE 命令可以高效地实现这一限流机制。

我们可以通过以下步骤来实现固定窗口限流:

  • 检查 Redis 中该用户的访问计数,如果不存在则创建,并设置有效期为 1 分钟。
  • 如果计数未达到阈值,允许访问并增加计数。
  • 如果计数超过阈值,拒绝请求。

首先,创建 RateLimiterUtil 工具类。

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;import java.util.concurrent.TimeUnit;@Component
public class RateLimiterUtil {private final StringRedisTemplate redisTemplate;public RateLimiterUtil(StringRedisTemplate redisTemplate) {this.redisTemplate = redisTemplate;}/*** 基于固定窗口的限流* @param key 限流标识* @param limit 限流次数* @param windowSize 时间窗口大小(秒)* @return 是否允许访问*/public boolean isAllowed(String key, int limit, long windowSize) {Long count = redisTemplate.opsForValue().increment(key);if (count == 1) {// 第一次访问,设置过期时间redisTemplate.expire(key, windowSize, TimeUnit.SECONDS);}return count <= limit;}
}
3. 使用固定窗口限流进行接口请求控制

接下来,我们可以在需要限流的接口上使用 RateLimiterUtil 来控制请求的频率。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class ApiController {@Autowiredprivate RateLimiterUtil rateLimiterUtil;private static final String LIMIT_KEY = "api_limit";@GetMapping("/api/resource")public String getResource() {// 限制每个用户每分钟最多访问 10 次boolean isAllowed = rateLimiterUtil.isAllowed(LIMIT_KEY, 10, 60);if (!isAllowed) {return "访问频率过高,请稍后再试";}return "访问成功";}
}
4. 实现滑动窗口限流

相比固定窗口,滑动窗口限流可以更细粒度地控制请求频率,避免流量高峰时集中在某个时间段。

滑动窗口的核心思想是,将一个大时间窗口划分为多个小的时间段,每次请求都会在 Redis 中记录当前时间段的请求次数,并删除过期的时间段数据。

可以通过 Redis 的 ZADD(有序集合)来记录请求的时间戳,结合 ZRANGEZREM 来计算当前窗口内的请求次数。

import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;import java.time.Instant;@Component
public class SlidingWindowRateLimiter {private final StringRedisTemplate redisTemplate;public SlidingWindowRateLimiter(StringRedisTemplate redisTemplate) {this.redisTemplate = redisTemplate;}/*** 基于滑动窗口的限流* @param key 限流标识* @param limit 限流次数* @param windowSize 时间窗口大小(秒)* @return 是否允许访问*/public boolean isAllowed(String key, int limit, long windowSize) {long now = Instant.now().getEpochSecond();long windowStart = now - windowSize;// 使用 Redis 的有序集合记录请求时间redisTemplate.opsForZSet().add(key, String.valueOf(now), now);// 移除窗口之外的数据redisTemplate.opsForZSet().removeRangeByScore(key, 0, windowStart);// 统计窗口内的请求数Long requestCount = redisTemplate.opsForZSet().zCard(key);if (requestCount != null && requestCount > limit) {return false;}return true;}
}
5. 使用滑动窗口限流控制接口访问
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class SlidingApiController {@Autowiredprivate SlidingWindowRateLimiter slidingWindowRateLimiter;private static final String LIMIT_KEY = "sliding_api_limit";@GetMapping("/api/sliding_resource")public String getResource() {// 限制每个用户每分钟最多访问 10 次boolean isAllowed = slidingWindowRateLimiter.isAllowed(LIMIT_KEY, 10, 60);if (!isAllowed) {return "访问频率过高,请稍后再试";}return "访问成功";}
}
四、限流效果分析
  1. 性能与效率:基于 Redis 的限流具有较高的性能,INCREXPIREZADD 等操作都具备原子性,且 Redis 本身可以高效处理大量并发请求,适用于分布式系统。
  2. 限流精度:固定窗口限流简单易实现,适用于对请求频率没有精细控制要求的场景;滑动窗口限流能够提供更加平滑的限流体验,避免了流量高峰。
  3. 分布式扩展:Redis 支持分布式部署,适用于多实例环境中的限流需求,能够保证多个节点对同一用户的请求进行统一控制。
五、其他优化与改进建议
  1. 限流规则动态调整:可以通过 Redis 订阅发布模式(Pub/Sub)实现限流规则的动态调整,适应不同的流量需求。
  2. 用户维度限流:在实际应用中,限流往往根据不同用户、IP 地址等维度进行,可以通过 key 动态拼接用户 ID 或 IP 来实现多维度限流。
  3. 分布式缓存与 Redis 哨兵:使用 Redis 的哨兵机制或集群模式来提高限流系统的可用性。

http://www.ppmy.cn/news/1547997.html

相关文章

智能网页内容截图工具:AI助力内容提取与可视化

我们每天都会接触到大量的网页内容。然而&#xff0c;如何从这些内容中快速提取关键信息&#xff0c;并有效地进行整理和分享&#xff0c;一直是困扰我们的问题。本文将介绍一款我近期完成的基于AI技术的智能网页内容截图工具&#xff0c;它能够自动分析网页内容&#xff0c;截…

【Cesium】自定义材质,添加带有方向的滚动路线

【Cesium】自定义材质&#xff0c;添加带有方向的滚动路线 &#x1f356; 前言&#x1f3b6;一、实现过程✨二、代码展示&#x1f3c0;三、运行结果&#x1f3c6;四、知识点提示 &#x1f356; 前言 【Cesium】自定义材质&#xff0c;添加带有方向的滚动路线 &#x1f3b6;一、…

时序预测:多头注意力+宽度学习

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

Java算法OJ(7)随机快速排序

目录 1.前言 2.正文 1. 快速排序的基本原理 2. 随机快速排序的改进 3. 随机快速排序的步骤 3.小结 1.前言 哈喽大家好吖&#xff0c;今儿给大家带来算法—随机快速排序相关知识点&#xff0c;废话不多说让我们开始。 2.正文 在了解随机快排之前&#xff0c;先了解一下…

【网络安全】XSS注入

一、什么是XSS注入 XSS&#xff08;Cross-Site Scripting&#xff09;注入是一种网络安全漏洞&#xff0c;它允许攻击者向网站注入恶意脚本代码&#xff0c;然后在用户的浏览器上执行。 二、XSS注入有哪些危害 盗取用户的敏感信息&#xff1a;攻击者可以通过注入恶意脚本代码…

Docker在微服务架构中的最佳实践

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 Docker在微服务架构中的最佳实践 Docker在微服务架构中的最佳实践 Docker在微服务架构中的最佳实践 引言 Docker 概述 定义与原理…

2411rust,异步函数

原文 Rust异步工作组很高兴地宣布,在实现在特征中使用异步 fn的目标方面取得了重大进度.将在下周发布稳定的Rust1.75版,会包括特征中支持impl Trait注解和async fn. 稳定化 自从RFC#1522在Rust1.26中稳定下来以来,Rust就允许用户按函数的返回类型(一般叫"RPIT")编…

第74期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以找…