当前位置: 首页 > news >正文

8. 基于 Redis 实现限流

在高并发的分布式系统中,限流是保证服务稳定性的重要手段之一。通过限流机制,可以控制系统处理请求的频率,避免因瞬时流量过大导致系统崩溃。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 的哨兵机制或集群模式来提高限流系统的可用性。

相关文章:

8. 基于 Redis 实现限流

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

241117学习日志——[CSDIY] [ByteDance] 后端训练营 [05]

CSDIY&#xff1a;这是一个非科班学生的努力之路&#xff0c;从今天开始这个系列会长期更新&#xff0c;&#xff08;最好做到日更&#xff09;&#xff0c;我会慢慢把自己目前对CS的努力逐一上传&#xff0c;帮助那些和我一样有着梦想的玩家取得胜利&#xff01;&#xff01;&…...

蓝桥杯备赛(持续更新)

16届蓝桥杯算法类知识图谱.pdf 1. 格式打印 %03d&#xff1a;如果是两位数&#xff0c;将会在前面添上一位0 %.2f&#xff1a;会保留两位小数 如果是long&#xff0c;必须在数字后面加上L。 2. 进制转化 2.1. 十进制转任意进制&#xff1a; 十进制转任意进制时&#xff…...

k8s 学习笔记之 k8s 存储管理

文章目录 概述卷卷的常用类型emptyDir边车容器 HostPathnfsPV/PVC静态供给 PV 和 PVC创建静态 PV创建 pvc创建 pod 应用 pvc 动态供给 PV 和 PVC创建 StorageClass创建 pvc创建 pod 使用 pvc PV 的生命周期 内置存储对象ConfigMapSecret 配置文件自动重新加载方案**1. 应用内动…...

ios swift开发--ios远程推送通知配置

远程推送通知&#xff08;Push Notifications&#xff09;在 iOS 平台上是免费提供的&#xff0c;但需要一些准备工作。以下是开通和使用远程推送通知的基本步骤&#xff1a; 开通远程推送通知 注册 Apple Developer Program&#xff1a; 访问 Apple Developer 并注册一个开发…...

【JavaEE进阶】CSS

本节⽬标 掌握 CSS 基本语法规范和CSS选择器的各种⽤法, 熟练使⽤CSS的常⽤属性. 一.CSS介绍 1.什么是CSS? CSS(Cascading Style Sheet)&#xff0c;层叠样式表, ⽤于控制⻚⾯的样式. CSS 能够对⽹⻚中元素位置的排版进⾏像素级精确控制, 实现美化⻚⾯的效果. 能够做到⻚⾯…...

基于Java Springboot宠物领养救助平台

一、作品包含 源码数据库设计文档万字PPT全套环境和工具资源部署教程 二、项目技术 前端技术&#xff1a;Html、Css、Js、Vue、Element-ui 数据库&#xff1a;MySQL 后端技术&#xff1a;Java、Spring Boot、MyBatis 三、运行环境 开发工具&#xff1a;IDEA/eclipse 数据…...

C/C++ 中有哪些类型转换方式? 分别有什么区别?

在C编写C/C代码的时候&#xff0c;我们经常会遇到发生类型转换的场景&#xff0c;比如 赋值运算符的两个操作数不同、实参和形参类型不同、函数返回值类型和接收返回值的类型不同&#xff0c;都会发生类型转换&#xff1b;所以&#xff0c;在C语言中提供了两种类型转换 —— 隐…...

小程序租赁系统开发为企业提供高效便捷的租赁服务解决方案

内容概要 在这个数字化飞速发展的时代&#xff0c;小程序租赁系统应运而生&#xff0c;成为企业管理租赁业务的一种新选择。随着移动互联网的普及&#xff0c;越来越多的企业开始关注如何利用小程序来提高租赁服务的效率和便捷性。小程序不仅可以为用户提供一个快速、易用的平…...

Scala的Array

数组&#xff1a;物理空间上连续的&#xff08;一个挨一个&#xff09; 优势&#xff1a;根据下标&#xff0c;能快速找到元素 列表&#xff1a;物理空间上不连续&#xff08;不是一个元素挨着一个元素&#xff09; 优势&#xff1a;插入元素&#xff0c;删除比较快 object…...

