高并发场景下限流算法实践与性能优化指南

限流指南封面

高并发场景下限流算法实践与性能优化指南

在大规模并发访问环境中,合理的限流策略能保护后端服务稳定运行,避免系统因瞬时高并发导致资源耗尽或崩溃。本文将从原理出发,深入解析几种主流限流算法,并结合Java和Redis给出完整可运行的代码示例,最后分享在生产环境中的性能优化建议。


一、技术背景与应用场景

随着业务流量激增,API网关、微服务接口等处于高并发流量的第一线。常见场景包括:

  • 短期秒级爆发流量,如秒杀、抢购场景
  • 持续大规模监控上报、日志埋点
  • 第三方系统突发调用

此时若无限流保护,系统可能出现线程池耗尽、数据库连接池耗尽、Redis阻塞等问题,导致服务异常甚至宕机。

二、核心原理深入分析

1. 固定窗口计数(Fixed Window)

思路:将时间切分为大小相同的固定窗口(如1秒),记录窗口内的请求计数,超过阈值拒绝。

优点:实现简单,计数开销低。

缺点:临界点易出现短时间内双倍阈值的突发量。

2. 滑动窗口计数(Sliding Window Counter)

思路:利用两个固定窗口,以及当前窗口的权重,平滑地计算限流。

实现:

  • 记录上一个窗口的计数 count_prev 和当前窗口的计数 count_cur
  • 按时间比例计算:total = count_prev * (1 - t/T) + count_cur

3. 滑动窗口日志(Sliding Window Log)

思路:记录每次请求的时间戳,通过检查日志中有效时间段的请求数判断是否超过阈值。

优点:精确;缺点:存储和遍历开销大,不适合超高频场景。

4. 令牌桶(Token Bucket)

思路:以固定速率往桶中添加令牌,请求到来先尝试取令牌,若有则放行,否则拒绝或等待。

优点:支持突发流量,可平滑输出。

5. 漏桶(Leaky Bucket)

思路:将请求排入“漏桶”队列,以固定速率处理队列中的请求;队列满则拒绝新请求。

与令牌桶的区别在于:漏桶保证输出速率固定,而令牌桶更灵活。


三、关键源码解读与示例

1. Guava RateLimiter(令牌桶实现)

import com.google.common.util.concurrent.RateLimiter;public class GuavaLimiterDemo {// 创建每秒产生 100 个令牌的令牌桶private static final RateLimiter limiter = RateLimiter.create(100);public boolean tryAcquire() {// 非阻塞立即获取令牌,返回是否获取成功return limiter.tryAcquire();}public static void main(String[] args) {GuavaLimiterDemo demo = new GuavaLimiterDemo();if (demo.tryAcquire()) {// 业务处理System.out.println("请求通过");} else {System.out.println("限流处理");}}
}

2. Redis 滑动窗口计数(Lua 原子操作)

文件:scripts/sliding_window.lua

-- KEYS[1] 主键,ARGV[1]=当前时间戳毫秒,ARGV[2]=窗口大小(毫秒),ARGV[3]=阈值
local key = KEYS[1]
local now = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local limit = tonumber(ARGV[3])-- 移除过期记录
redis.call('ZREMRANGEBYSCORE', key, 0, now - window)
-- 统计当前窗口请求数
local count = redis.call('ZCARD', key)
if count < limit then-- 记录本次请求redis.call('ZADD', key, now, now)-- 设置过期防止持久化redis.call('PEXPIRE', key, window)return 1
end
return 0

Java 调用示例:

public class RedisSlidingWindowLimiter {private final JedisPool jedisPool;private final String scriptSha1;public RedisSlidingWindowLimiter(JedisPool pool) {this.jedisPool = pool;try (Jedis jedis = jedisPool.getResource()) {scriptSha1 = jedis.scriptLoad(new String(Files.readAllBytes(Paths.get("scripts/sliding_window.lua"))));}}public boolean tryAcquire(String key, long windowMs, long limit) {try (Jedis jedis = jedisPool.getResource()) {Object res = jedis.evalsha(scriptSha1,Collections.singletonList(key),Arrays.asList(String.valueOf(System.currentTimeMillis()), String.valueOf(windowMs), String.valueOf(limit)));return Integer.valueOf(1).equals(res);}}
}

3. Spring Cloud Gateway 全局限流过滤器

@Configuration
public class GatewayRateLimiterConfig {@Beanpublic GlobalFilter rateLimiterFilter(RedisSlidingWindowLimiter limiter) {return (exchange, chain) -> {String requestKey = "gateway:" + exchange.getRequest().getPath();boolean pass = limiter.tryAcquire(requestKey, 1000, 200); // 1秒200次if (!pass) {exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);return exchange.getResponse().setComplete();}return chain.filter(exchange);};}
}

项目结构示例:

src/
├─ main/
│  ├─ java/
│  │  └─ com.example.limiter/
│  │     ├─ GuavaLimiterDemo.java
│  │     ├─ RedisSlidingWindowLimiter.java
│  │     └─ GatewayRateLimiterConfig.java
│  └─ resources/
│     └─ scripts/
│        └─ sliding_window.lua

四、实际应用示例

在电商秒杀场景,采用 Redis 滑动窗口限流:

