Sentinel架构篇 - 熔断降级
熔断降级
概念
除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。一个服务常常会调用其它模块,可能是一个远程服务、数据库、或者第三方 API 等。然而,被依赖的服务的稳定性是不能保证的。如果依赖的服务出现了不稳定的情况,导致请求的响应时间变长,那么调用服务的方法的响应时间也会变长,线程会堆积,最终可能会耗尽业务自身的线程池,甚至服务本身变得不可用。
现在的微服务架构都是分布式的,由非常多的服务组成。不同的服务之间相互调用,形成复杂的调用链路。链路中某一环不稳定,可能会层层级联,最终导致整个链路不可用。因此需要对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定的调用,避免局部不稳定因素导致整体的雪崩。熔断降级通常在客户端(调用端)进行配置。
熔断可以类比成生活中的保险丝,一旦电流过载,保险丝就会断开。
Sentinel 熔断降级基于熔断器模式 (circuit breaker pattern) 实现。熔断器内部维护了一个熔断器的状态机,状态机的转换关系如下图所示:
熔断器有三种状态:
- Closed 状态:也是初始状态,该状态下,熔断器会保持闭合,对资源的访问直接通过熔断器的检查。
- Open 状态:断开状态,熔断器处于开启状态,对资源的访问会被切断。
- Half-Open 状态:半开状态,该状态下除了探测流量,其余对资源的访问也会被切断。探测流量指熔断器处于半开状态时,会周期性的允许一定数目的探测请求通过,如果探测请求能够正常的返回,代表探测成功,此时熔断器会重置状态到 Closed 状态,结束熔断;如果探测失败,则回滚到 Open 状态。
熔断策略
Sentinel 提供了如下三种熔断策略。
- 慢调用比例(
SLOW_REQUEST_RATIO
):选择慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),如果请求的时间大于该阈值则被统计为慢调用。当单位统计时长(statIntervalMs
)内请求的数量大于设置的最小请求数量,并且慢调用的比例大于阈值,则接下来的熔断时长(timeWindow
)内请求自动被熔断。经过熔断时长后,熔断器进入探测恢复状态(Half-Open 状态),如果接下来的一个请求的响应时间小于设置的慢调用 RT 则结束熔断;如果大于则再次被熔断。慢调用比例的阈值范围为[0.0, 1.0]
,代表 0% - 100%。 - 异常比例(
ERROR_RATIO
):当单位统计时长(statIntervalMs
)内请求数量大于设置的最小请求数量,并且异常比例大于阈值,则接下来的熔断时长(timeWindow
)内请求自动被熔断。经过熔断时长后,熔断器进入探测恢复状态(Half-Open 状态),如果接下来的一个请求成功完成(没有错误)则结束熔断;否则再次被熔断。异常比例的阈值范围为[0.0, 1.0]
,代表 0% - 100%。 - 异常数(
ERROR_COUNT
):当单位统计时长(statIntervalMs
)内的异常数量超过阈值之后,则接下来的熔断时长(timeWindow
)内请求自动被熔断。经过熔断时长后,熔断器进入探测恢复状态(Half-Open 状态),如果接下来的一个请求成功完成(没有错误)则结束熔断;否则再次被熔断。
熔断降级规则
字段 | 说明 | 默认值 |
---|---|---|
resource | 资源名,即规则作用的对象 | |
grade | 熔断策略,支持慢调用比例/异常比例/异常数 | 慢调用比例 |
count | 慢调用比例模式下对应慢调用RT(超过该值即为慢调用);异常比例/异常数模式下为对应的阈值 | |
timeWindow | 熔断时长,单位为秒 | |
minRequestAmount | 熔断触发的最小请求数,请求数小于该值时即使异常比例超过阈值也不会熔断(1.7.0 版本引入) | 5 |
statIntervalMs | 统计时长,单位为毫秒(1.8.0 版本引入) | 1000 |
slowRationThreshold | 慢调用比例阈值,仅慢调用比例模式有效(1.8.0 版本引入) |
同一个资源可以同时有多个熔断降级规则。
实际操作
在 Nacos 的控制台中的配置管理/配置列表中,在 public 的命名空间中创建一个如下配置:
dataId:spring-cloud-demo-consumer-sentinel-degrade
group:DEFAULT
[{"resource": "/hello/say","limitApp": "default","grade": 0,"count": 200,"timeWindow": 10,"statIntervalMs": 1000,"slowRatioThreshold": 0.6 }
]
如果 1 秒内,请求数量至少达到 200,并且(请求的响应时间超过 200 毫秒即为慢调用)慢调用的比例达到 60%,则进行熔断,熔断时长为 10 秒。
对应的客户端的配置文件如下:
spring:application:name: spring-cloud-demo-consumercloud:nacos:discovery:server-addr: 10.211.55.11:8848,10.211.55.12:8848,10.211.55.13:8848enabled: truesentinel:transport:dashboard: 127.0.0.1:9000eager: truedatasource:degrade-nacos-datasource:nacos:server-addr: 10.211.55.11:8848,10.211.55.12:8848,10.211.55.13:8848group-id: DEFAULT_GROUPnamespace: publicdata-id: ${spring.application.name}-sentinel-degradedata-type: jsonrule-type: degradeusername: nacospassword: nacos
DegradeSlot
负责熔断降级规则的判断。
@Spi(order = Constants.ORDER_DEGRADE_SLOT)
public class DegradeSlot extends AbstractLinkedProcessorSlot<DefaultNode> {@Overridepublic void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count,boolean prioritized, Object... args) throws Throwable {// 校验熔断降级规则performChecking(context, resourceWrapper);fireEntry(context, resourceWrapper, node, count, prioritized, args);}void performChecking(Context context, ResourceWrapper r) throws BlockException {// 由DegradeRuleManager负责加载所有的断路器List<CircuitBreaker> circuitBreakers = DegradeRuleManager.getCircuitBreakers(r.getName());// 如果断路器列表为空,则直接返回if (circuitBreakers == null || circuitBreakers.isEmpty()) {return;}// 遍历断路器列表,只要有一个断路器判定请求不通过,则抛出DegradeException异常for (CircuitBreaker cb : circuitBreakers) {if (!cb.tryPass(context)) {throw new DegradeException(cb.getRule().getLimitApp(), cb.getRule());}}}@Overridepublic void exit(Context context, ResourceWrapper r, int count, Object... args) {Entry curEntry = context.getCurEntry();// 如果调用过程中存在BlockException异常,则直接返回if (curEntry.getBlockError() != null) {fireExit(context, r, count, args);return;}// 由DegradeRuleManager负责加载所有的断路器List<CircuitBreaker> circuitBreakers = DegradeRuleManager.getCircuitBreakers(r.getName());// 如果断路器列表为空,则直接返回if (circuitBreakers == null || circuitBreakers.isEmpty()) {fireExit(context, r, count, args);return;}// 如果调用过程中不存在BlockException异常if (curEntry.getBlockError() == null) {// 遍历断路器列表,触发每个断路器的onRequestComplete方法的回调for (CircuitBreaker circuitBreaker : circuitBreakers) {circuitBreaker.onRequestComplete(context);}}fireExit(context, r, count, args);}
}
接下来看下断路器如何判断请求是否通过的。
AbstractCircuitBreaker
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;
}
接下来看下 tryPass 方法的处理逻辑。
@Override
public boolean tryPass(Context context) {// 如果断路器的状态是CLOSED,则返回true,表示请求通过if (currentState.get() == State.CLOSED) {return true;}// 如果断路器的状态是OPENif (currentState.get() == State.OPEN) {// 判断是否到了熔断结束时间,如果到了则尝试将断路器的状态从OPEN变为HALF-OPENreturn retryTimeoutArrived() && fromOpenToHalfOpen(context);}// 剩余情况,返回false,表示请求不通过return false;
}
retryTimeoutArrived 方法
判断是否到了熔断结束时间
protected boolean retryTimeoutArrived() {// 判断当前时间 >= 下一次的熔断结束时间return TimeUtil.currentTimeMillis() >= nextRetryTimestamp;
}
fromOpenToHalfOpen 方法
尝试将断路器的状态从OPEN变为HALF-OPEN
protected boolean fromOpenToHalfOpen(Context context) {// 尝试将断路器的状态从OPEN更新为HALF_OPENif (currentState.compareAndSet(State.OPEN, State.HALF_OPEN)) {// 触发所有CircuitBreakerStateChangeObserver的onStateChange方法回调notifyObservers(State.OPEN, State.HALF_OPEN, null);Entry entry = context.getCurEntry();entry.whenTerminate(new BiConsumer<Context, Entry>() {@Overridepublic void accept(Context context, Entry entry) {// 如果调用过程中存在BlockException异常if (entry.getBlockError() != null) {// 将断路器的状态从HALF_OPEN更新为OPENcurrentState.compareAndSet(State.HALF_OPEN, State.OPEN);// 触发所有CircuitBreakerStateChangeObserver的onStateChange方法回调notifyObservers(State.HALF_OPEN, State.OPEN, 1.0d);}}});return true;}return false;
}
接下来重点看下 AbstractCircuitBreaker 的子类对于 onRequestComplete 方法的具体实现。
ResponseTimeCircuitBreaker
关注响应时间的断路器实现
public ResponseTimeCircuitBreaker(DegradeRule rule) {// 统计时长由熔断降级规则的statIntervalMs参数指定,默认1000,即1秒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;
}
看下 ResponseTimeCircuitBreaker 对于 onRequestComplete 方法的具体实现。
@Override
public 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();// 如果响应时间超过了阈值(对应熔断降级规则中的count参数)if (rt > maxAllowedRt) {// 慢请求数指标加一counter.slowCount.add(1);}// 总请求数指标加一counter.totalCount.add(1);handleStateChangeWhenThresholdExceeded(rt);
}
接下来看下 handleStateChangeWhenThresholdExceeded 方法的处理逻辑。
private void handleStateChangeWhenThresholdExceeded(long rt) {// 如果断路器的状态是OPEN,则直接返回if (currentState.get() == State.OPEN) {return;}// 如果断路器的状态是HALF_OPENif (currentState.get() == State.HALF_OPEN) {// 如果请求的响应时间超过了阈值if (rt > maxAllowedRt) {// 将断路器的状态更新为OPEN,然后更新下一次的熔断结束时间fromHalfOpenToOpen(1.0d);} else {// 将断路器的状态更新为CLOSED,然后重置慢请求数、总请求数指标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();}// 如果总请求数 < 熔断降级规则中的minRequestAmount参数,则直接返回if (totalCount < minRequestAmount) {return;}// 计算慢调用比例double currentRatio = slowCount * 1.0d / totalCount;// 如果慢调用比例 > 熔断降级队则中的slowRatioThreshold参数值(默认1)if (currentRatio > maxSlowRequestRatio) {// 将断路器的状态更新为OPEN,然后更新下一次的熔断结束时间transformToOpen(currentRatio);}// 如果当前的慢调用比例达到了100%if (Double.compare(currentRatio, maxSlowRequestRatio) == 0 &&Double.compare(maxSlowRequestRatio, SLOW_REQUEST_RATIO_MAX_VALUE) == 0) {// 将断路器的状态更新为OPEN,然后更新下一次的熔断结束时间transformToOpen(currentRatio);}
}
ExceptionCircuitBreaker
关注异常比例、异常数的断路器实现
public ExceptionCircuitBreaker(DegradeRule rule) {// 统计时长由熔断降级规则的statIntervalMs参数指定,默认1000,即1秒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;
}
看下 ExceptionCircuitBreaker 对于 onRequestComplete 方法的具体实现。
@Override
public 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);handleStateChangeWhenThresholdExceeded(error);
}
接下来看下 handleStateChangeWhenThresholdExceeded 方法的处理逻辑。
private void handleStateChangeWhenThresholdExceeded(Throwable error) {// 如果断路器的状态是OPEN,则直接返回if (currentState.get() == State.OPEN) {return;}// 如果断路器的状态是HALF_OPENif (currentState.get() == State.HALF_OPEN) {if (error == null) {// 将断路器的状态更新为CLOSED,然后重置慢请求数、总请求数指标fromHalfOpenToClose();} else {// 将断路器的状态更新为OPEN,然后更新下一次的熔断结束时间fromHalfOpenToOpen(1.0d);}// 直接返回return;}List<SimpleErrorCounter> counters = stat.values();long errCount = 0;long totalCount = 0;// 累加错误请求数、总请求数for (SimpleErrorCounter counter : counters) {errCount += counter.errorCount.sum();totalCount += counter.totalCount.sum();}// 如果总请求数 < 熔断降级规则中的minRequestAmount参数,则直接返回if (totalCount < minRequestAmount) {return;}double curCount = errCount;// 如果策略是统计异常数比例,则将异常数比例转化成错误请求数if (strategy == DEGRADE_GRADE_EXCEPTION_RATIO) {curCount = errCount * 1.0d / totalCount;}// 如果错误请求数 > 阈值if (curCount > threshold) {// 将断路器的状态更新为OPEN,然后更新下一次的熔断结束时间transformToOpen(curCount);}
}
相关文章:

