SpringCloud之Hystrix高版本熔断器源码解析

news2024/12/23 5:06:27

Hystrix官方已经停止开发了,Hystrix官方推荐使用新一代熔断器作为Resilience4j。作为新一代的熔断器,Resilience4j有很多优势,比如依赖少,模块化程度较好等优势。

Resilience4j是受Hystrix启发而做的熔断器,通过管理远程调用的容错处理来帮助实现一个健壮的系统。resilience4j提供了更好用的API,并且提供了很多其他功能比如Rate Limiter(限流器)、Bulkhead(舱壁隔离)、熔断器、重试、缓存、限时器等。

  1. 限时器
    引入resilience4j-timelimiter[6]依赖。可以使用TimeLimiter限制调用远程服务所花费的时间。

  2. 重试
    引入resilience4j-retry[4]库。

    用户可参与的设置:

    • 最大尝试数。
    • 重试前等待时间。
    • 自定义函数,用于修改故障后的等待间隔。
    • 自定义谓词,用于评估异常是否应重试。
  3. 舱壁隔离
    引入resilience4j-bulkhead[3]依赖。可以限制对特定服务的并发调用数。

    用户可参与的设置:允许的最大并行数、线程等待的最大时间。

  4. 限流器
    引入resilience4j-ratelimiter[2]依赖。可以允许限制对某些服务的访问。用户可参与的设置:limit刷新周期、刷新周期的权限限制、默认等待权限持续时间。

  5. 熔断器

    熔断器有三种可能状态:

    • 关闭:服务正常,不需要进行短路。
    • 打开:远程服务宕机,所有请求都短路。
    • 半开:进入打开状态一段时间后,熔断器允许检查远程服务是否恢复。

    用户可参与的设置:

    • 熔断器进入打开状态的阈值。
    • 等待时间,即熔断器进入打开状态到半开状态需要等待的时间。
    • 熔断器半开或者闭合时,ring buffer的大小。
    • 处理自定义事件的监听器。
    • 自定义谓词,用于评估异常是否应算作故障,从而提高故障率。

FeignAutoConfiguration、BulkheadAutoConfiguration【舱壁隔离的核心类】、RetryAutoConfiguration【重试功能的核心类】、CircuitBreakerAutoConfiguration【熔断器的核心类】、RateLimiterAutoConfiguration【限流器的核心类】、TimeLimiterAutoConfiguration【限时器的核心类】。

FeignAutoConfiguration核心类中熔断器功能的引导类之Targeter子类FeignCircuitBreakerTargeter。

feign.circuitbreaker.enabled【false】:则通过DefaultTargeter路由至抽象类Feign完成Feign客户端的代理【ReflectiveFeign利用InvocationHandler之FeignInvocationHandler】。

feign.circuitbreaker.enabled【true】:则通过FeignCircuitBreakerTargeter路由至FeignCircuitBreaker完成【Feign客户端】的代理【ReflectiveFeign利用InvocationHandler之FeignCircuitBreakerInvocationHandler、MethodHandler之SynchronousMethodHandler】。

SynchronousMethodHandler内部是通过客户端FeignBlockingLoadBalancerClient完成请求的执行。

1.resilience4j涉及的相关配置类

public class CommonProperties {

    Map<String, String> tags = new HashMap<>();
    public Map<String, String> getTags() {
        return tags;
    }
    public void setTags(Map<String, String> tags) {
        this.tags = tags;
    }
}

父类CommonProperties涉及的子类包含RateLimiterConfigurationProperties、CircuitBreakerConfigurationProperties、RetryConfigurationProperties、TimeLimiterConfigurationProperties等。

2.FeignCircuitBreakerInvocationHandler

class FeignCircuitBreakerInvocationHandler implements InvocationHandler {
	private final boolean c;
	@Override
	public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
		...
		String circuitName = circuitBreakerNameResolver.resolveCircuitBreakerName(feignClientName, target, method);
		// 如果存在链路追踪sleuth选择TraceCircuitBreaker,否则选择Resilience4JCircuitBreaker
		CircuitBreaker circuitBreaker = c ? factory.create(circuitName, feignClientName): factory.create(circuitName);
		Supplier<Object> supplier = asSupplier(method, args);
		if (this.nullableFallbackFactory != null) {
			Function<Throwable, Object> fallbackFunction = throwable -> {
				Object fallback = this.nullableFallbackFactory.create(throwable);
				// 执行降级逻辑
				return this.fallbackMethodMap.get(method).invoke(fallback, args);
			};
			//通过TraceCircuitBreaker的CircuitBreaker类型的属性之delegate取值Resilience4JCircuitBreaker完成下游服务的调用
			return circuitBreaker.run(supplier, fallbackFunction);
		}
		return circuitBreaker.run(supplier);
	}
		
	private Supplier<Object> asSupplier(final Method method, final Object[] args) {
		final RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
		final Thread caller = Thread.currentThread();
		return () -> {
			// 利用SynchronousMethodHandler完成目标方法的调用
			return dispatch.get(method).invoke(args);
		};
	}
}