  1. 用户请求进入API网关,先通过限流过滤器;
  2. 限流通过后,执行业务逻辑下单;
  3. 请求高峰时可动态调整阈值,或采用多级限流(API 网关、微服务内部双层)策略。

五、性能特点与优化建议

  1. 单机 vs 分布式:Guava 限流仅适用于单实例,多实例需借助 Redis 或 ZooKeeper 实现全局限流。
  2. 数据清理:滑动窗口日志方式需定期清理过期数据,否则内存/Redis 会堆积。
  3. Lua 原子性:使用 Redis + Lua 能保证高并发下的限流原子操作。
  4. 批量令牌:令牌桶算法可一次性发放一定数量令牌,减少系统调用开销。
  5. 阈值动态调整:结合监控(Prometheus)动态调整限流策略,避免过严或过松。
  6. 多级限流:前端网关 + 后端服务双层限流方案能增强系统鲁棒性。

总结与最佳实践

限流是高并发系统的核心防护手段。本文从固定窗口、滑动窗口到令牌桶、漏桶算法,结合 Java/Redis 和 Spring Cloud Gateway 给出了完整实现示例,并提出了多级限流、动态阈值、性能优化等实战建议。希望对构建稳定、高可用的后端限流体系有所帮助。

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

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

相关文章

Vue3应用执行流程详解

精确化的完整执行流程 (以 Vite Vue3 SPA 为例)整个过程可以分为两部分&#xff1a;首次访问的“冷启动”和后续的Vue应用接管。第一部分&#xff1a;首次访问与页面加载客户端&#xff1a;发送请求用户打开浏览器&#xff0c;输入 URL&#xff08;如 http://localhost:5173&a…

Redis 持久化与高可用实践(RDB / AOF / Sentinel / Cluster 全解析)

这篇是我把几套生产环境踩坑与复盘整理成的一份“从 0 到 1 长期可维护”的实践文。目标是&#xff1a;明确策略、给出默认可用的配置模板、把常见坑一次讲透。 适用场景&#xff1a;新项目选型、老项目稳定性加固、从单机迁移到 HA/Cluster、应对数据安全与故障切换要求。目录…

Linux内核的PER_CPU机制

参考书《Linux内核模块开发技术指南》 1.原理 在多核CPU的情况下&#xff0c;为了提高CPU并发执行的效率&#xff0c;对于某些不是必须要在核间进行同步访问的资源&#xff0c;可以为每一个CPU创建一个副本&#xff0c;让每个CPU都访问自身的数据副本&#xff0c;而不是通过加锁…

VSCode 的百度 AI编程插件

VSCode 的百度 AI编程插件主要是 Baidu Comate&#xff08;文心快码&#xff09;&#xff0c;这是一款基于文心大模型的新一代编码辅助工具&#xff0c;旨在提升开发者的编码效率&#xff0c;让写代码变得更简单。以下是关于 Baidu Comate 的详细介绍&#xff1a; 一、功能特点…

阿里云监控使用

阿里云的云监控服务&#xff08;CloudMonitor&#xff09;是一款简单易用、功能强大的监控工具&#xff0c;主要用来帮助用户实时监控阿里云上的各种资源&#xff08;比如服务器、数据库、网络等&#xff09;&#xff0c;并在出现问题时及时发出警报&#xff0c;确保业务稳定运…

嵌入式C语言-关键字typedef

定义和作用 typedef是C/C中的一个关键字&#xff0c;作用是为现有的数据类型&#xff08;int 、char 、flaot等&#xff09;创建新的别名&#xff0c;其目的是为了方便阅读和理解代码。 用法 typedef 原有类型名 新类型名;基本类型创建别名 typedef unsigned char uint8_t; typ…

【混合开发】【大前端++】Vue节点优化Dome之单节点轮播图片播放视频二

动图更精彩 背景 Vue作为大前端开发页面交互&#xff0c;在数字屏&#xff0c;智慧大屏等大屏幕开发过程中&#xff0c;轮播效果作为丰富的展示组件经常作为首选。但也因为这个组件的交互体验很好&#xff0c;于是各种单点组件增加到轮播效果里。经过业务的扩展&#xff0c;人…

前端开发核心技术与工具全解析:从构建工具到实时通信

觉得主包文章可以的,可以点个小爱心哟&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 主页:一位搞嵌入式的 genius-CSDN博客 系列文章专栏: https://blog.csdn.net/m0_73589512/category_13028539.html 前端开发核心技术与工具全解…

GPT 系列论文 gpt3-4 175B参数 + few-shot + 多模态输入 + RLHF + system

GPT&#xff0c;GPT-2&#xff0c;GPT-3 论文精读【论文精读】 GPT-4论文精读 从1750亿参数的文本预言家&#xff0c;到多模态的通用天才&#xff0c;OpenAI用两次震撼世界的发布&#xff0c;重新定义了人工智能的可能性边界。这份笔记将带你深入GPT-3和GPT-4的核心突破&#…

.gitignore文件的作用及用法

目录 ​​.gitignore 文件的作用​​ ​​.gitignore 的基本语法​​ ​​Python 项目的 .gitignore 示例​​ ​​如何使用 .gitignore​​ ​​1. 创建 .gitignore 文件​​ ​​2. 编辑 .gitignore​​ ​​3. 检查 Git 状态​​ ​​常见问题​​ ​​Q1&#xff…

QEMU环境准备

QEMU环境准备 下载 qemu # qemu sudo apt install qemu-system-arm # gdb sudo apt install gdb-multiarchsudo apt-get update sudo apt-get install build-essential zlib1g-dev pkg-config libglib2.0-dev \libpixman-1-dev libfdt-dev ninja-build下载并自行编译 qemu(可…

003 cargo使用

cargo是什么 cargo 是 Rust 的构建系统和包管理器。Rust 开发者常用 cargo 来管理 Rust 工程和获取工程所依赖的库。 在上一篇文章中我们已经使用cargo new命令创建了一个名叫hello_rust的项目。也使用cargo run来运行项目。 cargo常用命令 cargo 除了创建工程以外还具备构建&a…

跨省跨国监控难题破解:多层级运维的“中国解法”

在全球化的商业浪潮中&#xff0c;集团型客户的业务布局日益广泛&#xff0c;涉及跨省甚至跨国的多个分支机构和业务节点。这种跨域管理的模式给企业的运维监控带来了前所未有的挑战。多个分支机构和业务节点运维调整首先&#xff0c;不同地区的网络环境差异巨大。从国内不同省…

pandas读取复合列名列头及数据和处理

pandas读取复合列名列头及数据和处理1. 效果图2. 源代码1. 效果图 原始excel&#xff1a; 读取1&#xff0c;2行为复合表头&#xff1a; 读取序号为1003一整行的数据&#xff0c;以及获取序号为1002行及1003行的C列复合表头列的值&#xff1a; 2. 源代码 import pandas …

制作一个简单的vscode插件

当前环境情况 操作系统&#xff1a;Windows 项目类型&#xff1a;VS Code 插件&#xff08;TypeScript 编写&#xff09; Node.js 版本&#xff1a;20.18.1 yarn 版本&#xff1a;1.22.22 npm 版本&#xff1a;10.8.2 npm registry&#xff1a;huawei ------- https://repo.hua…

分布式专题——10.2 ShardingSphere-JDBC分库分表实战与讲解

1 分库分表案例 下面实现一个分库分表案例&#xff0c;将一批课程信息分别拆分到两个库&#xff0c;四个表中&#xff1a; 需提前准备一个 MySQL 数据库&#xff0c;并在其中创建 Course 表。Course 表的建表语句如下&#xff1a; CREATE TABLE course (cid bigint(0) NOT N…

Digital Clock 4,一款免费的个性化桌面数字时钟

Digital Clock 4&#xff0c;一款免费的个性化桌面数字时钟 ** 功能 ** &#xff1a;一款免费的桌面数字时钟工具&#xff0c;支持多种皮肤、透明度调节和字体样式自定义&#xff0c;时钟可自由拖动&#xff0c;支持设置闹钟、定时关机、显示自定义消息等功能&#xff0c;适合想…

学习Python是一个循序渐进的过程,结合系统学习、持续实践和项目驱动,

学习Python是一个循序渐进的过程&#xff0c;结合系统学习、持续实践和项目驱动&#xff0c;你会掌握得更好。下面我为你梳理了一个分阶段的学习路线和实用建议&#xff0c;希望能帮你高效入门并逐步提升。 &#x1f40d; Python学习指南&#xff1a;从入门到精通 &#x1f5…

vcpkg:面向C/C++的跨平台库管理工具软件配置笔记经验教程

1、什么是vcpkg 对于使用过Python进行程序设计的开发者们&#xff0c;大多都会对Python的各种库和依赖&#xff0c;仅仅通过几条简单命令行就完成配置的操作感到惊叹&#xff0c;非常的省事省力。反倒是C/C开发时&#xff0c;要是每个库都要自己下载源码编译或者对环境进行配置…

【Docker】常用帮忙、镜像、容器、其他命令合集(2)

【Docker】常用帮忙、镜像、容器、其他命令合集&#xff08;2&#xff09;博主有话说容器命令新建容器并启动列出所有的运行的容器退出容器docker run -it centos:7.0.1406 /bin/bash指令解析docker exec -it ... bash 、docker run -it ... bash、docker attach [容器] 的exit…