JAVA限流方法

在 Java 项目中限制短时间内的频繁访问(即接口限流),是保护系统资源、防止恶意攻击或高频请求导致过载的重要手段。常见实现方案可分为单机限流分布式限流,以下是具体实现方式:

一、核心限流算法

无论哪种方案,底层通常基于以下算法:

  1. 固定窗口计数器:将时间划分为固定窗口(如 1 秒),统计窗口内请求数,超过阈值则拒绝。
    • 优点:简单易实现;缺点:窗口交界处可能出现 “突增流量”(如窗口边缘允许双倍阈值请求)。
  2. 滑动窗口:将固定窗口拆分为多个小窗口,实时滑动计算请求数,解决临界问题。
  3. 令牌桶:匀速生成令牌放入桶中,请求需获取令牌才能处理,支持突发流量(桶内令牌可累积)。
  4. 漏桶:请求先进入桶中,系统以固定速率处理,平滑流量波动(不支持突发流量)。

二、单机限流实现(适用于单实例服务)

1. 基于 Guava 的 RateLimiter(令牌桶算法)

Guava 提供了现成的RateLimiter工具类,适合快速实现单机限流。

依赖引入

<dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>31.1-jre</version>
</dependency>

代码示例(结合 Spring 拦截器)

// 1. 定义限流拦截器
public class RateLimitInterceptor implements HandlerInterceptor {// 每秒允许10个请求(令牌桶算法)private final RateLimiter rateLimiter = RateLimiter.create(10.0);@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 尝试获取令牌,无令牌则拒绝if (!rateLimiter.tryAcquire()) {response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());response.getWriter().write("请求过于频繁,请稍后再试");return false;}return true;}
}// 2. 注册拦截器(Spring配置)
@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {// 对指定路径生效(如所有接口)registry.addInterceptor(new RateLimitInterceptor()).addPathPatterns("/**");}
}
2. 基于滑动窗口的自定义实现

适合需要更精细控制的场景(如按 IP 限流):

public class SlidingWindowLimiter {// 窗口大小(毫秒)private final long windowSize;// 窗口内最大请求数private final int maxRequests;// 记录每个时间片的请求数(key:时间片起始时间,value:请求数)private final ConcurrentHashMap<Long, Integer> timeSliceCounts = new ConcurrentHashMap<>();public SlidingWindowLimiter(long windowSize, int maxRequests) {this.windowSize = windowSize;this.maxRequests = maxRequests;}public synchronized boolean tryAcquire() {long now = System.currentTimeMillis();// 计算当前窗口的起始时间long windowStart = now - windowSize;// 移除过期的时间片timeSliceCounts.keySet().removeIf(timestamp -> timestamp < windowStart);// 统计当前窗口总请求数int totalRequests = timeSliceCounts.values().stream().mapToInt(Integer::intValue).sum();if (totalRequests < maxRequests) {// 记录当前时间片的请求(精确到100ms,可调整精度)long currentSlice = now - (now % 100);timeSliceCounts.put(currentSlice, timeSliceCounts.getOrDefault(currentSlice, 0) + 1);return true;}return false;}
}// 使用示例(在Controller中)
@RestController
public class TestController {// 10秒内最多允许5次请求(按IP限流)private final Map<String, SlidingWindowLimiter> ipLimiters = new ConcurrentHashMap<>();@GetMapping("/test")public String test(HttpServletRequest request) {String ip = request.getRemoteAddr();// 为每个IP创建独立的限流器SlidingWindowLimiter limiter = ipLimiters.computeIfAbsent(ip, k -> new SlidingWindowLimiter(10000, 5));if (!limiter.tryAcquire()) {return "IP:" + ip + " 请求过于频繁";}return "请求成功";}
}

三、分布式限流(适用于多实例集群)

单机限流无法跨服务实例共享状态,分布式场景需借助中间件(如 Redis)实现全局计数。

