凭着十年云转型实战,站在AI的风口上,金蝶向上增长的动能更为显著。2025年,金蝶“AI优先、订阅优先”核心战略持续生效,上半年,云服务收入约人民币2...
2025-08-12 0
在互联网软件开发领域,随着业务规模的不断扩大和用户量的持续增长,系统面临的流量压力日益增大。对于基于 SpringBoot3 构建的应用系统而言,合理的限流策略成为了保障系统稳定运行、防止因流量过载而导致服务崩溃的关键手段。今天,我们就来深入探讨一下 SpringBoot3 中常用的几种限流算法,帮助各位开发者更好地应对高并发场景下的流量挑战。
(一)算法原理
固定窗口算法是最为基础且简单的限流算法。它将时间划分为一个个固定长度的窗口,在每个窗口内,系统会对请求进行计数。当请求到达时,计数器增加 1,如果在当前窗口内计数器的值超过了预先设定的阈值,后续的请求就会被拒绝。直到这个固定窗口结束,计数器清零,新的窗口开始,计数过程重新开始。
例如,设定固定窗口时长为 1 分钟,限流阈值为 100 次请求。在这 1 分钟内,每收到一个请求,计数器就加 1,当计数器达到 100 时,后续请求都将被系统拒绝,直到下一分钟,计数器归零,重新计数。
(二)实现方式
在 SpringBoot3 项目中,可以借助 Redis 来实现固定窗口限流算法。我们可以利用 Redis 的原子自增操作来实现计数器功能。当一个请求到达时,通过 Redis 的 INCR 命令对指定的计数器键值进行自增操作。同时,设置该键值的过期时间为固定窗口的时长。如果自增后的结果超过了限流阈值,则拒绝该请求。
代码示例如下:
@RestControllerpublic class FixedWindowController { @Autowired private StringRedisTemplate stringRedisTemplate; private static final String FIXED_WINDOW_KEY = "fixed_window_limit"; private static final int LIMIT_THRESHOLD = 100; // 限流阈值 private static final long WINDOW_DURATION = 60; // 窗口时长,单位秒 @GetMapping("/fixedWindow") public String fixedWindow() { String key = FIXED_WINDOW_KEY; // 使用Redis的INCR命令对计数器进行自增 Long count = stringRedisTemplate.opsForValue().increment(key, 1); if (count == 1) { // 如果是第一次计数,设置键值的过期时间为窗口时长 stringRedisTemplate.expire(key, WINDOW_DURATION, TimeUnit.SECONDS); } if (count > LIMIT_THRESHOLD) { // 如果超过限流阈值,返回提示信息 return "请求过于频繁,请稍后再试"; } return "请求成功"; }}
(三)优缺点分析
优点
缺点
(一)算法原理
滑动窗口算法是对固定窗口算法的优化。它将固定窗口进一步细分,把一个大的时间窗口划分为多个小的子窗口,每个子窗口都有自己独立的计数器。随着时间的推移,窗口像滑动一样移动,每次移动一个子窗口的时间间隔。系统通过统计滑动窗口内所有子窗口的计数器之和来判断是否达到限流阈值。
例如,将 1 分钟的大窗口划分为 60 个 1 秒的子窗口。在每个子窗口内,对到达的请求进行计数。当窗口滑动时,最旧的子窗口的计数被移除,新的子窗口加入统计范围。这样可以更精确地控制流量,避免固定窗口算法在窗口切换时出现的临界问题。
(二)实现方式
同样可以基于 Redis 来实现滑动窗口限流算法。我们可以使用 Redis 的有序集合(Sorted Set)来存储每个子窗口的请求计数。有序集合的成员是子窗口的时间戳,分值是该子窗口内的请求数量。
代码示例如下:
@RestControllerpublic class SlidingWindowController { @Autowired private StringRedisTemplate stringRedisTemplate; private static final String SLIDING_WINDOW_KEY = "sliding_window_limit"; private static final int LIMIT_THRESHOLD = 100; // 限流阈值 private static final long WINDOW_DURATION = 60; // 窗口时长,单位秒 private static final long SUB_WINDOW_DURATION = 1; // 子窗口时长,单位秒 @GetMapping("/slidingWindow") public String slidingWindow() { String key = SLIDING_WINDOW_KEY; long now = System.currentTimeMillis() / 1000; // 当前子窗口的时间戳 long currentSubWindow = now - now % SUB_WINDOW_DURATION; // 使用Redis的ZINCRBY命令增加当前子窗口的计数 stringRedisTemplate.opsForZSet().incrementScore(key, currentSubWindow, 1); // 移除过期的子窗口 long startTime = now - WINDOW_DURATION; stringRedisTemplate.opsForZSet().removeRangeByScore(key, 0, startTime); // 统计滑动窗口内的请求总数 Set<ZSetOperations.TypedTuple<String>> tuples = stringRedisTemplate.opsForZSet() .rangeByScoreWithScores(key, startTime, now); long count = tuples.stream().mapToLong(ZSetOperations.TypedTuple::getScore).sum(); if (count > LIMIT_THRESHOLD) { return "请求过于频繁,请稍后再试"; } return "请求成功"; }}
(三)优缺点分析
优点
缺点
(一)算法原理
令牌桶算法的核心思想是系统以固定的速率向一个虚拟的令牌桶中放入令牌,每个请求在执行前需要从令牌桶中获取一个令牌。如果令牌桶中有足够的令牌,请求可以顺利通过并消耗一个令牌;如果令牌桶为空,没有令牌可供请求获取,那么该请求将被拒绝或者等待,直到有新的令牌被放入桶中。
令牌桶具有一定的容量限制,当令牌生成的速率大于请求消耗令牌的速率时,令牌桶会逐渐被填满,直到达到桶的最大容量。此时,新生成的令牌将被丢弃,以保证令牌桶中的令牌数量不会超过其容量。
例如,设定令牌生成速率为每秒 10 个,令牌桶容量为 100 个。系统会每秒向令牌桶中放入 10 个令牌,当有请求到达时,请求尝试从桶中获取一个令牌。如果桶中有令牌,请求获取令牌后继续执行;如果桶为空,请求将被限流。
(二)实现方式
在 SpringBoot3 项目中,可以借助 Google Guava 库来实现令牌桶算法。Guava 库提供了 RateLimiter 类来方便地实现令牌桶限流。
代码示例如下:
@RestControllerpublic class TokenBucketController { private static final RateLimiter rateLimiter = RateLimiter.create(10); // 每秒生成10个令牌 @GetMapping("/tokenBucket") public String tokenBucket() { if (rateLimiter.tryAcquire()) { // 如果成功获取令牌,处理请求 return "请求成功"; } else { // 如果获取令牌失败,返回提示信息 return "请求过于频繁,请稍后再试"; } }}
(三)优缺点分析
优点
缺点
(一)算法原理
漏桶算法可以将请求看作是水流,将系统处理能力看作是一个底部有小孔的固定容量的水桶。请求像水流一样不断地流入漏桶,而漏桶则以固定的速率从底部的小孔流出,即系统以固定的速率处理请求。当流入的请求速率超过漏桶的流出速率时,由于漏桶的容量有限,多余的请求(即溢出的水)将被丢弃或者排队等待处理。
例如,假设漏桶的容量为 100,流出速率为每秒 10 个请求。当请求以每秒 15 个的速率流入时,漏桶会以每秒 10 个的速率处理请求,多余的每秒 5 个请求会被限流,要么被丢弃,要么进入队列等待。
(二)实现方式
在 SpringBoot3 中,可以通过自定义过滤器和队列来模拟漏桶算法的实现。我们可以使用一个阻塞队列来存储请求,通过控制从队列中取出请求的速率来模拟漏桶的流出速率。
代码示例如下:
@Componentpublic class LeakyBucketFilter implements Filter { private static final int BUCKET_CAPACITY = 100; // 漏桶容量 private static final int LEAK_RATE = 10; // 漏桶流出速率,单位:请求/秒 private final BlockingQueue<ServletRequest> requestQueue = new ArrayBlockingQueue<>(BUCKET_CAPACITY); private final ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); @Override public void init(FilterConfig filterConfig) throws ServletException { // 定时从队列中取出请求进行处理,模拟漏桶的流出 executorService.scheduleAtFixedRate(() -> { try { requestQueue.take(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } }, 0, 1000 / LEAK_RATE, TimeUnit.MILLISECONDS); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { if (requestQueue.offer((ServletRequest) servletRequest)) { filterChain.doFilter(servletRequest, servletResponse); } else { ((HttpServletResponse) servletResponse).sendError(HttpServletResponse.SC_TOO_MANY_REQUESTS, "请求过于频繁,请稍后再试"); } } @Override public void destroy() { executorService.shutdown(); }}
(三)优缺点分析
优点
缺点
不同的限流算法各有优缺点,在实际应用中,我们需要根据具体的业务场景和需求来选择合适的限流算法。以下是对这几种常用限流算法的对比总结:
限流算法 | 优点 | 缺点 | 适用场景 |
固定窗口算法 | 实现简单、资源消耗低 | 临界问题明显、限流不够平滑 | 流量相对平稳、对限流精度要求不高的场景 |
滑动窗口算法 | 解决临界问题、适应流量变化 | 实现复杂度增加、资源消耗增加 | 流量波动较大、对限流精度要求较高的场景 |
令牌桶算法 | 支持突发流量、限流效果平滑 | 实现复杂度较高、对时间精度要求高 | 存在突发流量、对系统稳定性要求较高的场景 |
漏桶算法 | 有效平滑流量、简单易懂 | 无法应对突发流量、资源利用率较低 | 对流量稳定性要求高、对突发流量处理能力要求不高的场景 |
例如,如果是一个电商平台的秒杀活动,由于会在短时间内产生大量的突发请求,并且需要保证系统能够在高并发下稳定运行,此时令牌桶算法可能是比较合适的选择;而对于一个提供稳定数据查询服务的接口,流量相对平稳,对系统资源消耗较为敏感,固定窗口算法或漏桶算法可能就能够满足需求。
在 SpringBoot3 开发中,合理选择和应用限流算法对于保障系统的稳定性和可靠性至关重要。通过对固定窗口算法、滑动窗口算法、令牌桶算法和漏桶算法的深入了解,我们可以根据不同的业务场景和流量特点,灵活选择最合适的限流策略,有效应对高并发流量带来的挑战,为用户提供更加稳定、高效的服务。希望本文能够帮助各位互联网软件开发人员在实际项目中更好地运用限流算法,提升系统的性能和用户体验。
相关文章
凭着十年云转型实战,站在AI的风口上,金蝶向上增长的动能更为显著。2025年,金蝶“AI优先、订阅优先”核心战略持续生效,上半年,云服务收入约人民币2...
2025-08-12 0
亲,这款游戏可以开挂的,确实是有挂的,很多玩家在这款游戏中打牌都会发现很多用户的牌特别好,总是好牌,而且好像能看到-人的牌一样。所以很多小伙伴就怀疑这...
2025-08-12 0
你真的了解“AI味”的判定逻辑吗?它是算法的偏见,还是内容的共性?本文将带你深入解析“AI率”的计算机制、平台标准与背后隐忧,揭示那些让人“闻风丧胆”...
2025-08-12 0
金融界2025年8月12日消息,国家知识产权局信息显示,禹州七方超硬材料制品有限公司取得一项名为“一种新型金刚石串珠”的专利,授权公告号CN22321...
2025-08-12 0
在刚刚落幕的2025世界机器人大会上,微亿智造凭借工业具身智能机器人的突破性创新与商业化实践,从百余家参评企业中强势突围,成功斩获"2025中国最具成...
2025-08-12 0
还在送外卖的兄弟姐妹们,近日在商圈附近正在等单的骑手们闲聊,不管是专送还是众包都有份,具体如下:首先是美团。(1)关于派单:派单分为系统派单和商家派单...
2025-08-12 0
我们一直都说,回音壁这种品类,和电视是密不可分的,所以在当用户对于视听娱乐需求越来越高之际,不但能推动中高端电视市场的发展,同时也会带动回音壁这类产品...
2025-08-12 0
据多家美国媒体报道,美国交通部长兼国家航空航天局代理局长肖恩·达菲近日将宣布,美国将加快推进在月球上建设核反应堆的计划。这是达菲自今年被任命为代理局长...
2025-08-12 0
发表评论