wordpress纯图片主题,台州做网站优化,seo免费诊断,无锡高端网站设计开发概述 一个用于 RPC 框架的异常比例熔断器#xff0c;可以实现时间窗口内统计请求成功次数#xff0c;失败次数#xff0c;失败比例达到阈值并且时间窗口内总请求数量达到阈值则对服务进行降级#xff0c;经过特定时间间隔尝试恢复服务#xff0c;放开服务可调用次数permit…概述一个用于 RPC 框架的异常比例熔断器可以实现时间窗口内统计请求成功次数失败次数失败比例达到阈值并且时间窗口内总请求数量达到阈值则对服务进行降级经过特定时间间隔尝试恢复服务放开服务可调用次数permits防止服务未恢复大量请求导致下游服务受到ddos攻击当成功次数达到阈值再次恢复服务调用。核心特性如下1. 滑动时间窗口统计用 Bucket[] 数组实现秒级时间桶每个桶统计 1 秒内的成功/失败数基于 baseSecond 基准时间计算索引避免时间推移导致的桶覆盖问题真正的滑动窗口只统计「最近 windowSize 秒」且「不早于基准时间」的数据2. 无锁并发设计状态切换用 AtomicReferenceState保证原子性时间桶重置用 AtomicLong.compareAndSet()避免高并发锁竞争半开状态试探次数用 AtomicInteger.compareAndSet()防止超量3. 半开状态优化支持失败容忍不是一次失败就切回 OPEN而是失败数达到 halfOpenFailureThreshold 才切回用 halfOpenInitialized 标记初始化完成避免并发问题4. 生产级特性异常过滤器支持过滤无需计入失败的异常如参数错误、客户端异常手动重置reset() 方法支持运维手动干预监控指标暴露getWindowStats() 和 getHalfOpenStats() 方便对接 Prometheus/Grafana自旋限制tryAcquire() 最多自旋 10 次避免 CPU 耗尽5. 浮点数精度优化预计算整数阈值failThresholdPercent、halfOpenFailureThreshold避免重复浮点数运算用整数比较替代浮点数比较解决精度问题状态支持CLOSED, HALF_OPEN, OPEN 三种状态机制分别对应服务正常服务尝试恢复服务熔断参数完整代码package com.pig.rpc.breaker; import lombok.*; import lombok.extern.slf4j.Slf4j; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; /** * className: CircuitBreaker * author: XTX * date: 2026/1/31 12:23 * Version: 1.0 * description: 异常比例熔断器, 记录十秒内窗口 */ Slf4j public class CircuitBreaker { // 常量定义避免魔法值 /** 默认窗口大小10秒 */ public static final int DEFAULT_WINDOW_SIZE 10; /** 默认最小触发请求数10次 */ public static final int DEFAULT_MIN_REQUEST_COUNT 10; /** 默认失败率阈值50% */ public static final double DEFAULT_FAIL_THRESHOLD 0.5D; /** 默认OPEN状态持续时间10000毫秒 */ public static final long DEFAULT_OPEN_DURATION_MILLIS 10000L; /** 默认半开状态最大试探次数8次 */ public static final int DEFAULT_HALF_OPEN_PERMITS 8; /** 默认半开状态成功恢复阈值50% */ public static final double DEFAULT_HALF_OPEN_SUCCESS_THRESHOLD 0.5D; /** 最大自旋次数避免CPU耗尽 */ public static final int MAX_SPIN_COUNT 10; /** 百分比基数解决浮点数精度问题 */ private static final int PERCENT_BASE 100; // 熔断器状态机 Getter public enum State { /** 闭合状态正常转发所有请求统计失败率 */ CLOSED, /** 打开状态拒绝所有请求直到超时后尝试切半开 */ OPEN, /** 半开状态允许少量试探请求根据结果决定切闭合/打开 */ HALF_OPEN } /** 核心状态原子引用保证线程安全的状态切换 */ private final AtomicReferenceState state new AtomicReference(State.CLOSED); // 滑动窗口核心配置不可变 /** 时间窗口大小单位秒 */ Getter private final int windowSize; /** 窗口内最小请求数达到该数量才会判断失败率是否触发熔断 */ Getter private final int minRequestCount; /** 窗口内失败率阈值达到该比例触发熔断0.0~1.0 */ Getter private final double failThreshold; /** 滑动时间桶数组每个桶统计1秒的成功/失败请求 */ private final Bucket[] buckets; /** 熔断器初始化基准秒数解决时间桶索引偏移问题实现真正滑动窗口 */ private final long baseSecond; // 半开状态配置与统计不可变配置原子统计 /** 半开状态最大试探请求数防止试探流量过大压垮服务 */ Getter private final int halfOpenPermits; /** 半开状态恢复闭合的成功比例阈值0.0~1.0 */ Getter private final double halfOpenSuccessThreshold; /** 半开状态已使用的试探次数 */ private final AtomicInteger halfOpenUsed new AtomicInteger(0); /** 半开状态试探成功次数 */ private final AtomicInteger halfOpenSuccess new AtomicInteger(0); /** 半开状态试探失败次数 */ private final AtomicInteger halfOpenFailure new AtomicInteger(0); /** 半开状态初始化标记volatile保证可见性替代冗余AtomicBoolean */ private volatile boolean halfOpenInitialized false; /** 半开状态失败阈值预计算整数避免重复浮点数运算 */ private final int halfOpenFailureThreshold; // 打开状态配置与统计不可变配置原子/volatile /** OPEN状态持续时间单位毫秒超时后可尝试切半开 */ Getter private final long openDurationMillis; /** 上一次切为OPEN状态的时间戳volatile保证多线程可见性 * -- GETTER -- * 获取上一次切为OPEN状态的时间戳 */ Getter private volatile long openTimestamp; /** 失败率阈值整数预计算避免重复浮点数运算 */ private final int failThresholdPercent; // 生产级特性异常过滤 /** 失败异常过滤器过滤无需计入失败的异常如参数错误、客户端异常 */ Getter private final FailureFilter failureFilter; // 构造方法重载默认全参支持可配置 /** * 默认构造方法使用所有默认配置 */ public CircuitBreaker() { this(DEFAULT_WINDOW_SIZE, DEFAULT_MIN_REQUEST_COUNT, DEFAULT_FAIL_THRESHOLD, DEFAULT_OPEN_DURATION_MILLIS, DEFAULT_HALF_OPEN_PERMITS, DEFAULT_HALF_OPEN_SUCCESS_THRESHOLD, t - true); } /** * 基础配置构造方法指定核心窗口配置其余使用默认 * * param windowSize 时间窗口大小秒 * param minRequestCount 窗口内最小触发请求数 * param failThreshold 失败率阈值0.0~1.0 */ public CircuitBreaker(int windowSize, int minRequestCount, double failThreshold) { this(windowSize, minRequestCount, failThreshold, DEFAULT_OPEN_DURATION_MILLIS, DEFAULT_HALF_OPEN_PERMITS, DEFAULT_HALF_OPEN_SUCCESS_THRESHOLD, t - true); } /** * 全参构造方法支持所有配置自定义包含异常过滤器 * * param windowSize 时间窗口大小秒必须0 * param minRequestCount 窗口内最小触发请求数必须0 * param failThreshold 失败率阈值0.0~1.0 * param openDurationMillis OPEN状态持续时间毫秒必须0 * param halfOpenPermits 半开状态最大试探次数必须0 * param halfOpenSuccessThreshold 半开状态恢复成功比例0.0~1.0 * param failureFilter 失败异常过滤器非空 * throws IllegalArgumentException 入参不合法时抛出 */ public CircuitBreaker(int windowSize, int minRequestCount, double failThreshold, long openDurationMillis, int halfOpenPermits, double halfOpenSuccessThreshold, FailureFilter failureFilter) { // 1. 入参合法性校验生产级核心避免非法参数导致运行时异常 if (windowSize 0) { throw new IllegalArgumentException(windowSize must be 0, current: windowSize); } if (minRequestCount 0) { throw new IllegalArgumentException(minRequestCount must be 0, current: minRequestCount); } if (failThreshold 0 || failThreshold 1) { throw new IllegalArgumentException(failThreshold must be between 0 and 1, current: failThreshold); } if (openDurationMillis 0) { throw new IllegalArgumentException(openDurationMillis must be 0, current: openDurationMillis); } if (halfOpenPermits 0) { throw new IllegalArgumentException(halfOpenPermits must be 0, current: halfOpenPermits); } if (halfOpenSuccessThreshold 0 || halfOpenSuccessThreshold 1) { throw new IllegalArgumentException(halfOpenSuccessThreshold must be between 0 and 1, current: halfOpenSuccessThreshold); } if (failureFilter null) { throw new IllegalArgumentException(failureFilter must not be null); } // 2. 基础配置赋值 this.windowSize windowSize; this.minRequestCount minRequestCount; this.failThreshold failThreshold; this.openDurationMillis openDurationMillis; this.halfOpenPermits halfOpenPermits; this.halfOpenSuccessThreshold halfOpenSuccessThreshold; this.failureFilter failureFilter; this.baseSecond nowSecond(); // 初始化基准时间解决时间桶索引偏移 // 3. 预计算整数阈值避免重复浮点数运算解决精度问题 this.failThresholdPercent (int) (failThreshold * PERCENT_BASE); this.halfOpenFailureThreshold (int) (halfOpenPermits * (1 - halfOpenSuccessThreshold)); // 4. 初始化时间桶数组 this.buckets new Bucket[windowSize]; for (int i 0; i windowSize; i) { buckets[i] new Bucket(); } log.info(CircuitBreaker initialized with config: windowSize{}s, minRequestCount{}, failThreshold{}%, openDuration{}ms, halfOpenPermits{}, halfOpenSuccessThreshold{}%, windowSize, minRequestCount, failThresholdPercent, openDurationMillis, halfOpenPermits, (int) (halfOpenSuccessThreshold * PERCENT_BASE)); } // 核心入口请求是否允许通过 /** * 判断当前请求是否允许通过熔断器 * 支持CLOSED/OPEN/HALF_OPEN三级状态的逻辑处理增加自旋限制避免CPU耗尽 * * return true-允许通过false-拒绝请求熔断中 */ public boolean tryAcquire() { int spinCount 0; // 有限自旋避免无限循环导致CPU耗尽自旋失败则降级拒绝 while (spinCount MAX_SPIN_COUNT) { State currentState state.get(); switch (currentState) { case CLOSED: // 闭合状态允许所有请求 return true; case OPEN: // 打开状态判断是否超时超时则尝试切半开 if (System.currentTimeMillis() - openTimestamp openDurationMillis) { return false; } // CAS尝试切半开保证原子性只有一个线程能成功 if (state.compareAndSet(State.OPEN, State.HALF_OPEN)) { // 初始化半开状态统计 halfOpenUsed.set(0); halfOpenSuccess.set(0); halfOpenFailure.set(0); halfOpenInitialized true; log.info(CircuitBreaker state changed: OPEN - HALF_OPEN, open duration expired); // 自旋重新判断状态 continue; } // CAS失败其他线程已切半开重新自旋获取最新状态 break; case HALF_OPEN: // 半开状态检查是否初始化完成未完成则重新自旋 if (!halfOpenInitialized) { break; } // CAS原子控制试探次数防止超量核心并发安全优化 int currentUsed; do { currentUsed halfOpenUsed.get(); // 试探次数已达上限拒绝请求 if (currentUsed halfOpenPermits) { return false; } // CAS自增保证只有一个线程能成功获取试探权限 } while (!halfOpenUsed.compareAndSet(currentUsed, currentUsed 1)); log.debug(CircuitBreaker HALF_OPEN state, acquire permit: used{}/{}, currentUsed 1, halfOpenPermits); return true; default: // 未知状态降级拒绝避免异常 log.warn(CircuitBreaker unknown state: {}, reject request, currentState); return false; } } // 自旋次数耗尽降级拒绝保护系统 log.warn(CircuitBreaker tryAcquire spin count exhausted({}), reject request, MAX_SPIN_COUNT); return false; } // 结果统计成功/失败重载支持异常过滤 /** * 记录请求成功 * 区分CLOSED/HALF_OPEN状态半开状态的成功不计入滑动窗口 */ public void recordSuccess() { State currentState state.get(); if (currentState State.HALF_OPEN) { handleHalfOpenSuccess(); return; } // 仅闭合状态统计成功数到滑动窗口 if (currentState State.CLOSED) { currentBucket().success.incrementAndGet(); } } /** * 记录请求失败无异常直接统计 */ public void recordFailure() { recordFailure(null); } /** * 生产级失败统计支持异常类型过滤过滤后的异常不计入失败 * * param throwable 失败对应的异常可为null */ public void recordFailure(Throwable throwable) { // 异常过滤过滤无需计入失败的异常如参数错误、客户端异常 if (throwable ! null !failureFilter.isCounted(throwable)) { log.debug(CircuitBreaker ignore failure, filtered by exception: {}, throwable.getClass().getSimpleName()); return; } State currentState state.get(); if (currentState State.HALF_OPEN) { handleHalfOpenFailure(); return; } // 仅闭合状态统计失败数并判断是否需要触发熔断 if (currentState State.CLOSED) { currentBucket().failure.incrementAndGet(); if (shouldOpen()) { open(); // 触发熔断切为打开状态 } } } // 生产级特性手动重置 /** * 手动重置熔断器状态为CLOSED * 生产运维核心特性服务恢复后可手动干预无需等待超时 */ public void reset() { State oldState state.getAndSet(State.CLOSED); if (oldState ! State.CLOSED) { halfOpenInitialized false; openTimestamp 0; // 重置所有时间桶清空历史统计 for (Bucket bucket : buckets) { bucket.reset(0); } log.info(CircuitBreaker manually reset, state changed: {} - CLOSED, oldState); } } // 生产级特性核心监控指标暴露 /** * 获取当前熔断器状态 */ public State getCurrentState() { return state.get(); } /** * 获取滑动窗口内的核心统计指标 * 包括总请求数、失败数、失败率用于监控系统对接如Prometheus/Grafana * * return 窗口统计对象 */ public WindowStats getWindowStats() { long now nowSecond(); int total 0; int failed 0; for (Bucket bucket : buckets) { // 仅统计窗口内的有效数据真正的滑动窗口 if (bucket.getTimestamp() now - windowSize bucket.getTimestamp() baseSecond) { int s bucket.success.get(); int f bucket.failure.get(); total s f; failed f; } } // 计算失败率避免除零 int failRate total 0 ? 0 : (failed * PERCENT_BASE) / total; return new WindowStats(total, failed, failRate); } /** * 获取半开状态的统计指标 */ public HalfOpenStats getHalfOpenStats() { return new HalfOpenStats( halfOpenUsed.get(), halfOpenSuccess.get(), halfOpenFailure.get(), halfOpenPermits, halfOpenSuccessThreshold ); } // 内部方法状态处理与判断 /** * 处理半开状态的请求成功 * 达到成功阈值则切回闭合状态保证服务恢复 */ private void handleHalfOpenSuccess() { int success halfOpenSuccess.incrementAndGet(); // 整数比较成功数 试探数*成功阈值切回闭合状态 if (success * PERCENT_BASE halfOpenPermits * (int) (halfOpenSuccessThreshold * PERCENT_BASE)) { halfOpenInitialized false; // CAS切回闭合状态保证原子性 if (state.compareAndSet(State.HALF_OPEN, State.CLOSED)) { log.info(CircuitBreaker state changed: HALF_OPEN - CLOSED, half open success: {}/{}, success, halfOpenPermits); } } } /** * 处理半开状态的请求失败 * 失败数达到阈值则切回打开状态增加容错性避免单次抖动导致恢复失败 */ private void handleHalfOpenFailure() { int failure halfOpenFailure.incrementAndGet(); // 失败数达到阈值切回打开状态 if (failure halfOpenFailureThreshold) { halfOpenInitialized false; open(); // 切回打开状态 log.warn(CircuitBreaker HALF_OPEN state failure threshold reached: {}/{}, switch to OPEN, failure, halfOpenFailureThreshold); } } /** * 触发熔断将状态切为OPEN记录熔断时间戳 * 支持从CLOSED/HALF_OPEN切为OPEN保证原子性 */ private void open() { // CAS保证原子性支持从闭合/半开切为打开 if (state.compareAndSet(State.CLOSED, State.OPEN) || state.compareAndSet(State.HALF_OPEN, State.OPEN)) { this.openTimestamp System.currentTimeMillis(); WindowStats stats getWindowStats(); log.error(CircuitBreaker opened! state changed to OPEN, window stats: total{}, failed{}, failRate{}%, stats.getTotal(), stats.getFailed(), stats.getFailRatePercent()); } } /** * 判断是否需要触发熔断闭合状态下 * 统计滑动窗口内的总请求数和失败率达到阈值则返回true * * return true-需要触发熔断false-无需熔断 */ private boolean shouldOpen() { long now nowSecond(); int total 0; int failed 0; for (Bucket bucket : buckets) { // 仅统计「最近windowSize秒」且「不早于基准时间」的有效数据实现真正的滑动窗口 if (bucket.getTimestamp() now - windowSize bucket.getTimestamp() baseSecond) { int s bucket.success.get(); int f bucket.failure.get(); total s f; failed f; // 提前终止总请求数达标且失败率达标无需继续遍历 if (total minRequestCount) { int currentFailRate (failed * PERCENT_BASE) / total; if (currentFailRate failThresholdPercent) { return true; } } } } // 最终判断总请求数达标 失败率达标 return total minRequestCount (failed * PERCENT_BASE) / total failThresholdPercent; } // 内部方法时间桶操作核心优化真正的滑动窗口 /** * 获取当前秒对应的时间桶采用无锁CAS重置减少高并发锁竞争 * 基于基准时间计算索引避免模运算覆盖实现真正的滑动窗口 * * return 当前秒的时间桶 */ private Bucket currentBucket() { long now nowSecond(); // 基于基准时间计算索引避免时间推移导致的索引重复覆盖 int idx (int) ((now - baseSecond) % windowSize); // 索引边界保护避免负数极端情况系统时间回拨 idx Math.max(0, idx % windowSize); Bucket bucket buckets[idx]; // 无锁重置时间戳不一致则重置CAS保证原子性 if (bucket.getTimestamp() ! now) { bucket.tryReset(now); } return bucket; } /** * 获取当前时间的秒数毫秒转秒向下取整 */ private long nowSecond() { return System.currentTimeMillis() / 1000; } // 内部类时间桶统计单秒的成功/失败 /** * 时间桶统计单个秒内的请求成功/失败数 * 采用原子类保证计数线程安全无锁CAS重置减少高并发竞争 */ static class Bucket { /** 桶对应的秒级时间戳原子类保证重置的原子性 */ private final AtomicLong timestamp new AtomicLong(0); /** 成功请求数 */ private final AtomicInteger success new AtomicInteger(0); /** 失败请求数 */ private final AtomicInteger failure new AtomicInteger(0); /** * 无锁重置时间桶CAS保证原子性避免高并发锁竞争 * * param ts 新的秒级时间戳 */ void tryReset(long ts) { // CAS保证只有一个线程能成功重置其余线程直接使用已重置的桶 if (timestamp.compareAndSet(timestamp.get(), ts)) { success.set(0); failure.set(0); } } /** * 重置时间桶用于手动重置熔断器 */ void reset(long ts) { timestamp.set(ts); success.set(0); failure.set(0); } /** * 获取桶的时间戳Acquire保证可见性 */ long getTimestamp() { return timestamp.get(); } } // 内部类监控指标对象生产级方便监控对接 /** * 滑动窗口统计指标暴露给监控系统包含总请求、失败数、失败率 */ Getter public static class WindowStats { /** 窗口内总请求数 */ private final int total; /** 窗口内失败请求数 */ private final int failed; /** 窗口内失败率百分比0~100 */ private final int failRatePercent; public WindowStats(int total, int failed, int failRatePercent) { this.total total; this.failed failed; this.failRatePercent failRatePercent; } Override public String toString() { return WindowStats{total total , failed failed , failRatePercent failRatePercent %}; } } /** * 半开状态统计指标暴露给监控系统包含试探次数、成功/失败数等 */ Getter public static class HalfOpenStats { /** 已使用的试探次数 */ private final int used; /** 试探成功次数 */ private final int success; /** 试探失败次数 */ private final int failure; /** 最大试探次数 */ private final int permits; /** 成功恢复阈值0.0~1.0 */ private final double successThreshold; public HalfOpenStats(int used, int success, int failure, int permits, double successThreshold) { this.used used; this.success success; this.failure failure; this.permits permits; this.successThreshold successThreshold; } Override public String toString() { return HalfOpenStats{used used , success success , failure failure , permits permits , successThreshold (int) (successThreshold * 100) %}; } } // 函数式接口失败异常过滤器生产级异常类型过滤 /** * 失败异常过滤器接口用于过滤无需计入失败的异常 * 支持lambda表达式传入灵活适配业务场景 */ FunctionalInterface public interface FailureFilter { /** * 判断该异常是否需要计入失败数 * * param throwable 失败对应的异常 * return true-计入失败false-过滤该异常不计入失败 */ boolean isCounted(Throwable throwable); } }