剖析sentinel的限流和熔断

sentinel的限流和熔断

  • 前言
  • 源码分析
    • 滑动窗口源码
    • 限流源码
    • 熔断源码
  • 完结撒花,sentinel源码还是挺简单的,如有需要收藏的看官,顺便也用发财的小手点点赞哈,如有错漏,也欢迎各位在评论区评论!

前言

平时发起一个请求,在系统内部微服务之间调用就会形成一条调用链路,那对于每个服务要起到保护的作用,如何保护呢?本文就来做一个介绍,笔者平时是使用sentinel居多,是通过其提供的限流和熔断的措施来保护的,于是文本来剖析sentinel的限流和熔断;
先介绍雪崩问题:
例如a1服务——》b服务——》c服务;
a2服务——》b服务——》c服务;
a3服务——》b服务;
d服务——》a3服务;
在a1服务调用b时,往下调用c服务,因服务c故障,会占用着b服务连接至超时时间,此时又会有服务a2调b服务,再调c服务,会因服务c故障,继续堆积连接在b服务上至连接超时,堆积到服务b性能瓶颈也会导致服务b故障,此时a3服务调用b服务也会继续导致a3服务堆积连接,依次导致所有服务故障,这就是雪崩
市面上解决雪崩的方案:
在这里插入图片描述
流量控制是限流的,用于保护下游服务,然后其余三种是下游发生了故障的前提下,保护上游服务的方案,其中舱壁模式,也是线程隔离,下游发生故障时,是为调上游的多个服务,建立属于它们的线程池,仍然会调下游,这样就会占用着线程;而熔断降级则不会,下游有问题,例如上游根据调用下游的失败比例、失败数来决定触发熔断;
所以说流量控制避免雪崩,有了流量控制就不会发生雪崩,而其余三种则解决雪崩问题;

再介绍限流与熔断的概念:
限流是保护当前服务,提前对服务做了qps限流保护;
熔断则是某个服务因没有限流发生了故障,然后上游调用该服务时,不会再调用了,而是在上游定义了关于该服务的降级逻辑,起到保护上游服务的作用,避免因为该服务的故障,导致雪崩问题;

那限流、熔断、雪崩之间的关系?
更像是因为没有限流容易导致服务提供方问题,然后服务消费方用熔断来保护自己,从而避免雪崩;

源码分析

在 Sentinel 里面,所有的资源都对应一个资源名称以及一个 Entry。Entry 可以通过对主流框架的适配自动创建,也可以通过注解的方式或调用 API 显式创建;每一个 Entry 创建的时候,同时也会创建一系列功能插槽(slot chain);
例如服务a——》服务b——》服务c,每个服务就是一个保护资源,默认是一个controller一个保护资源,在一个服务里其实可以有多个保护资源,用SentinelResource注解标识controller往后调的一个个service层的方法即可,sentinel对于保护资源的调用链路是如下图:
在这里插入图片描述
调用链路就是这8个slot,简单来说就是统计访问的qps,判断是否达到触发限流(FlowSlot)或熔断(DegradeSlot)阈值,每个slot抛出blockExeception,就代表访问停止了,就不会触发往后的slot调用,它是使用责任链模式调用的。
在这里插入图片描述
SentinelResource的切面,主要是调SphU.entry方法