基于 Redis + Lua 脚本(滑动窗口算法)

利用 Redis 的原子性和 Lua 脚本保证限流逻辑的一致性:

Lua 脚本(限流逻辑)

-- 限流key(如:接口名:IP)
local key = KEYS[1]
-- 窗口大小(毫秒)
local windowSize = tonumber(ARGV[1])
-- 最大请求数
local maxRequests = tonumber(ARGV[2])
-- 当前时间
local now = tonumber(ARGV[3])-- 窗口起始时间
local windowStart = now - windowSize-- 移除窗口外的请求记录
redis.call('ZREMRANGEBYSCORE', key, 0, windowStart)
-- 统计当前窗口内的请求数
local currentCount = redis.call('ZCARD', key)if currentCount < maxRequests then-- 记录当前请求时间戳redis.call('ZADD', key, now, now .. ':' .. math.random())-- 设置key过期时间(避免内存泄漏)redis.call('EXPIRE', key, windowSize / 1000 + 1)return 1  -- 允许请求
endreturn 0  -- 拒绝请求

Java 代码调用

@Component
public class RedisRateLimiter {@Autowiredprivate StringRedisTemplate redisTemplate;// 加载Lua脚本private final DefaultRedisScript<Long> limitScript;public RedisRateLimiter() {limitScript = new DefaultRedisScript<>();limitScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("limit.lua")));limitScript.setResultType(Long.class);}/*** 尝试获取请求权限* @param key 限流标识(如:"api:test:192.168.1.1")* @param windowSize 窗口大小(毫秒)* @param maxRequests 最大请求数* @return 是否允许*/public boolean tryAcquire(String key, long windowSize, int maxRequests) {Long result = redisTemplate.execute(limitScript,Collections.singletonList(key),String.valueOf(windowSize),String.valueOf(maxRequests),String.valueOf(System.currentTimeMillis()));return result != null && result == 1;}
}// 在Controller中使用
@RestController
public class TestController {@Autowiredprivate RedisRateLimiter redisRateLimiter;@GetMapping("/test")public String test(HttpServletRequest request) {String ip = request.getRemoteAddr();String key = "api:test:" + ip;// 10秒内最多5次请求boolean allowed = redisRateLimiter.tryAcquire(key, 10000, 5);if (!allowed) {return "请求过于频繁,请稍后再试";}return "请求成功";}
}

四、成熟框架推荐

生产环境中,推荐使用现成的限流框架简化开发:

  1. Sentinel:阿里开源的流量控制框架,支持限流、熔断、降级,可通过注解或配置中心动态调整规则。
  2. Resilience4j:轻量级熔断限流框架,支持令牌桶、滑动窗口等多种算法,适合 Spring Boot 项目。
  3. Spring Cloud Gateway:网关层限流(如基于 Redis 的RequestRateLimiter过滤器),适合在入口层统一限流。

总结