Sentinel架构篇 - 熔断降级
熔断降级 概念 除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一。一个服务常常会调用其它模块,可能是一个远程服务、数据库、或者第三方 API 等。然而,被依赖的服务的稳定性是不能保证的。如果依赖的服…...

shell脚本的一些记录 与jenkins的介绍
shell 脚本的执行 sh ***.sh shell脚本里面的命令 其实就是终端执行一些命令 shell 连接服务器 可以直接ssh连接 但是这样最好是无密码的 不然后面的命令就不好写了 换而言之有密码得 不好写脚本 需要下载一些expect的插件之类的才可以 判断语句 的示例 需要注意的是…...

JVM的了解与学习
一:jvm是什么 jvm是java虚拟机java Virtual Machine的缩写 jdk包含jre和java DevelopmentTools 二:什么是java虚拟机 虚拟机是一种抽象化的计算机,通过在实际的计算机上仿真模拟各种计算机功能来实现的。java虚拟机有自己完善的硬体结构,如处理器、堆栈、寄存器等,还有…...

提升数字品牌的5个技巧
“品牌”或“品牌推广”的概念通常用于营销。因为建立您的企业品牌对于产品来说极其重要,品牌代表了您与客户互动的身份和声音。今天,让我们来看看在数字领域提升品牌的一些有用的技巧。如何在数字领域提升您的品牌?在了解这些技巧之前&#…...