2.1.Resilience4JCircuitBreaker

public class Resilience4JCircuitBreaker implements CircuitBreaker {
	private final ExecutorService executorService;
	public <T> T run(Supplier<T> toRun, Function<Throwable, T> fallback) {
		io.vavr.collection.Map<String, String> tags = io.vavr.collection.HashMap.of("group",this.groupName);
		CircuitBreaker defaultCircuitBreaker = registry.circuitBreaker(this.id,this.circuitBreakerConfig, tags);
		circuitBreakerCustomizer.ifPresent(customizer -> customizer.customize(defaultCircuitBreaker));
		TimeLimiter timeLimiter = timeLimiterRegistry.timeLimiter(id, timeLimiterConfig, tags);
		if (bulkheadProvider != null) {
			return bulkheadProvider.run(this.groupName, toRun, fallback, defaultCircuitBreaker, timeLimiter, tags);
		}else {
			if (executorService != null) {
				// 异步触发Ribbon调用下游服务
				Supplier<Future<T>> futureSupplier = () -> executorService.submit(toRun::get);
				Callable restrictedCall = TimeLimiter.decorateFutureSupplier(timeLimiter, futureSupplier);
				Callable<T> callable = CircuitBreaker.decorateCallable(defaultCircuitBreaker, restrictedCall);
				
				return Try.of(callable::call)// 第一步:触发decorateCallable的Lambda表达式执行
							  .recover(fallback).get();// 第一步中存在异常则在recover内部回调fallback执行降级逻辑
			}else {Supplier<T> decorator = CircuitBreaker.decorateSupplier(defaultCircuitBreaker, toRun);
				return Try.of(decorator::get).recover(fallback).get();
			}
		}
	}
}
public interface CircuitBreaker {

	static <T> Callable<T> decorateCallable(CircuitBreaker circuitBreaker, Callable<T> callable) {
	    return () -> {
	        circuitBreaker.acquirePermission();
	        final long start = circuitBreaker.getCurrentTimestamp();
	        try {
	            T result = callable.call();//第二步:触发 TimeLimiter#decorateFutureSupplier的Lambda表达式执行
	            long duration = circuitBreaker.getCurrentTimestamp() - start;//下游服务响应花费的时间
	            circuitBreaker.onResult(duration, circuitBreaker.getTimestampUnit(), result);
	            return result;// 成功返回响应结果
	        } catch (Exception exception) {
	            long duration = circuitBreaker.getCurrentTimestamp() - start;
	            circuitBreaker.onError(duration, circuitBreaker.getTimestampUnit(), exception);
	            throw exception;
	        }
	    };
	}
}

3.限时器之TimeLimiter

public class TimeLimiterImpl implements TimeLimiter {
	
	private final TimeLimiterConfig timeLimiterConfig;
	
	public TimeLimiterImpl(String name, TimeLimiterConfig config,io.vavr.collection.Map<String, String> tags) {
        this.name = name;
        this.tags = Objects.requireNonNull(tags, "Tags must not be null");
        this.timeLimiterConfig = config;
        this.eventProcessor = new TimeLimiterEventProcessor();
    }
	public <T, F extends Future<T>> Callable<T> decorateFutureSupplier(Supplier<F> futureSupplier) {
	    return () -> {
	        Future<T> future = futureSupplier.get();// 第三步:触发 Lambda表达式之Supplier执行,即触发Ribbon调用下游服务
	        try {
	        	// 从timeLimiterConfig获取限时时间,如果在限时时间内没有得到下游服务的响应,则降级处理
	            T result = future.get(getTimeLimiterConfig().getTimeoutDuration().toMillis(),TimeUnit.MILLISECONDS);
	            onSuccess();
	            return result;// 成功返回响应结果
	        } catch (TimeoutException e) {//限时时间内没有得到下游服务的响应,则降级处理
	            TimeoutException timeoutException = TimeLimiter.createdTimeoutExceptionWithName(name, e);
	            onError(timeoutException);
	            if (getTimeLimiterConfig().shouldCancelRunningFuture()) {
	                future.cancel(true);
	            }
	            throw timeoutException;
	        }
	    };
	}
}