  • 单机服务:优先使用 Guava 的RateLimiter或自定义滑动窗口(简单场景)。
  • 分布式服务:必须基于 Redis 等中间件实现全局限流,配合 Lua 脚本保证原子性。
  • 复杂场景:直接集成 Sentinel 等成熟框架,减少重复开发并支持动态配置。

根据业务需求(如限流粒度:IP / 用户 / 接口、是否允许突发流量)选择合适的方案即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/94294.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/94294.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

性能比拼: .NET (C#) vs. Fiber (Go)

本内容是对知名性能评测博主 Anton Putra .NET (C#) vs. Fiber (Go): Performance (Latency - Throughput - Saturation - Availability) 内容的翻译与整理, 有适当删减, 相关指标和结论以原作为准 在本视频中&#xff0c;我们将对比 C# 与 .NET 框架和 Golang 的表现。在第一个…

信誉代币的发行和管理机制是怎样的?

信誉代币的发行与管理机制是区块链技术与经济模型深度融合的产物&#xff0c;其核心在于通过代码和社区共识构建可量化、可验证的信任体系。以下从技术架构、经济模型、治理机制三个维度展开分析&#xff0c;并结合具体案例说明&#xff1a;一、发行机制&#xff1a;行为即价值…

神经网络|(十二)概率论基础知识-先验/后验/似然概率基本概念

【1】引言 前序学习进程中&#xff0c;对贝叶斯公式曾经有相当粗糙的回归&#xff0c;实际上如果我们看教科书或者网页&#xff0c;在讲贝叶斯公式的时候&#xff0c;会有几个名词反复轰炸&#xff1a;先验概率、后验概率、似然概率。 今天就来把它们解读一下&#xff0c;为以…

使用UE5开发《红色警戒3》类战略养成游戏的硬件配置指南

从零开始&#xff0c;学习 虚幻引擎5&#xff08;UE5&#xff09;&#xff0c;开始游戏开发之旅&#xff01;本文章仅提供学习&#xff0c;切勿将其用于不法手段&#xff01;开发类似《红色警戒3》级别的战略养成游戏&#xff0c;其硬件需求远超普通2D或小型3D项目——这类游戏…

Vue2+Vue3前端开发_Day12-Day14_大事件管理系统

参考课程: 【黑马程序员 Vue2Vue3基础入门到实战项目】 [https://www.bilibili.com/video/BV1HV4y1a7n4] ZZHow(ZZHow1024) 项目收获 Vue3 composition APIPinia / Pinia 持久化处理Element Plus&#xff08;表单校验&#xff0c;表格处理&#xff0c;组件封装&#xff09…

[ACTF新生赛2020]明文攻击

BUUCTF在线评测BUUCTF 是一个 CTF 竞赛和训练平台&#xff0c;为各位 CTF 选手提供真实赛题在线复现等服务。https://buuoj.cn/challenges#[ACTF%E6%96%B0%E7%94%9F%E8%B5%9B2020]%E6%98%8E%E6%96%87%E6%94%BB%E5%87%BB下载查看&#xff0c;一个压缩包和一张图片。压缩包需要密…

关于日本服务器的三种线路讲解

租用日本服务器时&#xff0c;哪种线路选择更适合?当初次接触跨境业务的站长们着手租用日本服务器时&#xff0c;会发现不同服务商提供的网络线路五花八门&#xff0c;从陌生的运营商名称到复杂的技术参数&#xff0c;常常使其感到眼花缭乱。为了帮助大家理清思路&#xff0c;…

【大白话解析】 OpenZeppelin 的 MerkleProof 库:Solidity 默克尔证明验证工具全指南​​(附源代码)

🧩 一、Merkle Tree 是什么?为什么要验证它? 想象你有一个名单,比如: ["Alice", "Bob", "Charlie", "Dave"] 你想让别人验证:“我(比如 Alice)是不是在这个名单里?”,但不想把整个名单都放在区块链上(太贵!)。 于是你…

机械学习综合练习项目

数据集合完整项目文件已经上传一、项目介绍案例介绍 案例是针对“红酒.csv”数据集&#xff0c;在红葡萄酒质量分析的场景 中&#xff0c;利用多元线性回归来探索红葡萄酒的不同化学成分如何共同 影响其质量评分。在建立线性回归模型之后&#xff0c;当给出了红葡萄酒 的新的一…

第3篇:配置管理的艺术 - 让框架更灵活

前言 在前一章中&#xff0c;我们设计了强大的注解API。本章将深入探讨配置管理系统的设计&#xff0c;学习如何将注解中的声明式配置转换为运行时可用的配置对象。 配置管理的核心挑战 在我们的框架中&#xff0c;配置来源有三个层级&#xff1a;主要挑战&#xff1a; &#x…

发版混乱怎么规范

你是否经历过这种场景&#xff1a;临到发版&#xff0c;一堆功能代码挤在一起&#xff0c;测试分不清范围&#xff0c;修复一个Bug可能引发三个新Bug&#xff1f;发布过程像一场豪赌&#xff1f;问题的核心往往在于分支策略和流程的混乱。今天&#xff0c;我们就来建立一套在绝…

【golang长途旅行第30站】channel管道------解决线程竞争的好手

channel 为什么需要channel 使用全局变量加锁同步来解决goroutine的竞争&#xff0c;可以但不完美难以精确控制等待时间​&#xff08;主线程无法准确知道所有 goroutine 何时完成&#xff09;。全局变量容易引发竞态条件​&#xff08;即使加锁&#xff0c;代码复杂度也会增加…

苹果XR芯片介绍

苹果的 XR 芯片技术主要体现在 A 系列、M 系列处理器以及专为空间计算设计的 R1 协处理器中。以下从技术架构、产品迭代和综合对比三个维度展开分析&#xff1a;一、技术架构解析1. A 系列芯片&#xff08;以 A12 Bionic 为例&#xff09;制程工艺&#xff1a;7nm&#xff08;台…

达梦数据库巡检常用SQL(三)

达梦数据库巡检常用SQL(三) 数据库SQL运行检查 数据库SQL运行检查 死锁的事务情况: SELECT TO_CHAR(HAPPEN_TIME,YYYY-MM-DD HH24:MI:SS) HAPPEN_TIME,SQL_TEXT FROM V$DEADLOCK_HISTORY WHERE HAPPEN_TIME >DATEADD(DAY,-30,

基于SpringBoot的校园周边美食探索及分享平台

1. 项目简介 项目名称&#xff1a;校园周边美食探索及分享平台 项目背景&#xff1a;针对校园师生对周边美食信息的需求&#xff0c;构建一个集美食推荐、鉴赏、评论互动及社交功能于一体的平台&#xff0c;帮助用户发现优质美食资源并进行分享交流。 主要目标&#xff1a; 提供…

Go数据结构与算法-常见的排序算法

虽然看过别人写了很多遍&#xff0c;而且自己也写过很多遍&#xff08;指的是笔记&#xff09;&#xff0c;但是还是要写的就是排序算法。毕竟是初学Go语言&#xff0c;虽然之前写过&#xff0c;但是还是打算再写一遍。主要包括插入排序、选择排序、冒泡排序、快速排序、堆排序…

第 6 篇:目标规则与负载均衡 - `DestinationRule` 详解

系列文章:《Istio 服务网格详解》 第 6 篇:目标规则与负载均衡 - DestinationRule 详解 本篇焦点: 深入理解 DestinationRule 的核心作用:定义流量在到达目的地之后的行为。 详细剖析其三大核心功能:服务子集 (Subsets), 流量策略 (Traffic Policy), TLS 设置。 动手实战…

一个简洁的 C++ 日志模块实现

一个简洁的 C 日志模块实现 1. 引言 日志功能在软件开发中扮演着至关重要的角色&#xff0c;它帮助开发者追踪程序执行过程、诊断问题以及监控系统运行状态。本文介绍一个使用 C 实现的轻量级日志模块&#xff0c;该模块支持多日志级别、线程安全&#xff0c;并提供了简洁易用…

C语言---数据类型

文章目录数据类型分类1. 基本类型 (Basic Types)a. 整数类型 (Integer Types)char (字符型)int (整型)short (短整型)long (长整型)long long (C99标准引入)图片汇总b. 浮点类型 (Floating-Point Types)float (单精度浮点型)double (双精度浮点型)long double (长双精度浮点型)…

本搭建乌云漏洞库

1.下载镜像站文件&#xff0c;并拖入虚拟机 2.将bugs.rar解压至网站根目录下 /var/www/html 3.配置bugs/conn.php 4.在bugs下创建upload目录&#xff0c;将10-14、15-a、15-b、16压缩包文件解压到该upload目录 5.把wooyun.rar解压到 /mysql/data/wooyun目录下 6.配置hosts文件后…