02-限流熔断详解

张开发
2026/4/16 13:35:50 15 分钟阅读

分享文章

02-限流熔断详解
限流熔断详解一、知识概述限流和熔断是系统自我保护的两大核心机制。限流防止系统过载,熔断防止级联故障。两者结合,构建系统的"免疫系统"。核心目标:保护系统不被压垮防止故障扩散保证核心服务可用提供友好的降级体验适用场景:流量突增(营销活动、热点事件)下游服务故障资源耗尽(CPU、内存、连接池)第三方服务不可用二、知识点详细讲解2.1 限流算法2.1.1 固定窗口算法原理:在固定时间窗口内限制请求数量 ┌─────────────────────────────────────┐ │ 时间窗口(1秒) │ │ │ │ ▓▓▓▓▓▓▓▓▓▓░░░░░░░░░░ │ │ 10个请求(限制) │ │ │ │ T0 ──────────────── T1 │ └─────────────────────────────────────┘ 优点:实现简单,内存占用小 缺点:边界问题(窗口边界可能突发2倍流量)/** * 固定窗口限流器 */publicclassFixedWindowRateLimiter{privatefinalintlimit;// 限制数量privatefinallongwindowSize;// 窗口大小(ms)privatefinalAtomicIntegercounter=newAtomicInteger(0);privatefinalAtomicLongwindowStart=newAtomicLong(System.currentTimeMillis());publicFixedWindowRateLimiter(intlimit,longwindowSizeMs){this.limit=limit;this.windowSize=windowSizeMs;}publicbooleantryAcquire(){longnow=System.currentTimeMillis();longcurrentWindowStart=windowStart.get();// 检查是否需要重置窗口if(now-currentWindowStart=windowSize){// CAS更新窗口起始时间if(windowStart.compareAndSet(currentWindowStart,now)){counter.set(0);}}// 计数器增加returncounter.incrementAndGet()=limit;}}2.1.2 滑动窗口算法原理:将窗口划分为多个小格,滑动计算 ┌─────────────────────────────────────┐ │ 滑动窗口(1秒 = 10格,每格100ms) │ │ │ │ ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐ │ │ 1 │ 2 │ 1 │ 3 │ 2 │ 1 │ 0 │ 0 │ 0 │ 0 │ │ └───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘ │ ↑ 当前位置 │ │ │ │ 总计: 1+2+1+3+2+1 = 10 (限制) │ └─────────────────────────────────────┘ 优点:解决了固定窗口的边界问题 缺点:内存占用较大/** * 滑动窗口限流器 */publicclassSlidingWindowRateLimiter{privatefinalintlimit;// 总限制privatefinalintwindowSize;// 窗口大小(ms)privatefinalintsubWindowCount;// 子窗口数量privatefinalint[]counters;// 每个子窗口的计数privatefinallongsubWindowSize;// 子窗口大小privatelonglastTime;publicSlidingWindowRateLimiter(intlimit,intwindowSize,intsubWindowCount){this.limit=limit;this.windowSize=windowSize;this.subWindowCount=subWindowCount;this.subWindowSize=windowSize/subWindowCount;this.counters=newint[subWindowCount];this.lastTime=System.currentTimeMillis();}publicsynchronizedbooleantryAcquire(){longnow=System.currentTimeMillis();// 计算当前子窗口索引intcurrentIndex=(int)((now/subWindowSize)%subWindowCount);// 重置过期的子窗口longelapsed=now-lastTime;if(elapsed0){intexpiredCount=(int)Math.min(elapsed/subWindowSize,subWindowCount);for(inti=0;iexpiredCount;i++){intindex=(currentIndex-i+subWindowCount)%subWindowCount;counters[index]=0;}lastTime=now;}// 计算当前总请求数inttotalCount=0;for(intcount:counters){totalCount+=count;}// 判断是否允许if(totalCountlimit){counters[currentIndex]++;returntrue;}returnfalse;}}2.1.3 令牌桶算法原理:以固定速率生成令牌,请求消耗令牌 ┌─────────────────────────────────────┐ │ 令牌桶 │ │ │ │ ┌─────────────────────┐ │ │ │ ▣ ▣ ▣ ▣ ▣ ▣ ▣ ▣ ░ ░ │ │ │ │ 桶中令牌(容量100) │ │ │ └─────────────────────┘ │ │ ↑ │ │ 固定速率补充 │ │ (如100个/秒) │ │ │ │ 请求 → 取令牌 → 有则通过 │ │ → 无则拒绝 │ └─────────────────────────────────────┘ 优点:允许一定程度的突发流量 适用:需要应对突发流量的场景/** * 令牌桶限流器 */publicclassTokenBucketRateLimiter{privatefinallongcapacity;// 桶容量privatefinallongrate;// 令牌生成速率(个/秒)privatefinalAtomicLongtokens=newAtomicLong(0);privatefinalAtomicLonglastRefillTime=newAtomicLong(System.currentTimeMillis());publicTokenBucketRateLimiter(longcapacity,longrate){this.capacity=capacity;this.rate=rate;this.tokens.set(capacity);// 初始满桶}publicbooleantryAcquire(){returntryAcquire(1);}publicbooleantryAcquire(longpermits){// 补充令牌refillTokens();// 尝试获取令牌while(true){longcurrent=tokens.get();longtarget=current-permits;if(target0){returnfalse;// 令牌不足}if(tokens.compareAndSet(current,target)){returntrue;}}}/** * 补充令牌 */privatevoidrefillTokens(){longnow=System.currentTimeMillis();longlastTime=lastRefillTime.get();if(nowlastTime){// 计算应该补充的令牌数longelapsed=now

更多文章