sentinel 随笔 3-降级处理
0. 像喝点东西,但不知道喝什么
先来段源码,看一下 我们在dashboard 录入的降级规则,都映射到哪些字段上
package com.alibaba.csp.sentinel.slots.block.degrade;public class DegradeRule extends AbstractRule {public DegradeRule(String resourceName) {setResource(resourceName);}/*** Circuit breaking strategy (0: average RT, 1: exception ratio, 2: exception count).*/private int grade = RuleConstant.DEGRADE_GRADE_RT;/*** Threshold count.*/private double count;/*** Recovery timeout (in seconds) when circuit breaker opens. After the timeout, the circuit breaker will* transform to half-open state for trying a few requests.*/private int timeWindow;/*** Minimum number of requests (in an active statistic time span) that can trigger circuit breaking.** @since 1.7.0*/private int minRequestAmount = RuleConstant.DEGRADE_DEFAULT_MIN_REQUEST_AMOUNT;/*** The threshold of slow request ratio in RT mode.*/private double slowRatioThreshold = 1.0d;private int statIntervalMs = 1000;
}
1. sentinel 的断路器实现
- 效果跟 netflix.hystrix 差不离
package com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker;public abstract class AbstractCircuitBreaker implements CircuitBreaker {protected final DegradeRule rule;protected final int recoveryTimeoutMs;private final EventObserverRegistry observerRegistry;protected final AtomicReference<State> currentState = new AtomicReference<>(State.CLOSED);protected volatile long nextRetryTimestamp;public AbstractCircuitBreaker(DegradeRule rule) {this(rule, EventObserverRegistry.getInstance());}AbstractCircuitBreaker(DegradeRule rule, EventObserverRegistry observerRegistry) {AssertUtil.notNull(observerRegistry, "observerRegistry cannot be null");if (!DegradeRuleManager.isValidRule(rule)) {throw new IllegalArgumentException("Invalid DegradeRule: " + rule);}this.observerRegistry = observerRegistry;this.rule = rule;this.recoveryTimeoutMs = rule.getTimeWindow() * 1000;}// true, 成功获得令牌@Overridepublic boolean tryPass(Context context) {// 断路器关闭// Template implementation.if (currentState.get() == State.CLOSED) {return true;}// 断路器开启if (currentState.get() == State.OPEN) {// 半开状态,允许通过1个请求来尝试,可行的话,即 true// For half-open state we allow a request for probing.return retryTimeoutArrived() && fromOpenToHalfOpen(context);}return false;}// 当前系统时间 >= 下一次重试时间protected boolean retryTimeoutArrived() {return TimeUtil.currentTimeMillis() >= nextRetryTimestamp;}protected boolean fromOpenToHalfOpen(Context context) {if (currentState.compareAndSet(State.OPEN, State.HALF_OPEN)) {// 通知订阅者: 状态的变化 开 -> 半开notifyObservers(State.OPEN, State.HALF_OPEN, null);Entry entry = context.getCurEntry();// 过程中断时的回调,回滚状态entry.whenTerminate(new BiConsumer<Context, Entry>() {@Overridepublic void accept(Context context, Entry entry) {// Note: This works as a temporary workaround for https://github.com/alibaba/Sentinel/issues/1638// Without the hook, the circuit breaker won't recover from half-open state in some circumstances// when the request is actually blocked by upcoming rules (not only degrade rules).if (entry.getBlockError() != null) {// Fallback to OPEN due to detecting request is blockedcurrentState.compareAndSet(State.HALF_OPEN, State.OPEN);notifyObservers(State.HALF_OPEN, State.OPEN, 1.0d);}}});return true;}return false;}private void notifyObservers(CircuitBreaker.State prevState, CircuitBreaker.State newState, Double snapshotValue) {for (CircuitBreakerStateChangeObserver observer : observerRegistry.getStateChangeObservers()) {observer.onStateChange(prevState, newState, rule, snapshotValue);}}
}
从 DegradeRule.grade 可知道:
- 默认的降级策略,即 响应时长
- 除此之外,还支持 异常 的触发方式
下面分别借助两个 AbstractCircuitBreaker 的实现类来说明实现细节
1.1 ResponseTimeCircuitBreaker(RT) 
package com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker;// 根据请求的响应时间(慢调用比例)
public class ResponseTimeCircuitBreaker extends AbstractCircuitBreaker {private static final double SLOW_REQUEST_RATIO_MAX_VALUE = 1.0d;private final long maxAllowedRt;private final double maxSlowRequestRatio;private final int minRequestAmount;private final LeapArray<SlowRequestCounter> slidingCounter;public ResponseTimeCircuitBreaker(DegradeRule rule) {this(rule, new SlowRequestLeapArray(1, rule.getStatIntervalMs()));}ResponseTimeCircuitBreaker(DegradeRule rule, LeapArray<SlowRequestCounter> stat) {super(rule);AssertUtil.isTrue(rule.getGrade() == RuleConstant.DEGRADE_GRADE_RT, "rule metric type should be RT");AssertUtil.notNull(stat, "stat cannot be null");this.maxAllowedRt = Math.round(rule.getCount());this.maxSlowRequestRatio = rule.getSlowRatioThreshold();this.minRequestAmount = rule.getMinRequestAmount();this.slidingCounter = stat;}@Overridepublic void onRequestComplete(Context context) {SlowRequestCounter counter = slidingCounter.currentWindow().value();Entry entry = context.getCurEntry();if (entry == null) {return;}long completeTime = entry.getCompleteTimestamp();if (completeTime <= 0) {completeTime = TimeUtil.currentTimeMillis();}long rt = completeTime - entry.getCreateTimestamp();if (rt > maxAllowedRt) {counter.slowCount.add(1);}counter.totalCount.add(1);handleStateChangeWhenThresholdExceeded(rt);}private void handleStateChangeWhenThresholdExceeded(long rt) {if (currentState.get() == State.OPEN) {return;}if (currentState.get() == State.HALF_OPEN) {// In detecting request// TODO: improve logic for half-open recoveryif (rt > maxAllowedRt) {fromHalfOpenToOpen(1.0d);} else {fromHalfOpenToClose();}return;}List<SlowRequestCounter> counters = slidingCounter.values();long slowCount = 0;long totalCount = 0;for (SlowRequestCounter counter : counters) {slowCount += counter.slowCount.sum();totalCount += counter.totalCount.sum();}if (totalCount < minRequestAmount) {return;}double currentRatio = slowCount * 1.0d / totalCount;if (currentRatio > maxSlowRequestRatio) {transformToOpen(currentRatio);}if (Double.compare(currentRatio, maxSlowRequestRatio) == 0 &&Double.compare(maxSlowRequestRatio, SLOW_REQUEST_RATIO_MAX_VALUE) == 0) {transformToOpen(currentRatio);}}static class SlowRequestCounter {private LongAdder slowCount;private LongAdder totalCount;}
}
1.2 ExceptionCircuitBreaker
package com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker;// 策略:异常比例、异常数
public class ExceptionCircuitBreaker extends AbstractCircuitBreaker {private final int strategy; // 策略的枚举值private final int minRequestAmount; // 最小请求数private final double threshold; // 设置的阈值private final LeapArray<SimpleErrorCounter> stat;public ExceptionCircuitBreaker(DegradeRule rule) {this(rule, new SimpleErrorCounterLeapArray(1, rule.getStatIntervalMs()));}ExceptionCircuitBreaker(DegradeRule rule, LeapArray<SimpleErrorCounter> stat) {super(rule);this.strategy = rule.getGrade();boolean modeOk = strategy == DEGRADE_GRADE_EXCEPTION_RATIO || strategy == DEGRADE_GRADE_EXCEPTION_COUNT;AssertUtil.isTrue(modeOk, "rule strategy should be error-ratio or error-count");AssertUtil.notNull(stat, "stat cannot be null");this.minRequestAmount = rule.getMinRequestAmount();this.threshold = rule.getCount();this.stat = stat;}@Overridepublic void onRequestComplete(Context context) {Entry entry = context.getCurEntry();if (entry == null) {return;}Throwable error = entry.getError();SimpleErrorCounter counter = stat.currentWindow().value();// 异常发生了,累加if (error != null) {counter.getErrorCount().add(1);}// 总数(异常+非异常),同样累加counter.getTotalCount().add(1);// step into ...handleStateChangeWhenThresholdExceeded(error);}private void handleStateChangeWhenThresholdExceeded(Throwable error) {// 断路器早已启动? 好吧,后面不用看了if (currentState.get() == State.OPEN) {return;}// 半开状态,试探一下if (currentState.get() == State.HALF_OPEN) {// In detecting requestif (error == null) {fromHalfOpenToClose();} else {fromHalfOpenToOpen(1.0d);}return;}// 把这个异常计数传播到整个时间窗(LeapArray)的计数器中List<SimpleErrorCounter> counters = stat.values();long errCount = 0;long totalCount = 0;for (SimpleErrorCounter counter : counters) {errCount += counter.errorCount.sum();totalCount += counter.totalCount.sum();}// 虽然有异常,但是比配置的最小请求数还小,那不需要使用断路器if (totalCount < minRequestAmount) {return;}double curCount = errCount;// 如果策略是:按照异常率的话,计算概率if (strategy == DEGRADE_GRADE_EXCEPTION_RATIO) {// Use errorRatiocurCount = errCount * 1.0d / totalCount;}// 这里开启断路器if (curCount > threshold) {transformToOpen(curCount);}}static class SimpleErrorCounter {private LongAdder errorCount;private LongAdder totalCount;public SimpleErrorCounter() {this.errorCount = new LongAdder();this.totalCount = new LongAdder();}public LongAdder getErrorCount() {return errorCount;}public LongAdder getTotalCount() {return totalCount;}public SimpleErrorCounter reset() {errorCount.reset();totalCount.reset();return this;}@Overridepublic String toString() {return "SimpleErrorCounter{" +"errorCount=" + errorCount +", totalCount=" + totalCount +'}';}}
}
相关文章:

sentinel 随笔 3-降级处理
0. 像喝点东西,但不知道喝什么 先来段源码,看一下 我们在dashboard 录入的降级规则,都映射到哪些字段上 package com.alibaba.csp.sentinel.slots.block.degrade;public class DegradeRule extends AbstractRule {public DegradeRule(String…...

如何解决IP能ping通但无法上网的问题?
当我们在网络环境中遇到无法上网的问题时,可能会尝试使用ping命令来测试网络连接是否正常。如果ping测试成功,说明我们的IP地址能够和网络中其他设备进行通信,但是无法上网。这种情况下,我们需要采取一些措施来解决这个问题。本文…...
Autosar实践-CANTp
文章目录 前言一、CanTp是什么?二、Autosar配置三、诊断数据传输流程1.接收单帧失败,上层没有适当的buffer2.成功接收单帧3.成功发送单帧4.成功接收多帧5.成功发送多帧前言 CANTp模块作为提供数据拆包、组包、流控制传输的服务,在Autosar基础软件通信中起着至关重要的作用。…...

Redis简介
Redis(Remote Dictionary Server)是一个开源的键值对(key-value)数据库,支持网络、可基于内存亦可持久化。 Redis的数据结构包括列表(List)、集合(Set)、有序集合&#…...
报错问题修改
Vue 项目报错:‘$‘ is not defined ( no-undef ) 错误原因是不认识 $ 符,他是 JQuery 中得符号,引入了 JQuery 文件里的函数报错onclick is not defined问题(作用域问题) window.onload function (){ onload function (){ 第二种方法…...

专访惠众科技|元宇宙应用如何借助3DCAT实时云渲染实现流畅大并发呈现?
当前互联网流量红利已经逐渐消失,营销同质化愈发严重。在这样的背景下,催生了以为元宇宙 焦点的虚拟产业经济。元宇宙在各行各业中以不同形式快速萌生、成长,呈现出多元化的应用场景。尤其是众多品牌,将元宇宙视为品牌建设与营销新…...

加速开放计算产业化,OCTC五大原则瞄准需求痛点
回顾计算产业过去十余载的历程,开放计算始终是一个绕不开的核心焦点。 始于2011年Facebook发起的数据中心硬件开源项目--开放计算项目(简称:OCP),开放计算犹如星星之火,不仅迅速形成燎原之势,更…...

【RabbitMQ】安装及六种模式
文章目录 安装rabbitmq镜像访问容器内部15672端口映射到外面的端口地址RabbitMQ六种模式Hello world模式Work queues模式Publish/Subscribe模式交换机fanout类型 Routing模式Topics模式RPC模式 rabbitmq:0->1的学习 学习文档:https://www.cnblogs.com…...

数据结构刷题(三十一):1049. 最后一块石头的重量 II、完全背包理论、518零钱兑换II
一、1049. 最后一块石头的重量 II 1.思路:01背包问题,其中dp[j]表示容量为j的背包,最多可以背最大重量为dp[j]。 2.注意:递推公式dp[j] max(dp[j], dp[j - stones[i]] stones[i]);本题中的重量就是价值,所以第二个…...

opencv_c++学习(四)
图像在opencv中的存储方式 在上图中可以看出,在opencv中采用的是像素值来代表每一个像素三通道颜色的深浅。 Mat对象 Mat对象是在OpenCV2.0之后引进的图像数据结构、自动分配内存、不存在内存泄漏的问题,是面向对象的数据结构。分了两个部分࿰…...

基于AT89C51单片机的篮球计时记分设计
点击链接获取Keil源码与Project Backups仿真图: https://download.csdn.net/download/qq_64505944/87771065 源码获取 主要内容: 基于51单片机设计篮球计时计分器,结合单片机串行接口原理,用AT89C51设计一个篮球比赛计分计时器,能够通过数码管显示分数和比赛时间(并设有…...
并发编程-Day2
并发编程 1.共享模型-内存 共享变量在多线程间的<可见性>问题与多条指令执行时的<有序性>问题 1.1Java内存模型 JMM它定义了主存、工作内存抽象概念,底层对应着CPU寄存器、缓存、硬件内存CPU指令优化等. JMM体现在: 原子性-保证指令不会受到线程上…...

第1章 Nginx简介
基于 Nginx版本 1.14.2 ,Tomcat版本 9.0.0 演示 第1章 Nginx简介 1.1 Nginx发展介绍 Nginx (engine x) 是一个高性能的Web服务器和反向代理服务器,也可以作为邮件代理服务器。 Nginx 特点是占有内存少,并发处理能力…...

一个.Net功能强大、易于使用、跨平台开源可视化图表
可视化图表运用是非常广泛的,比如BI系统、报表统计等。但是针对桌面应用的应用,很多报表都是收费的,今天给大家推荐一个免费.Net可视化开源的项目! 项目简介 基于C#开发的功能强大、易于使用、跨平台高质量的可视化图表库&#…...
浅谈 ext2 文件系统的特点、优缺点以及使用场景
ext2(Extended File System 2)是 Linux 中最早的一种文件系统,它是 Linux 文件系统的基础,也被广泛用于其他类 Unix 系统中。下面是 ext2 文件系统的特点、优缺点以及使用场景: 特点: ext2 文件系统可以支…...
Map和Set数据结构和ES6模块化语法
Map和Set数据结构 ●ES6 新增的两种数据结构 ●共同的特点: 不接受重复数据 Set数据结构 ●是一个 类似于 数组的数据结构 ●按照索引排列的数据结构 创建 Set 数据结构 语法: var s new Set([ 数据1, 数据2, 数据3, ... ]) Set 数据结构的属性和方法 ●size 属性 ○语法: 数…...

10_Uboot启动流程_2
目录 _main函数详解 board_init_f函数详解 relocate_code函数详解 relocate_vectors函数详解 board_init_r 函数详解 _main函数详解 在上一章得知会执行_main函数_main函数定义在文件arch/arm/lib/crt0.S 中,函数内容如下: 第76行,设置sp指针为CONFIG_SYS_INIT_SP_ADDR,也…...

python+django汽车4S店零配件保养服务管理系统
汽车4S服务管理系统包括三种用户。管理员、普通员工、客户。 开发语言:Python 框架:django/flask Python版本:python3.7.7 数据库:mysql 数据库工具:Navicat 开发软件:PyCharm django 应用目录结构管…...

STM32F4的输出比较极性和PWM1,PWM2的关系
PWM 输出比较通道 在这里以通用定时器的通道1作为介绍。 如图,左边就是CNT计数器和CCR1第一路的捕获/比较寄存器,它俩进行比较,当CNT>CCR1, 或者CNTCCR1时,就会给输出模式控制器传送一个信号,然后输出模式控制器就…...
易优cms伪静态,EyouCms去除URL中的index.php
针对不同服务器、虚拟空间,运行PHP的环境也有所不同,目前主要分为:Nginx、apache、IIS以及其他服务器。下面分享如何去掉URL上的index.php字符,记得在管理后台清除缓存,对于一些ECS服务器可能要重启nginx等服务! 【Nginx服务器】 在原有的nginx重写文件里新增以下代码片…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

Linux-07 ubuntu 的 chrome 启动不了
文章目录 问题原因解决步骤一、卸载旧版chrome二、重新安装chorme三、启动不了,报错如下四、启动不了,解决如下 总结 问题原因 在应用中可以看到chrome,但是打不开(说明:原来的ubuntu系统出问题了,这个是备用的硬盘&a…...

算法岗面试经验分享-大模型篇
文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer (1)资源 论文&a…...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式
今天是关于AI如何在教学中增强学生的学习体验,我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育,这并非炒作,而是已经发生的巨大变革。教育机构和教育者不能忽视它,试图简单地禁止学生使…...

Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...

Golang——6、指针和结构体
指针和结构体 1、指针1.1、指针地址和指针类型1.2、指针取值1.3、new和make 2、结构体2.1、type关键字的使用2.2、结构体的定义和初始化2.3、结构体方法和接收者2.4、给任意类型添加方法2.5、结构体的匿名字段2.6、嵌套结构体2.7、嵌套匿名结构体2.8、结构体的继承 3、结构体与…...

pikachu靶场通关笔记19 SQL注入02-字符型注入(GET)
目录 一、SQL注入 二、字符型SQL注入 三、字符型注入与数字型注入 四、源码分析 五、渗透实战 1、渗透准备 2、SQL注入探测 (1)输入单引号 (2)万能注入语句 3、获取回显列orderby 4、获取数据库名database 5、获取表名…...

WPF八大法则:告别模态窗口卡顿
⚙️ 核心问题:阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程,导致后续逻辑无法执行: var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题:…...