4.熔断策略

在这里插入图片描述

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

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

相关文章

【动手学深度学习】课程笔记 00-03 深度学习介绍及环境配置

目录 00-01 课程安排 02 深度学习介绍 深度学习实际应用的流程 完整的故事 03 环境配置 00-01 课程安排 1. 学习了这门课&#xff0c;你将收获什么&#xff1f; 深度学习的经典和最新模型&#xff1a;LeNet&#xff0c;ResNet&#xff0c;LSTM&#xff0c;BERT&#xff1…

Linux程序崩溃时的信号量(signal)说明

一、概念说明 在程序崩溃的时候&#xff0c;我们将会获取到两个信息: • signal: 信号量&#xff0c;下文将会详细的说明不同的信号量及其含义 • code: 错误码, 除了几个所有信号量(signal) 公共的错误码(code)&#xff0c;一般不同信号量(signal)有特定的错误码(code)&#x…

智能工业通信解决方案!钡铼BL124实现Modbus转Ethernet/IP互联!

钡铼技术BL124 Modbus转Ethernet/IP协议网关是一款专为工业自动化领域而设计的先进设备。它提供了可靠的通信解决方案&#xff0c;能够将Modbus通信协议与Ethernet/IP通信协议进行高效转换&#xff0c;实现不同类型设备之间的无缝集成和通信。 添加图片注释&#xff0c;不超过 …

冲刺十五届蓝桥杯P0004递增三元组

文章目录 题目解析代码如下 题目 递增三元组 解析 用到线性代数的知识&#xff0c;原来的三元组一共有27钟组合&#xff0c;不一一列举了。如果将三元组排序一下&#xff0c;得到的27钟组合和原来时一样的&#xff0c;只是顺序变了而已。 我们以b组为核心&#xff0c;遍历b组…

矢量图绘制软件EazyDraw mac中文版软件介绍

EazyDraw mac是一款功能强大且易于使用的矢量绘图软件。 EazyDraw mac软件介绍 矢量绘图工具&#xff1a;EazyDraw 提供了一套全面的矢量绘图工具&#xff0c;包括直线、曲线、多边形、文本框、图形填充等。用户可以使用这些工具创建和编辑精确的矢量图形&#xff0c;无论是简…

电动主轴与气动主轴的优缺点

随着工业自动化的不断发展&#xff0c;主轴的应用越来越广泛&#xff0c;并且不断改进优化。目前&#xff0c;市面上常用的主轴主要有两种&#xff1a;电动主轴和气动主轴。为了更好地选择和使用主轴&#xff0c;我们需要了解电动主轴和气动主轴各有什么优缺点&#xff1f; 电动…

徐明君:企业管理的新视角,业务与行为的整合

随着社会的发展和科技的进步&#xff0c;企业管理在社会化大生产的背景下愈显重要。近日&#xff0c;在一次企业管理的论坛上&#xff0c;众多业界人士针对企业管理的新视角进行了深入探讨&#xff0c;强调了业务管理和行为管理并重的重要性。 业务管理主要侧重于对企业的各种…

CS5366最新设计电路|Typec转HDMI 8K带PD方案设计|带DSC视频压缩技术Typec扩展方案

CS5366支持4K24/25/30/50/60Hz刷新率的HDR&#xff0c;CS5366集成DSC decoded影像解压缩技术,可将DPRX 4Lanes等效宽推升至97.2Gbps或 DPRX 2Lanes等效带宽推升至48.6Gbps ,此功能可改善画面延迟、影像撕裂等问题,可让用户在观看电影或是电玩游戏等高效能影像时有更好的体验。…

unity设计模式——代理模式

Subject类&#xff0c;定义了Real Subject和Proxy的共用接口&#xff0c;这样就在任何使用Real Subject的地方都可以使用Proxy。 abstract class Subject : MonoBehaviour {public abstract void Request(); } RealSubject类&#xff0c;定义Proxy所代表的真实实体。 class R…

nginx高可用配置(五)