等保测评怎么做?具体流程是什么?

等保测评是对信息系统进行等保&#xff08;等级保护&#xff09;安全评测的过程。等保是指对信息系统进行等级化保护管理&#xff0c;目的是提高信息系统的安全性&#xff0c;防止信息泄露、篡改、破坏等安全问题。哈尔滨等保测评按照《中华人民共和国网络安全法》及《信息安全…...

基于YOLOv8深度学习的汽车车身车损检测系统研究与实现(PyQt5界面+数据集+训练代码)

本文研究并实现了一种基于YOLOV8深度学习模型的汽车车身车损检测系统&#xff0c;旨在解决传统车损检测中效率低、精度不高的问题。该系统利用YOLOV8的目标检测能力&#xff0c;在单张图像上实现了车身损坏区域的精确识别和分类&#xff0c;尤其是在车身凹痕、车身裂纹和车身划…...

力扣 LeetCode 144. 二叉树的前序遍历(Day6:二叉树)

解题思路&#xff1a; 方法一&#xff1a;递归&#xff08;中左右&#xff09; class Solution {List<Integer> res new ArrayList<>();public List<Integer> preorderTraversal(TreeNode root) {recur(root);return res;}public void recur(TreeNode roo…...

Adobe Illustrator(Ai)修图软件入门操作参考,收集查过的各个细节用法

到现在&#xff0c;对于Ai的使用也是一半一半&#xff0c;基本上都是用到啥就查啥。因为用得也不是很频繁&#xff0c;脑子也记不住很多操作&#xff0c;所以有时候靠肌肉记忆&#xff0c;很多时候&#xff0c;得再百度一遍…… 所以 我在这再备份一下&#xff0c;做个搬运工 …...

Apache Paimon、Apache Hudi、Apache Iceberg对比分析

Apache Paimon、Apache Hudi、Apache Iceberg 都是面向大数据湖的表格式存储管理框架。它们各自的架构、数据管理方式以及适用场景有所不同。下面是对三者的详细对比分析: 1. 基本简介 Apache Paimon: Paimon 是一个新兴的数据湖存储引擎,旨在支持流批一体的数据处理和管理…...

[ 网络安全介绍 5 ] 为什么要学习网络安全?

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…...

生产环境centos8 Red Hat8部署ansible and 一键部署mysql两主两从ansible脚本预告

一、各节点服务器创建lvm逻辑卷组 1.初始化磁盘为物理卷&#xff08;PV&#xff09; 命令&#xff1a;sudo pvcreate /dev/vdb 2.创建卷组&#xff08;VG&#xff09; 命令&#xff1a;sudo vgcreate db_vg /dev/vdb 3.创建逻辑卷&#xff08;LV&#xff09; 命令&#xff1a;s…...

华为云stack网络服务流量走向

1.同VPC同子网同主机内ECS间互访流量走向 一句话通过主机内部br-int通信 2.同VPC同子网跨主机ECS间互访流量走向 3.同VPC不同子网同主机ECS间互访流量走向 查看ECS配置文件底层KVM技术 查看日志 查看ECS的ID号&#xff08;管理员身份查询所有租户信息&#xff09; 查看ECS的其…...

嵌入式硬件杂谈(二)-芯片输入接入0.1uf电容的本质(退耦电容)

引言&#xff1a;对于嵌入式硬件这个庞大的知识体系而言&#xff0c;太多离散的知识点很容易疏漏&#xff0c;因此对于这些容易忘记甚至不明白的知识点做成一个梳理&#xff0c;供大家参考以及学习&#xff0c;本文主要针对芯片输入接入0.1uf电容的本质的知识点的进行学习。 目…...

计算机网络HTTP——针对实习面试

目录 计算机网络HTTP什么是HTTP&#xff1f;HTTP和HTTPS有什么区别&#xff1f;分别说明HTTP/1.0、HTTP/2.0、HTTP/3.0请说明访问网页的全过程请说明HTTP常见的状态码Cookie和Session有什么区别&#xff1f;HTTP请求方式有哪些&#xff1f;请解释GET和POST的区别&#xff1f;HT…...

java的for循环

