利用断路器状态统计sentinel熔断次数

最近项目需要sentinel熔断时记录熔断的次数,在经过一阵搜索后决定利用断路器的状态变化来实现此功能

然而,遇到了这样的一个情况,断路器的状态在第一次熔断时正常从close-->open,但在后续(熔断时间内blocked或者熔断结束后重新开启断路器)断路器的状态变化均为half open-->open,导致无法区分究竟是熔断时间内还是再次被熔断了,因此使用了一个flag来做标记实现了功能。

本方法利用了断路器的状态统计熔断次数,代码修改自chatgpt

代码如下:

java 复制代码
/**
 * @ClassName: SentinelBlockHandler
 * @Description: sentinel统一异常处理
 * @author: liuzijian @ haiyisoft
 * @Date: 2023/11/7 11:54
 * @version: 1.0
 **/
@Component
@Slf4j
public class SentinelBlockHandler implements BlockExceptionHandler {

    private boolean flag = false;
    @Resource
    private ServerDegradeLogsRepository serverDegradeLogsRepository;
    @Value("${server.port}")
    private Integer serverPort;

    private SentinelBlockHandler() {
        // 私有构造方法,防止外部实例化
    }

    public static SentinelBlockHandler getInstance() {
        return SingletonHolder.INSTANCE;
    }

    private static class SingletonHolder {
        private static final SentinelBlockHandler INSTANCE = new SentinelBlockHandler();
    }

    static {
        registerStateChangeObserver();
    }

    private static void registerStateChangeObserver() {
        EventObserverRegistry.getInstance().addStateChangeObserver("logging",
                (prevState, newState, rule, snapshotValue) -> {
                    List<CircuitBreakerStateChangeObserver> observers = EventObserverRegistry.getInstance().getStateChangeObservers();
                    if (newState == CircuitBreaker.State.OPEN) {
                        getInstance().flag = true;
                        System.err.println(String.format("===> resource: %s, %s -> OPEN at %d, snapshotValue=%.2f",
                                rule.getResource(), prevState.name(), TimeUtil.currentTimeMillis(), snapshotValue));
                    } else {
                        System.err.println(String.format("===> resource: %s, %s -> %s at %d",
                                rule.getResource(), prevState.name(), newState.name(), TimeUtil.currentTimeMillis()));
                    }
                });
    }

    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
        /**
         * 请求被限流了
         */
        if (e instanceof FlowException){
            httpServletResponse.setStatus(429);
            ResponseService.httpResponse(httpServletResponse, ResponseStatus.SENTINEL_FLOW_ERROR);
            log.error("请求被限流了:{}",e.getMessage());
        }
        /**
         * 请求被熔断降级了
         */
        else if (e instanceof DegradeException) {
            System.out.println("进入熔断异常");
            if (getInstance().flag){
                InetAddress addr = InetAddress.getLocalHost();
                String degradeText = "请求被熔断降级了:{" + e.getMessage() + "}";
                ServerDegradeLogs serverDegradeLogs = new ServerDegradeLogs(addr.getHostAddress(), this.serverPort, degradeText);
                serverDegradeLogsRepository.save(serverDegradeLogs);
                getInstance().flag = false;
            }
            httpServletResponse.setStatus(429);
            ResponseService.httpResponse(httpServletResponse, ResponseStatus.SENTINEL_DEGRADE_ERROR);
            log.error("请求被熔断降级了:{}",e.getMessage());
        }
        /**
         * 热点被限流了
         */
        else if (e instanceof ParamFlowException) {
            httpServletResponse.setStatus(429);
            ResponseService.httpResponse(httpServletResponse, ResponseStatus.SENTINEL_PARAM_FLOW_ERROR);
            log.error("热点被限流了:{}",e.getMessage());
        }
        /**
         * 请求没有权限
         */
        else if (e instanceof AuthorityException) {
            httpServletResponse.setStatus(401);
            ResponseService.httpResponse(httpServletResponse, ResponseStatus.UNAUTHORIZED);
            log.error("请求没有权限:{}",e.getMessage());
        }
    }
}

参考链接:

断路器的使用:https://github.com/alibaba/Sentinel/issues/1939

相关推荐
执明wa几秒前
Android RecyclerView 实战:点击频道栏切换对应内容
android·开发语言·windows·microsoft·android studio
开开心心就好2 分钟前
图片白底怎么去掉?抠图工具抠完背景透明
java·服务器·开发语言·pdf·ocr·散列表·启发式算法
朝朝辞暮i4 分钟前
C++ 第 22 课:const —— 不允许随便修改的数据
开发语言·c++·算法
web打印社区9 分钟前
JS 静默打印怎么做:纯前端为什么不行,以及最小可跑通写法
开发语言·前端·javascript·websocket·网络协议·http·pdf
大圣编蚕11 分钟前
C语言怎么写小游戏?从零开始做一个贪吃蛇
c语言·开发语言
Chen—LSN31 分钟前
数据结构——拿捏复杂度
java·c语言·开发语言·数据结构·经验分享·笔记·算法
阿钱真强道43 分钟前
25 嵌入式操作系统 | 设备面板:用 Qt 控件把“设备“画出来(本节不接串口)
开发语言·qt·flask·架构设计·协议契约
ym hyd 1111 小时前
宝宝早教服务系统源码 Java+SpringBoot+Vue3 前后分离
java·开发语言·spring boot
看浪的路人1 小时前
第7讲:实时告警与自动化响应
开发语言·后端·golang
“AI国潮设计-小江”1 小时前
Python实战 | SDXL批量生成“潮汕英歌舞”国潮甜品IP,附核心Prompt与商用授权思路
开发语言·人工智能·python·prompt·aigc