java通过反射获取加了某个注解的所有的类
有时候我们会碰到这样的情况:有n个场景,每个场景都有自己的逻辑,即n个处理逻辑,这时候我们就需要通过某个参数的值代表这n个场景,然后去加载每个场景不同的bean对象,即不同的类,这些类中都有一个…...

Warshall算法
🚀write in front🚀 📜所属专栏:> 算法 🛰️博客主页:睿睿的博客主页 🛰️代码仓库:🎉VS2022_C语言仓库 🎡您的点赞、关注、收藏、评论,是对我…...

vector中迭代器失效的问题及解决办法
目录 vector常用接口 vector 迭代器失效问题 vector中深浅拷贝问题 vector的数据安排以及操作方式,与array非常相似。两者的唯一差别在于空间的运用的灵活性。array 是静态空间,一旦配置了就不能改变;要换个大(或小) 一点的房子&#x…...

【蓝桥杯刷题训练营】day05
1 数的分解 拆分成3个数相加得到该数 然后采用了一种巨愚蠢的办法: int main() {int count 0;int a 2;int b 0;int c 1;int d 9;int a1, a2, a3;int c1, c2, c3;int d1, d2, d3;for (a1 0; a1 < 2; a1){for (a2 0; a2 < 2; a2){for (a3 0; a3 <…...

线程中断interrupt导致sleep产生的InterruptedException异常
强制当前正在执行的线程休眠(暂停执行),以“减慢线程”。 Thread.sleep(long millis)和Thread.sleep(long millis, int nanos)静态方法当线程睡眠时,它睡在某个地方,在苏醒之前不会返回到可运行状态。 当睡眠时间到期…...

ubuntu的快速安装与配置
文章目录前言一、快速安装二 、基础配置1 Sudo免密码2 ubuntu20.04 pip更新源3 安装和配置oneapi(infort/mpi/mkl) apt下载第一次下载的要建立apt源apt下载(infort/mpi/mkl)4 安装一些依赖库等5 卸载WSLpython总结前言 win11系统 ubuntu20.04 提示:以下…...

人工智能AI工具汇总(AIGC ChatGPT时代个体崛起)
NameCategoryWebsiteDescription描述《AIGC时代:超级个体的崛起》小报童https://xiaobot.net/p/SuperIndividual 介绍AIGC,ChatGPT,使用技巧与搞钱方式。Masterpiece Studio3Dhttps://masterpiecestudio.comSimplifying 3D Creation with AI…...

【rust-grpc-proxy】在k8s中,自动注入代理到pod中,再不必为grpc调试而烦恼
目录前言原理sidecarwebhook实现安装k8s设置webhook使用尾语前言 rust-grpc-proxy 目前功能基本完善。是时候上环境开始应用了。 之前考虑是gateway模式或者sidecar模式。 思考良久之后,觉得两种模式都有使用场景,那就都支持。本次就带来sidecar模式的食…...

VisualStudio2022制作多项目模板及Vsix插件
一、安装工作负载 在vs2022上安装“visual studio扩展开发 ”工作负载 二、制作多项目模板 导出项目模板这个我就不再多说了(项目→导出模板→选择项目模板,选择要导出的项目→填写模板信息→完成)。 1.准备模板文件 将解决方案中的多个…...

仿写简单IOC
目录 TestController类: UserService类: 核心代码SpringIOC: Autowired和Component注解 SpringIOCTest 类 编辑 总结: TestController类: Component public class TestController {Autowiredprivate UserService userService;public void test…...

liunx下安装node exporter
1 建立文件夹 cd /opt mkdir software 下载最新的包,并解压 https://prometheus.io/download/ 下载 curl -LO https://github.com/prometheus/node_exporter/releases/download/v0.18.1/node_exporter-0.18.1.linux-amd64.tar.gz 3.解压 tar -xvf node_exporter-0.…...

lambda函数
Lambda(函数指针)lambda 是c11非常重要也是最常用的特性之一,他有以下优点:可以就地匿名定义目标函数或函数对象,不需要额外写一个函数lambda表达式是一个匿名的内联函数lambda表达式定义了一个匿名函数,语法如下:[cap…...

【Python入门第二十七天】Python 日期
Python 日期 Python 中的日期不是其自身的数据类型,但是我们可以导入名为 datetime 的模块,把日期视作日期对象进行处理。 实例 导入 datetime 模块并显示当前日期: import datetimex datetime.datetime.now() print(x)运行实例 2023-0…...

C++基础知识【5】数组和指针
目录 一、概述 数组 指针 二、数组 2.1、数组的声明 2.2、数组的初始化 2.3、数组的访问 2.4、多维数组 2.5、数组作为函数参数 三、指针 3.1、指针的声明 3.2、指针的赋值 3.3、指针的访问 3.4、指针运算 3.5、指针数组和数组指针 3.6、二级指针 四、数组和指…...

Vim使用操作命令笔记
Vim使用操作命令笔记在普通模式下,输入 : help tutor 就可以进入vim的教学 在 terminal 中输入 vim 文件名 就可以打开文件 vim有两种模式 normal mode (普通模式)→ 指令操作 insert mode (输入模式&…...

【论文阅读】Robust Multi-Instance Learning with Stable Instances
1、摘要与引言 以往的MIL算法遵循i.i.d假设:训练样本与测试样本都分别来自于同一分布中,而这一假设往往与现实应用中有所出入。研究人员通过计算训练样本与测试样本之间的密度比对训练样本进行加权,以解决分布变化带来的问题。 分布的变化发…...

洛谷 P5116 [USACO18DEC]Mixing Milk B
题目链接:P5116 [USACO18DEC]Mixing Milk B - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题目描述 农业,尤其是生产牛奶,是一个竞争激烈的行业。Farmer John 发现如果他不在牛奶生产工艺上有所创新,他的乳制品生意可能就会受…...

华为OD机试 - 最左侧冗余覆盖子串(C 语言解题)【独家】
最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧文章目录 使用说明本期题目:最左侧冗…...

实验7 图像水印
本次实验大部分素材来源于山大王成优老师的讲义以及冈萨雷斯(MATLAB版),仅作个人学习笔记使用,禁止用作商业目的。 文章目录一、实验目的二、实验例题1. 数字图像水印技术2. 可见水印的嵌入3. 不可见脆弱水印4. 不可见鲁棒水印一、…...

如何实现大文件断点续传、秒传
大家先来了解一下几个概念: 「文件分块」:将大文件拆分成小文件,将小文件上传\下载,最后再将小文件组装成大文件; 「断点续传」:在文件分块的基础上,将每个小文件采用单独的线程进行上传\下载&…...

备战蓝桥python——完全平方数
完全平方数 链接: 完全平方数 暴力解法: n int(input()) for i in range(1, n1):if(((i*n)**0.5)%10.0):print(i)break运用数论相关知识求解 任意一个正整数都可以被分解成若干个质数乘积的形式,例如 :2022∗5120 \ 2^{2}*5^{1}\,20 22∗51 由此…...

WebRTC中的NAT穿透
NAT简介 我们知道,WebRTC会按照内网、P2P、中转的顺序来尝试连接。在大部分的情况下,实际是使用P2P或者中转的。这里P2P的场景主要使用的技术就是NAT穿透。 我们先简单了解下NAT。NAT在真实网络中是常见的,它的出现一是为了解决ipv4地址不够…...

SpringCloud-高级篇(一)
目录: (1)初识Sentinel-雪崩问题的解决方案 (2)服务保护Sentinel和Hystrix对比 (3)Sentinel初始-安转控制台 (4)整合微服务和Sentinel 微服务高级篇 (1&…...

电脑自动重启是什么原因?详细解说
案例:电脑自动重启是什么原因? “一台用了一年的电脑,最近使用,每天都会一两次莫名其妙自动重启,看了电脑错误日志,看不懂什么意思,一直找不到答案。有没有高手知道怎么解决这个问题的。” 当…...

2023美国大学生数学建模竞赛E题思路
problem 背景: 光污染用于描述过度或不良使用人造光。我们称之为光污染的一些现象包括光侵入、过度照明和光杂波。在大城市,太阳落山后,这些现象最容易在天空中看到:然而,它们也可能发生在更偏远的地区。 光污染会改变我们对夜空…...