public class Demo6 {public static void main(String[] args) {for (int money1;money<10;money){System.out.println("换一元纸币"money"张。换5角硬币"(10-money)*2"个");}} }public class Demo8 {public static void main(String[] args)…...

ESP32 SPI性能调优指南:从80MHz时钟到DMA配置,避开那些坑

ESP32 SPI性能调优实战&#xff1a;突破80MHz时钟与DMA配置的终极指南 当你在ESP32项目中遇到SPI通信速度瓶颈时&#xff0c;是否曾为如何突破80MHz时钟限制而苦恼&#xff1f;是否在配置DMA时踩过各种坑&#xff1f;本文将带你深入ESP32 SPI性能优化的核心领域&#xff0c;从硬…...

Claude Code 速查表

其中的&#xff1a;键盘快捷键常规控制Ctrl C&#xff1a;取消输入 / 生成Ctrl D&#xff1a;退出会话Ctrl L&#xff1a;清屏Ctrl O&#xff1a;切换详细输出Ctrl R&#xff1a;反向搜索历史Ctrl G&#xff1a;在编辑器中打开提示Ctrl B&#xff1a;后台运行任务Ctrl …...

sklearn分类指标实战:如何用precision_recall_curve优化你的模型效果

sklearn分类指标实战&#xff1a;如何用precision_recall_curve优化模型效果 在机器学习项目中&#xff0c;分类模型的评估往往比训练过程更考验数据科学家的专业素养。当你的模型在测试集上达到95%的准确率时&#xff0c;是否就意味着可以高枕无忧&#xff1f;现实情况往往复杂…...

AI编程助手太烧钱?试试这个‘外挂’:心灵宝石MCP服务在Cursor中的安装与长期使用心得

深度解析Cursor IDE中的MCP服务&#xff1a;心灵宝石的高效部署与实战技巧 作为一名全栈开发者&#xff0c;我几乎每天都要与代码编辑器打交道。从早期的Sublime Text到VS Code&#xff0c;再到如今集成了AI能力的Cursor&#xff0c;工具链的进化让开发效率不断提升。但随之而来…...

高效批处理:一键复制文件/文件夹至当前目录所有子文件夹

1. 为什么需要批量复制文件到子文件夹&#xff1f; 在日常工作中&#xff0c;我经常遇到这样的场景&#xff1a;需要把一个重要文件快速分发到几十甚至上百个子文件夹中。比如给每个项目文件夹添加一份新的规范文档&#xff0c;或者为所有客户目录更新同一份合同模板。手动操作…...

3步构建工业级语音数据集:从混乱录音到AI训练素材的蜕变之路

3步构建工业级语音数据集&#xff1a;从混乱录音到AI训练素材的蜕变之路 你是否还在为语音识别模型效果不佳而烦恼&#xff1f;是否采集了大量语音却不知如何转化为训练数据&#xff1f;本文将带你通过FunASR框架提供的标准化工具链&#xff0c;3步完成工业级语音数据集的构建…...

如何设计优雅的RESTful API:Blade框架完整指南

如何设计优雅的RESTful API&#xff1a;Blade框架完整指南 【免费下载链接】blade :rocket: Lightning fast and elegant mvc framework for Java8 项目地址: https://gitcode.com/gh_mirrors/bl/blade 想要在Java 8中快速构建高性能、优雅的RESTful API吗&#xff1f;B…...

通义千问多模态检索系统:图文视频混合输入全解析

通义千问多模态检索系统&#xff1a;图文视频混合输入全解析 1. 多模态检索的行业痛点与解决方案 在信息爆炸的时代&#xff0c;传统文本检索系统面临三大核心挑战&#xff1a; 跨模态匹配失效&#xff1a;用户用文字描述"红色跑车在沙漠驰骋"&#xff0c;系统却返…...

RVC 虚拟环境管理实战指南:解决三类核心运维问题

RVC 虚拟环境管理实战指南&#xff1a;解决三类核心运维问题 【免费下载链接】rvc RVC is a Linux console UI for vSphere, built on the RbVmomi bindings to the vSphere API. 项目地址: https://gitcode.com/gh_mirrors/rvc/rvc RVC&#xff08;Ruby vSphere Consol…...