广州网站建设丿新科送推广wordpress主题的使用
2026/2/13 18:49:02 网站建设 项目流程
广州网站建设丿新科送推广,wordpress主题的使用,windows优化大师好用吗,鄱阳网站建设面试被问到限流算法#xff0c;很多面试官会让直接手写令牌桶和漏桶的实现。虽然平时用过Redis、Guava等现成的限流工具#xff0c;但真要手写还是有点慌。今天就来聊聊这两种经典限流算法的区别#xff0c;并用Java手写实现。 很多的限流工具底层都应用了它们 一、令牌桶…面试被问到限流算法很多面试官会让直接手写令牌桶和漏桶的实现。虽然平时用过Redis、Guava等现成的限流工具但真要手写还是有点慌。今天就来聊聊这两种经典限流算法的区别并用Java手写实现。很多的限流工具底层都应用了它们一、令牌桶 vs 漏桶核心区别令牌桶令牌桶的核心思想固定容量的桶以固定速率往桶里放令牌请求来了就从桶拿令牌没令牌就拒绝。有点像买票进站想去坐火车就先去售票窗口买票买到票了就凭票进入买不到等待因为窗口会定时的放票再去抢。下图是用Ai生成的大致能体现出这么个意思令牌桶特点1、可以处理突发流量桶里有令牌就能用因为并不是一直请求都很多但会一直以固定速率向桶里添加令牌请求少时桶内令牌满了请求激增可以满桶拿令牌顶一阵2、原理和实现上相对简单3、内存占用小漏桶适用场景接口限流保护业务系统或者敏感接口防止恶意攻击抵御Dos或DDos攻击……它的优势在于能够限制平均速率同时允许一定的突发流量漏桶漏桶的核心思想比令牌桶早更简单请求像水一样流入桶中桶以固定速率“漏水”处理请求超出桶容量的请求被丢弃或排队。漏桶的特点1、输出非常平滑稳定2、能有效保护下游系统流量平滑3、❌ 无法处理突发流量4、❌ 可能造成请求延迟漏桶适用场景数据库连接池保护数据库不被过载消息队列消费控制消费速率支付系统确保支付处理稳定性二、手写实现令牌桶实现public class TokenBucket { // 桶容量最大令牌数 privatefinallong capacity; // 令牌填充速率令牌/秒 privatefinallong refillRate; // 当前令牌数量 private AtomicLong tokens; // 上次填充时间戳纳秒 privatelong lastRefillTime; public TokenBucket(long capacity, long refillRate) { this.capacity capacity; this.refillRate refillRate; this.tokens new AtomicLong(capacity); this.lastRefillTime System.nanoTime(); } // 示例使用 public static void main(String[] args) throws InterruptedException { // 创建桶容量10令牌每秒填充5令牌 TokenBucket bucket new TokenBucket(10, 2); // 模拟请求 for (int i 1; i 50; i) { if (bucket.tryAcquire()) { System.out.println(请求 i : 通过); } else { System.out.println(请求 i : 限流); } Thread.sleep(100); // 100ms请求一次 } } /** * 尝试获取令牌 * * return true-获取成功false-被限流 */ public synchronized boolean tryAcquire() { refillTokens(); if (tokens.get() 0) { tokens.decrementAndGet(); returntrue; } returnfalse; } /** * 尝试获取多个令牌 * * param numTokens 请求令牌数 */ public synchronized boolean tryAcquire(int numTokens) { refillTokens(); if (tokens.get() numTokens) { tokens.addAndGet(-numTokens); returntrue; } returnfalse; } // 根据时间差补充令牌 private void refillTokens() { long now System.nanoTime(); // 计算时间差秒 double elapsedSec (now - lastRefillTime) * 1e-9; // 计算应补充的令牌数 long tokensToAdd (long) (elapsedSec * refillRate); if (tokensToAdd 0) { tokens.set(Math.min(capacity, tokens.get() tokensToAdd)); lastRefillTime now; } } }使用 AtomicLong 保证线程安全。通过时间差动态计算补充的令牌数。桶容量限制突发流量的最大值。漏桶实现import java.util.concurrent.atomic.AtomicLong; publicclass LeakyBucket { // 桶容量最大请求数 privatefinallong capacity; // 漏水速率请求/秒 privatefinallong leakRate; // 当前水量待处理请求数 private AtomicLong water; // 上次漏水时间戳毫秒 privatelong lastLeakTime; public LeakyBucket(long capacity, long leakRate) { this.capacity capacity; this.leakRate leakRate; this.water new AtomicLong(0); this.lastLeakTime System.currentTimeMillis(); } // 示例使用 public static void main(String[] args) throws InterruptedException { // 创建桶容量5请求每秒处理2请求 LeakyBucket bucket new LeakyBucket(5, 1); // 模拟请求 for (int i 1; i 15; i) { if (bucket.tryPass()) { System.out.println(请求 i : 通过 (当前水位: bucket.water.get() )); } else { System.out.println(请求 i : 限流 (水位溢出)); } Thread.sleep(200); // 200ms请求一次 } } /** * 尝试通过漏桶 * * return true-允许通过false-被限流 */ public synchronized boolean tryPass() { leakWater(); if (water.get() capacity) { water.incrementAndGet(); returntrue; } returnfalse; } // 根据时间差漏水 private void leakWater() { long now System.currentTimeMillis(); // 计算时间差秒 long elapsedMs now - lastLeakTime; if (elapsedMs 0) { // 计算漏水量 long leaked (long) (elapsedMs * leakRate / 1000.0); if (leaked 0) { water.updateAndGet(cur - Math.max(0, cur - leaked)); lastLeakTime now; } } } }漏出速率固定确保请求处理平滑。水量超过容量时直接拒绝请求。三、测试对比public class RateLimiterTest { public static void main(String[] args) throws InterruptedException { // 测试令牌桶容量10每秒填充5个令牌 TokenBucket tokenBucket new TokenBucket(10, 5); // 测试漏桶容量10每秒漏出5个请求 LeakyBucket leakyBucket new LeakyBucket(10, 5); System.out.println( 令牌桶测试支持突发 ); testTokenBucket(tokenBucket); Thread.sleep(1000); System.out.println(\n 漏桶测试平滑输出 ); testLeakyBucket(leakyBucket); } private static void testTokenBucket(TokenBucket bucket) { // 模拟突发请求 for (int i 0; i 15; i) { boolean success bucket.tryConsume(1); System.out.printf(请求%d: %s (当前令牌: %.1f)%n, i 1, success ? 通过 : 拒绝, bucket.getCurrentTokens()); } } private static void testLeakyBucket(LeakyBucket bucket) { // 模拟突发请求 for (int i 0; i 15; i) { boolean success bucket.tryConsume(); System.out.printf(请求%d: %s (当前水量: %.1f)%n, i 1, success ? 通过 : 拒绝, bucket.getCurrentWater()); } } }四、面试要点总结面试官可能会问的问题Q: 两种算法的核心区别是什么A: 令牌桶允许突发漏桶强制平滑输出Q: 什么场景用令牌桶什么场景用漏桶A: 需要处理突发用令牌桶需要保护下游用漏桶Q: 如何选择桶的容量和速率A: 根据业务峰值、系统承载能力、用户体验综合考虑Q: 分布式环境下如何实现A: 可以用Redis实现或者用一致性哈希分片说在后边手写限流算法是一般在高级别的面试中不太会出现但它们的基础概念要掌握在考场景题时它们都是不错的方案。简单记令牌桶像ATM机有钱就能取漏桶像水龙头固定流速出水。完活

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询