//该方法是查找slot链,上面说的slot责任链就是指这个链
com.alibaba.csp.sentinel.CtSph#entryWithPriority
ProcessorSlot<Object> chain = this.lookProcessChain(resourceWrapper);//lookProcessChain方法:第一次访问资源时,使用copyOnWrite的方式添加到map中,后面就从map获取即可
ProcessorSlotChain chain = (ProcessorSlotChain)chainMap.get(resourceWrapper);if (chain == null) {synchronized(LOCK) {chain = (ProcessorSlotChain)chainMap.get(resourceWrapper);if (chain == null) {if (chainMap.size() >= 6000) {return null;}chain = SlotChainProvider.newSlotChain();Map<ResourceWrapper, ProcessorSlotChain> newMap = new HashMap(chainMap.size() + 1);newMap.putAll(chainMap);newMap.put(resourceWrapper, chain);chainMap = newMap;}}}//创建的slotChain是通过spi的方式从METAINFO目录获取所有的slotpublic ProcessorSlotChain build() {ProcessorSlotChain chain = new DefaultProcessorSlotChain();List<ProcessorSlot> sortedSlotList = SpiLoader.of(ProcessorSlot.class).loadInstanceListSorted();Iterator var3 = sortedSlotList.iterator();while(var3.hasNext()) {ProcessorSlot slot = (ProcessorSlot)var3.next();if (!(slot instanceof AbstractLinkedProcessorSlot)) {RecordLog.warn("The ProcessorSlot(" + slot.getClass().getCanonicalName() + ") is not an instance of AbstractLinkedProcessorSlot, can't be added into ProcessorSlotChain", new Object[0]);} else {//获取的每个slot形成一个AbstractLinkedProcessorSlot链表,因为每个slot继承了该类chain.addLast((AbstractLinkedProcessorSlot)slot);}}return chain;}
//创建完slotChain后,就开始执行每个slot
chain.entry(context, resourceWrapper, (Object)null, count, prioritized, args);public class DefaultProcessorSlotChain extends ProcessorSlotChain {AbstractLinkedProcessorSlot<?> first = new AbstractLinkedProcessorSlot<Object>() {//这里是第一个slot,从这里开始调用public void entry(Context context, ResourceWrapper resourceWrapper, Object t, int count, boolean prioritized, Object... args) throws Throwable {super.fireEntry(context, resourceWrapper, t, count, prioritized, args);}public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {super.fireExit(context, resourceWrapper, count, args);}};
}//调用下一个slot是通过当前slot的next属性(就是下一个slot元素)public void fireEntry(Context context, ResourceWrapper resourceWrapper, Object obj, int count, boolean prioritized, Object... args) throws Throwable {if (this.next != null) {this.next.transformEntry(context, resourceWrapper, obj, count, prioritized, args);}}

这里详细介绍了slot调用链路的过程,本文主要是关注限流和熔断,所以只需看FlowSlot和DegradeSlot即可;

滑动窗口源码

是用StatisticSlot统计访问资源的线程数、qps。
滑动窗口的原理:时间窗口设定qps阈值,先看看固定时间窗的缺点,一个时间窗口内是不会超出阈值,但一个时间窗的后半个时间窗和下一个时间窗的前半个时间窗加起来会超过阈值。于是将一个时间窗划分为多个时间样本,例如1s的时间窗划分为5个样本时间窗(每个200ms),即使统计到一个时间窗的后半个时间窗和后一个时间窗的前半个时间窗时,会统计每个样本时间窗来是否达到阈值,从而解决该问题;

注意:样本时间窗划分得越小,统计得越准确;

com.alibaba.csp.sentinel.slots.statistic.StatisticSlot#entry//访问链表所有的slotthis.fireEntry(context, resourceWrapper, node, count, prioritized, args);//统计线程数node.increaseThreadNum();//统计qpsnode.addPassRequest(count);

这里有觉得奇怪吗?先是访问所有的slot是否通过后(任何一个slot都不抛出BlockException),再统计资源的线程数和qps,其实是类似于elastic search写文档时,先写内存,然后再写transaction log文件,这样是为了写内存成功后再写入transaction log文件,不至于写入文件后,再回滚内存。同样是为了校验通过后,再统计,不至于统计完才校验失败。

基础知识:

在这里插入图片描述
这里是时间窗口类

在这里插入图片描述
时间窗口类包含的属性,以及包含的时间样本窗口类WindowWrap

public void addPass(int count) {//获取当前时间点所在的样本窗口WindowWrap<MetricBucket> wrap = this.data.currentWindow();//将当前请求的计数量添加到当前样本窗口的统计数据中((MetricBucket)wrap.value()).addPass(count);
}

就不往里跟了,主要是根据当前时间点统计是在当前时间窗的哪个样本时间窗里,然后往里添加

限流源码

在这里插入图片描述
对应的就是这些规则
是在FlowSlot中,根据staticFlow统计的qps、线程数,来判断是否达到阈值,从而触发限流

com.alibaba.csp.sentinel.slots.block.flow.FlowSlot#entry
public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, boolean prioritized, Object... args) throws Throwable {//检测并应用流控规则this.checkFlow(resourceWrapper, context, node, count, prioritized);//触发下一个slotthis.fireEntry(context, resourceWrapper, node, count, prioritized, args);
}public void checkFlow(Function<String, Collection<FlowRule>> ruleProvider, ResourceWrapper resource, Context context, DefaultNode node, int count, boolean prioritized) throws BlockException {if (ruleProvider != null && resource != null) {//获取到指定资源的所有流控规则Collection<FlowRule> rules = (Collection)ruleProvider.apply(resource.getName());if (rules != null) {Iterator var8 = rules.iterator();//这个应用流控规则。若是无法通过则抛出异常,后续规则不再应用while(var8.hasNext()) {FlowRule rule = (FlowRule)var8.next();if (!this.canPassCheck(rule, context, node, count, prioritized)) {throw new FlowException(rule.getLimitApp(), rule);}}}}}

熔断源码

public class DegradeSlot extends AbstractLinkedProcessorSlot<DefaultNode> {public void entry(Context context, ResourceWrapper resourceWrapper, DefaultNode node, int count, boolean prioritized, Object... args) throws Throwable {this.performChecking(context, resourceWrapper);this.fireEntry(context, resourceWrapper, node, count, prioritized, args);}void performChecking(Context context, ResourceWrapper r) throws BlockException {//获取当前资源所有熔断器List<CircuitBreaker> circuitBreakers = DegradeRuleManager.getCircuitBreakers(r.getName());if (circuitBreakers != null && !circuitBreakers.isEmpty()) {Iterator var4 = circuitBreakers.iterator();CircuitBreaker cb;//逐个尝试所有熔断器do {if (!var4.hasNext()) {return;}cb = (CircuitBreaker)var4.next();//若没有通过当前熔断器,则直接抛出异常} while(cb.tryPass(context));throw new DegradeException(cb.getRule().getLimitApp(), cb.getRule());}}
}

在这里插入图片描述
一般来说,熔断降级其实是对于服务的调用方来说的。在项目中会经常调用其它服务或者是第三方接口,而对于这些接口,一旦它们出现不稳定,就有可能导致自身服务长时间等待,从而出现响应延迟等等问题。此时服务调用方就可基于熔断降级方式解决。一旦第三方接口响应时间过长,那么就可以使用慢调用比例规则,当出现大量长时间响应的情况,那么就直接熔断,不去请求。虽然说熔断降级是针对服务的调用方来说,但是Sentinel本身并没有限制熔断降级一定是调用其它的服务。

完结撒花,sentinel源码还是挺简单的,如有需要收藏的看官,顺便也用发财的小手点点赞哈,如有错漏,也欢迎各位在评论区评论!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/898019.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

硬盘分区误删后的数据救赎

一、硬盘分区误删的概述 硬盘分区误删&#xff0c;是许多电脑用户在使用过程中可能遭遇的棘手问题。分区&#xff0c;作为硬盘上存储数据的逻辑单元&#xff0c;一旦被误删除&#xff0c;不仅会导致该分区内的所有数据瞬间消失&#xff0c;还可能影响到整个硬盘的存储结构和数…

代码随想录算法训练营第三十五天(20250303) |01背包问题 二维,01背包问题 一维,416. 分割等和子集 -[补卡20250316]

01背包问题 二维 链接 遍历物品没有大小顺序要求重点是模拟&#xff0c;推导出递推公式 #include <iostream> #include <vector>int main(){int m, n;std::cin>>m>>n;std::vector<int> weight(m,0),value(m,0);for(int i{0}; i<m; i){std:…

老牌软件,方便处理图片,量大管饱。

今天介绍的图片查看器名字是&#xff1a;FastStone Image Viewer&#xff0c;是一款可查看、编辑、批量重命名、批量转换的图片查看软件。文末有分享链接。 软件以资源管理器的方式管理你电脑里的图片&#xff0c;点击左侧可选择文件夹&#xff0c;右边可预览图片。 软妹用得最…

【数据库相关】mysql数据库巡检

mysql数据库巡检 巡检步骤**一、基础状态检查****二、服务器资源监控****CPU使用****内存使用****磁盘I/O****网络流量** **三、数据库内部健康度****全局状态****慢查询监控****锁与并发** **四、存储引擎健康****InnoDB引擎****MyISAM引擎** **五、日志与备份****六、安全与权…

Python进阶编程总结

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;…

Redis复制(replica)主从模式

Redis主从复制 Redis 的复制&#xff08;replication&#xff09;功能允许用户根据一个 Redis 服务器来创建任意多个该服务器的复制品&#xff0c;其中被复制的服务器为主服务器&#xff08;master&#xff09;&#xff0c;而通过复制创建出来的服务器复制品则为从服务器&#…

Adobe Premiere Pro2023配置要求

Windows 系统 最低配置 处理器&#xff1a;Intel 第六代或更新版本的 CPU&#xff0c;或 AMD Ryzen™ 1000 系列或更新版本的 CPU&#xff0c;需要支持 Advanced Vector Extensions 2&#xff08;AVX2&#xff09;。操作系统&#xff1a;Windows 10&#xff08;64 位&#xff…

【Kubernets】Deployment 和 StatefulSet 有什么区别?什么时候用 StatefulSet?

Deployment 和 StatefulSet 的区别 在 Kubernetes 中&#xff0c;Deployment 和 StatefulSet 都用于管理 Pod&#xff0c;但它们适用于不同的场景。 1. Deployment&#xff1a;管理无状态应用 特点&#xff1a; 无状态&#xff1a;Pod 之间相互独立&#xff0c;不需要保持顺…

R语言零基础系列教程-03-RStudio界面介绍与关键设置

代码、讲义、软件回复【R语言03】获取。 设置位置: 菜单栏 - Tools - Blobal Options 设置 通用设置 设置面板左侧General选项 版本选择: 一般只用一个版本即可 默认工作目录设置: 你希望RStudio打开时是基于哪个目录进行工作可以不设置, 因为脚本一般都是放置在特定项目路…

车载以太网测试-9【网络层】-子网划分的子网掩码VLAN

目录 1 摘要2 子网划分2.1 子网掩码2.2 VLAN&#xff08;虚拟局域网&#xff09;2.2.1 IEEE 802.1Q VLAN标签2.2.1.1 VLAN标签的结构2.2.1.2 VLAN标签的插入2.2.1.3 VLAN标签的处理2.1.2.4 PVID&#xff08;Port VLAN Identifier&#xff09; 和 VID&#xff08;VLAN Identifie…

微信小程序刷题逻辑实现:技术揭秘与实践分享

页面展示&#xff1a; 概述 在当今数字化学习的浪潮中&#xff0c;微信小程序以其便捷性和实用性&#xff0c;成为了众多学习者刷题备考的得力工具。今天&#xff0c;我们就来深入剖析一个微信小程序刷题功能的实现逻辑&#xff0c;从代码层面揭开其神秘面纱。 小程序界面布局…

JVM--垃圾回收

垃圾回收的概念 垃圾回收主要针对的是堆中的对象&#xff0c;堆是一个共享的区域&#xff0c;创建的对象和数组都放在这个位置。但是我们不能一直的创建对象&#xff0c;也不是所有的对象能一直存放&#xff0c;如果不进行垃圾回收&#xff0c;内存迟早会耗尽&#xff0c;及时…

【教程】继承中的访问控制 C++

目录 简介public&#xff0c;protected 和 private继承中的 public&#xff0c;protected 和 private示例 简介 在 C 中派生类可以通过 public&#xff0c;protected 和 private 三种修饰符决定基类成员在派生类中的访问级别 public&#xff0c;protected 和 private 公有成…

【2025】基于python+django的驾校招生培训管理系统(源码、万字文档、图文修改、调试答疑)

课题功能结构图如下&#xff1a; 驾校招生培训管理系统设计 一、课题背景 随着机动车保有量的不断增加&#xff0c;人们对驾驶技能的需求也日益增长。驾校作为驾驶培训的主要机构&#xff0c;面临着激烈的市场竞争和学员需求多样化等挑战。传统的驾校管理模式往往依赖于人工操作…

要登录的设备ip未知时的处理方法

目录 1 应用场景... 1 2 解决方法&#xff1a;... 1 2.1 wireshark设置... 1 2.2 获取网口mac地址&#xff0c;wireshark抓包前预过滤掉自身mac地址的影响。... 2 2.3 pc网口和设备对接... 3 2.3.1 情况1&#xff1a;... 3 2.3.2 情…

一.ffmpeg打开麦克风,录制音频并重采样

一.windows windows下使用msys编译ffmpeg&#xff0c;先编译libx264和libx265&#xff0c;然后编译ffmpeg的时候需要添加这两个库的路径才能--enable&#xff1b;为什么ffplay--enable了还是没有呢&#xff0c;仔细看编译打印&#xff0c;可能刚有一段报错提示SDL找不到&#…

go 安装swagger

1、依赖安装&#xff1a; # 安装 swag 命令行工具 go install github.com/swaggo/swag/cmd/swaglatest# 安装 gin-swagger 和 swagger 文件的依赖 go get -u github.com/swaggo/gin-swagger go get -u github.com/swaggo/files 2、测试 cmd中输入&#xff1a; swag -v 如果…

网络安全反渗透 网络安全攻防渗透

网络渗透防范主要从两个方面来进行防范&#xff0c;一方面是从思想意识上进行防范&#xff0c;另一方面就是从技术方面来进行防范。 1.从思想意识上防范渗透 网络攻击与网络安全防御是正反两个方面&#xff0c;纵观容易出现网络安全事故或者事件的公司和个人&#xff0c;在这些…

java泛型通配符?及上下界(extends,super)保证安全性、灵活性、可读性

在 Java 中&#xff0c;泛型通配符&#xff08;?&#xff09;用于表示未知类型&#xff0c;通常用于增强泛型的灵活性。通配符可以与上下限结合使用&#xff0c;以限制泛型的范围。以下是通配符及上下限的使用示例&#xff1a; 1. 无界通配符 (?) 无界通配符表示可以接受任意…

技术视界|构建理想仿真平台,加速机器人智能化落地

在近期的 OpenLoong 线下技术分享会 上&#xff0c;松应科技联合创始人张小波进行了精彩的演讲&#xff0c;深入探讨了仿真技术在机器人智能化发展中的关键作用。他结合行业趋势&#xff0c;剖析了现有仿真平台的挑战&#xff0c;并描绘了未来理想仿真系统的设计理念与实现路径…