keepalived keepalived安装 1.#进入根目录下的 usr目录 cd /usr 2.#安装keepalived yum install keepalived -y 3.安装完成后在根目录etc下会有个keepalived目录 4.进入keepalived目录 cd keepalived/ 5.ll命令查看&#xff0c;会有个配置文件 keepalived.conf 6.ke…

【已解决】Python打包文件执行报错:ModuleNotFoundError: No module named ‘pymssql‘

【已解决】Python打包文件执行报错&#xff1a;ModuleNotFoundError: No module named pymssql 1、问题2、原因3、解决 1、问题 今天打包一个 tkinter pymssql 的项目的时候&#xff0c;打包过程很顺利&#xff0c;但是打开软件的时候&#xff0c;报错 ModuleNotFoundError: …

何林达获得“软件方法建模师”称号

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 何林达做对所有强化自测题&#xff0c;获得“软件方法建模师”称号。 软件方法建模师 满分完成当前所有《软件方法》强化自测题的同学&#xff0c;可获得“软件方法建模师”的称号。…

GPT系列论文解读:GPT-3

GPT系列 GPT&#xff08;Generative Pre-trained Transformer&#xff09;是一系列基于Transformer架构的预训练语言模型&#xff0c;由OpenAI开发。以下是GPT系列的主要模型&#xff1a; GPT&#xff1a;GPT-1是于2018年发布的第一个版本&#xff0c;它使用了12个Transformer…

zabbix监控,zabbix部署

目录 zabbix监控 zabbix概述 zabbix 监控原理 zabbix 6.0功能组件 1、Zabbix Server 2、数据库 3.、Web 界面 4、Zabbix Agent 5、Zabbix Proxy 6、Java Gateway Zabbix部署 部署 zabbix 服务端 zabbix的客户端部署 自我监控 添加zabbix的其他客户端主机 zabbix…

BUGKU-simple_SSTI_1漏洞注入

SSTI漏洞注入 SSTI全称Server side template injection.服务端模板注入这节课主要讲flask的模板注入.flask会把类似于 的变量当做参数来渲染并填充到web页面,如果该参数可控并被后台解析则有可能被注入恶意代码导致注入漏洞请注意 模板注入只会存在于二次渲染中,无二次渲染不会…

漏刻有时数据可视化Echarts组件开发(39)splitLine网格线效果

splitLine设置坐标轴网格线的样式 show&#xff1a;是否显示网格线。默认为true。lineStyle&#xff1a;线条样式&#xff0c;包括类型&#xff08;type&#xff09;、颜色&#xff08;color&#xff09;、宽度&#xff08;width&#xff09;等。例如&#xff0c;可以设置为da…

JVM篇---第九篇

系列文章目录 文章目录 系列文章目录一、什么是指针碰撞&#xff1f;二、什么是空闲列表三、什么是TLAB&#xff1f; 一、什么是指针碰撞&#xff1f; 一般情况下&#xff0c;JVM的对象都放在堆内存中&#xff08;发生逃逸分析除外&#xff09;。当类加载检查通过后&#xff0…

【自用】ubuntu 18.04 LTS安装opencv 3.4.16 + opencv_contrib 3.4.16

1.下载 opencv 3.4.16 opencv_contrib 3.4.16 其中&#xff0c;opencv_contrib解压后的多个文件夹复制到opencv内、合并 声明&#xff1a;尚未验证该方式是否可行 2.安装 参考博文&#xff1a; https://zhuanlan.zhihu.com/p/650792342 https://zhuanlan.zhihu.com/p/8719780…

Java基于SpringBoot 的汽车租赁系统

1 简介 致远汽车租赁管理方面的任务繁琐,以至于公司每年都在致远汽车租赁管理这方面投入较多的精力却效果甚微,致远汽车租赁系统的目标就是为了能够缓解致远汽车租赁管理工作方面面临的压力,让致远汽车租赁管理方面的工作变得更加高效准确。 文章首发地址 2 技术栈 开发语言…

前端实现chatGpt流式输出 - SSE

前端实现chatGpt流式输出 - SSE 一、chatGpt流式输出技术分析 在使用ChatGPT时&#xff0c;模型的回复内容是连续输出&#xff0c;而不是整段话直接出现&#xff0c;因为模型需要不断预测接下来要回复什么内容&#xff0c;如果等整段回复生成之后再输出到网页&#xff0c;用户…