Retry重试机制(五十)

news2024/11/24 6:40:59

当新的世界出现,请立即向他奔去

上一章简单介绍了Melody 监控(四十九), 如果没有看过,请观看上一章

本章节文章参考:

https://juejin.cn/post/7234107489390116925

https://blog.csdn.net/hongyuan19/article/details/118995696

一. 重试

一.一 什么是重试

重试是指,当在一个程序运行过程中,突然遇到了例如网络延迟,中断等情况时,

为了保证程序容错性,可用性,一致性等的一个措施.

目前主流的框架大多都有一套自己的重试机制,例如 dubbo,mq,Spring 等

一.二 Spring 的 重试机制

Spring 也自己实现了一套重试机制,Spring Retry 是从 Spring batch 中独立出来的一个功能,

主要功能点在于重试和熔断,目前已经广泛应用于 Spring Batch,Spring Integration, Spring for Apache Hadoop 等 Spring 项目。

spring retry 提供了注解和编程 两种支持,提供了 RetryTemplate 支持,类似 RestTemplate。

整个流程如下:

image-20230608201245481

二. 重试机制

二.一 未使用重试机制

编写一个有很大概率 产生异常的方法

	@Override
	public void noRetry() throws Exception {
		Random random = new Random(System.currentTimeMillis());
		int nextNum = random.nextInt(10);
		if (nextNum >= 3) {
			log.error(">>>> 运行时间是:{},超时失败", nextNum);
			throw new Exception("运行超时");
		} else {
			log.info(">>>>>>>运行成功");
		}
	}

编写一个 Controller 进行调用

@RestController
public class RetryController {
	
	@Resource
	private UserBusiness userBusiness;
	
	@GetMapping("/noRetry")
	public String noRetry() {
		try {
			userBusiness.noRetry();
			return "运行成功";
		} catch (Exception e) {
			return "运行失败";
		}
	}
}

访问网址: http://localhost:8081/noRetry

运行到第二次的时候,就失败了

image-20230608201547329

对应的控制台日志是:

image-20230608201609357

失败时,只运行一次。

二.二 Spring 重试机制

二.二.一 pom.xml 添加依赖

<!--添加重试的依赖-->
        <dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
        </dependency>

二.二.二 启用重试注解

在启动类上添加 @EnableRetry 注解

@SpringBootApplication
// 开启注解
@EnableRetry
public class RetryApp {
	public static void main(String[] args) {
		SpringApplication.run(RetryApp.class, args);
	}
}

二.二.三 方法添加 @Retryable 注解

按照之前的,新复制一个方法。

添加 @Retryable 注解

	/**
	 * value 表示 何种异常时,进行重试.
	 * maxAttempts 重试的次数,默认是 3次
	 * <p>
	 * backoff 表示 第一次调用失败时,执行的策略。
	 * delay 表示, 第一次隔多长时间 2s 后重新调用.
	 * multiplier 表示 重试的延迟倍数, 刚开始是 2s, 后来是 2*2 =4 秒, 再后来是 4*2 = 8s
	 *
	 * @Recover 表示重试一直失败,到了最大重试次数后调用
	 */
	
	@Override
	@Retryable(value = Exception.class, maxAttempts = 3, backoff = @Backoff(delay = 2000, multiplier = 2))
	public void retry() throws Exception {
		Random random = new Random(System.currentTimeMillis());
		int nextNum = random.nextInt(10);
		if (nextNum >= 3) {
			log.error(">>>> 运行时间是:{},超时失败", nextNum);
			throw new Exception("运行超时");
		} else {
			log.info(">>>>>>>运行成功,运动时间是:{}", nextNum);
		}
	}

对应的 Controller 方法是

@GetMapping("/retry")
	public String retry() {
		try {
			userBusiness.retry();
			return "运行成功";
		} catch (Exception e) {
			return "运行失败";
		}
	}

二.二.四 请求验证

前端请求:

http://localhost:8081/retry

image-20230608202104999

目前运行三次后,结果仍是失败, 查看控制台:

image-20230608202126175

查看一个重试结果,最后是成功的

image-20230608202509079

查看控制台, 第二次是成功的。

image-20230608202524728

三. Retry 深入了解

三.一 重试 兜底操作

现在如果重试三次仍然失败后, 没有任何的处理。 希望在三次失败后,有一个兜底的操作机制

采用 @Recover 注解进行兜底

	/**
	 * 重试一直失败 调用 。
	 * 如果一直失败,则抛出异常。 这样,外部才可以捕获到
	 */
	@Recover
	public void retryUtilException() throws Exception  {
		log.error(">>>>>重试一直失败,执行一个兜底的操作");
		throw new Exception("一直失败,但还是要努力噢");
	}

当运行三次,仍然失败时:

image-20230608203131986

三.二 熔断模式

熔断模式采用注解 @CircuitBreaker

指在具体的重试机制下失败后打开断路器,过了一段时间,断路器进入半开状态,允许一个进入重试,

若失败再次进入断路器,成功则关闭断路器,注解为 @CircuitBreaker ,具体包括熔断打开时间、重置过期时间

@CircuitBreaker(openTimeout = 10000, maxAttempts =  3,resetTimeout = 3000, value = Exception.class)
	public void circuit() throws Exception {
		log.info(">>> 不好了,触发熔断了");
		throw new Exception("触发了熔断异常");
	}

openTimeout 时间范围内失败 maxAttempts 次数后,熔断打开 resetTimeout 时长

这个方法的意思就是方法在一秒内失败三次时,触发熔断,下次在有请求过来时,直接进入熔断方法

该功能没有执行成功,哎,
有谁知道如何处理这一个,请底下评论一下,谢谢噢。

三.三 Spring 配置文件 配置重试策略信息

三.三.一 配置文件中定义重试的信息

image-20230608204252213

三.三.二 引入配置文件

@SpringBootApplication
// 开启注解
@EnableRetry
// 引入配置文件
@PropertySource("classpath:retryConfig.properties")
public class RetryApp {
	public static void main(String[] args) {
		SpringApplication.run(RetryApp.class, args);
	}
}

三.三.三 重试方法编写

通过 ${} 进行引用

	/**
	 * 使用的是表达式配置处理
	 */
	
	@Override
	@Retryable(value = Exception.class, maxAttemptsExpression = "${retry.maxAttempts}",
			backoff = @Backoff(delayExpression = "${retry.delay}", maxDelayExpression = "${retry.maxDelay}", multiplierExpression = "${retry.multiplier}"))
	public void propertyRetry() throws Exception {
		
		Random random = new Random(System.currentTimeMillis());
		int nextNum = random.nextInt(10);
		if (nextNum >= 1) {
			log.error(">>>> 运行时间是:{},超时失败", nextNum);
			throw new Exception("运行超时");
		} else {
			log.info(">>>>>>>运行成功,运动时间是:{}", nextNum);
		}
	}

Controller 层调用

	@GetMapping("/propRetry")
	public String propRetry() {
		try {
			userBusiness.propertyRetry();
			return "运行成功";
		} catch (Exception e) {
			return "运行失败";
		}
	}

也会进行重试操作

image-20230608204506471

三.四 RetryTemplate 进行重试处理

三.四.一 定义重试的 Bean RetryTemplate

@Configuration
public class RetryConfig {
	
	@Bean
	public RetryTemplate retryTemplate() {
		RetryTemplate retryTemplate = new RetryTemplate();
		
		FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
		//设置重试回退
		fixedBackOffPolicy.setBackOffPeriod(2000L);
		retryTemplate.setBackOffPolicy(fixedBackOffPolicy);
		
		SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
		//设置 基本的,最大次数等。
		retryPolicy.setMaxAttempts(3);
		retryTemplate.setRetryPolicy(retryPolicy);
		
		// 注册监听器
		// retryTemplate.registerListener(new MyListenerSupport());
		
		return retryTemplate;
	}
}

三.四.二 接口重试调用

	/**
	 * '
	 * <p>
	 * 最后不会调用 retryUtilException() 方法。
	 */
	@Override
	public void selfRetry() throws Exception {
		try {
			retryTemplate.execute(new RetryCallback<Object, Throwable>() {
				@Override
				public Object doWithRetry(RetryContext context) throws Throwable {
					// 调用 重试方法
					try {
						noRetry();
						return null;
					} catch (Exception e) {
						// 有异常,往上抛出。
						throw e;
					}
				}
			});
		} catch (Throwable e) {
			throw new Exception("重试失败");
		}
	}

对应的 Controller 重试方法

	@GetMapping("/selfRetry")
	public String selfRetry() {
		try {
			userBusiness.selfRetry();
			return "运行成功";
		} catch (Exception e) {
			return "运行失败";
		}
	}

image-20230608204840727

三.五 重试监听器

三.五.一 自定义监听器 继承 RetryListenerSupport 类

/**
 * 自定义重试监听器
 *
 * @author yuejianli
 * @date 2022-06-28
 */
@Slf4j
public class MyListenerSupport extends RetryListenerSupport {
	
	/**
	 * 最后关闭的时候, 执行一次
	 */
	
	@Override
	public <T, E extends Throwable> void close(RetryContext context,
											   RetryCallback<T, E> callback, Throwable throwable) {
		log.info("onClose,关闭重试");
		super.close(context, callback, throwable);
	}
	
	/**
	 * 每一次执行失败时调用 ,可能会执行多次。
	 */
	@Override
	public <T, E extends Throwable> void onError(RetryContext context,
												 RetryCallback<T, E> callback, Throwable throwable) {
		log.info("onError,重试的结果,最终是失败的");
		super.onError(context, callback, throwable);
	}
	
	/**
	 * 最开始执行的时候, 执行一次
	 */
	@Override
	public <T, E extends Throwable> boolean open(RetryContext context,
												 RetryCallback<T, E> callback) {
		log.info("onOpen,开始重试");
		return super.open(context, callback);
	}
}

三.五.二 RetryTemplate 注册监听器

@Configuration
public class RetryConfig {
	
	@Bean
	public RetryTemplate retryTemplate() {
		RetryTemplate retryTemplate = new RetryTemplate();
		
		FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
		//设置重试回退
		fixedBackOffPolicy.setBackOffPeriod(2000L);
		retryTemplate.setBackOffPolicy(fixedBackOffPolicy);
		
		SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
		//设置 基本的,最大次数等。
		retryPolicy.setMaxAttempts(3);
		retryTemplate.setRetryPolicy(retryPolicy);
		
		// 注册监听器
		retryTemplate.registerListener(new MyListenerSupport());
		
		return retryTemplate;
	}
}

image-20230608205138267

三.六 重试策略

  • SimpleRetryPolicy 默认最多重试 3 次
  • TimeoutRetryPolicy 默认在 1 秒内失败都会重试
  • ExpressionRetryPolicy 符合表达式就会重试
  • CircuitBreakerRetryPolicy 增加了熔断的机制,如果不在熔断状态,则允许重试
  • CompositeRetryPolicy 可以组合多个重试策略
  • NeverRetryPolicy 从不重试(也是一种重试策略哈)
  • AlwaysRetryPolicy 总是重试

三.六.一 退避策略

退避策略退避是指怎么去做下一次的重试,在这里其实就是等待多长时间。

通过 @Backoff 注解实现,那么我们首先看一下@Backoff 的参数

三.六.一.一 @Backoff 参数

  • value

默认为 1000, 与 delay 作用相同,表示延迟的毫秒数。当 delay 非 0 时,此参数忽略。

  • delay

默认为 0。在指数情况下用作初始值,在统一情况下用作*的最小值。当此元素的值为 0 时,将采用元素 value 的值,否则将采用此元素的值,并且将忽略 value。

  • maxDelay

默认为 0。重试之间的最大等待时间(以毫秒为单位)。如果小于 delay,那么将应用默认值为 30000L

  • multipler

默认为 0。如果为正,则用作乘法器以生成下一个退避延迟。返回一个乘法器,用于计算下一个退避延迟

  • delayExpression

评估标准退避期的表达式。在指数情况下用作初始值*,在均匀情况下用作最小值。覆盖 delay。

  • maxDelayExpression

该表达式计算重试之间的最大等待时间(以毫秒为单位)。 如果小于 delay,那么将应用 30000L 为默认值。覆盖 maxDelay。

  • multiplierExpression

评估为用作乘数的值,以生成退避的下一个延迟。覆盖 multiplier。 返回一个乘数表达式,用于计算下一个退避延迟

  • random

默认为 false,在指数情况下 multiplier> 0 将此值设置为 true 可以使后退延迟随机化,从而使最大延迟乘以前一延迟,并且两个值之间的分布是均匀的。

@Retryable(value = MyException.class, maxAttempts = 4,
        backoff = @Backoff(delay = 2000, multiplier = 2, maxDelay = 5000))
public void testRetry08() throws MyException {
    System.out.println("测试-backoff属性");
    throw new MyException("出现了异常");
}

三.六.一.二 @Backoff 的参数会影响我们使用哪种退避策略**

  • FixedBackOffPolicy

默认退避策略,每 1 秒重试 1 次

  • ExponentialBackOffPolicy

指数退避策略,当设置 multiplier 时使用,每次重试时间间隔为 当前延迟时间 * multiplier。

例如:默认初始 0.1 秒,系数是 2,那么下次延迟 0.2 秒,再下次就是延迟 0.4 秒,如此类推,最大 30 秒。

  • ExponentialRandomBackOffPolicy

指数随机退避策略。在指数退避策略的基础上增加了随机性。

  • UniformRandomBackOffPolicy

均匀随机策略,设置 maxDely 但没有设置 multiplier 时使用,重试间隔会在 maxDelay 和 delay 间随机


本章节的代码放置在 github 上:

https://github.com/yuejianli/Function/tree/develop/Retry


谢谢您的观看,如果喜欢,请关注我,再次感谢 !!!

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

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

相关文章

身份证信息查看 案例

7-14位&#xff1a;出生年、月、日 17位&#xff1a;性别&#xff08;奇数男性、偶数女性&#xff09; 人物信息为&#xff1a;出生年月日&#xff1a;XXXX年X月X日 性别为&#xff1a;男/女 /** Copyright (c) 2017, 2023, zxy.cn All rights reserved.**/ package cn.str…

做了大半年软测,上班接触不到技术性的东西,是在浪费时间吗?

最近接到粉丝私信&#xff0c;苦恼目前的工作状态&#xff1a; 来这个公司大半年&#xff0c;现在主要做的是类似于淘宝的购物商城&#xff0c;以前也做应用系统什么的&#xff0c;可是感觉公司的软件测试岗位都是不着边的&#xff0c;因为做的都是功能测试&#xff0c;来了这么…

让你的文字更出色:编辑和校对的有效策略

要让你的文字更出色&#xff0c;掌握编辑和校对的有效策略至关重要。 以下是一些建议&#xff0c;帮助你提高编辑和校对水平&#xff0c;让你的作品更具吸引力和说服力。 1.分阶段进行编辑和校对 编辑和校对最好分阶段进行。先进行大局观的编辑&#xff0c;关注文章结构、逻辑…

Wildfly配置Datasources

配置Datasources前&#xff0c;需要先配置对应的JDBC驱动&#xff0c;配置方法&#xff0c;可以参考&#xff1a; Wildfly配置mysql8.0的JDBC驱动 之后&#xff0c;配置对应的Datasources。配置方法有两种&#xff0c;一种是通过管理后台配置&#xff0c;一种是通过手工修改配…

GLaDOS加速网络套餐edu教育网邮箱免费使用

产品介绍 教育优惠分享的好处&#xff0c;就是能一对一接触到网友的真实需求和最新的教育优惠产品&#xff0c;今天的这款也是网友投稿分享。 GLaDOS用于教育&#xff1a;建立开放思想和开放社会 GLaDOS Education可帮助学生&#xff0c;教师和学校找到他们掌握网络所需的工具…

【Python爬虫+数据分析】采集电商平台数据信息,并做可视化演示

文章目录 前言一、准备工作二、分析目标网站1.商品信息 三、编写爬虫程序五、总结 前言 随着电商平台的兴起&#xff0c;越来越多的人开始在网上购物。而对于电商平台来说&#xff0c;商品信息、价格、评论等数据是非常重要的。因此&#xff0c;抓取电商平台的商品信息、价格、…

虚拟机中使用Nginx + Keepalived 实现高可用 Web 负载均衡笔记

环境介绍 物理操作系统&#xff1a;Windows10 虚拟机软件&#xff1a;VMWare Workstation 16 Pro 虚拟操作系统统&#xff1a;CentOS7 Nginx&#xff1a;1.24.0 Keepalived&#xff1a;2.2.8 资源规划 在VMWare Worksattion中安装了2台CentOS7的虚拟机&#xff0c;桥接方式下…

ROS:常用可视化工具的使用

目录 一、日志输出工具——rqt_console二、绘制数据曲线——rqt_plot三、图像渲染工具——rqt_image_view四、图形界面总接口——rqt五、Rviz六、Gazebo 一、日志输出工具——rqt_console 启动海龟键盘控制节点&#xff0c;打开日志输出工具 roscorerosrun turtlesim turtles…

项目资源利用率是什么?如何提高?

任何项目经理的主要职责之一是跟踪项目资源&#xff0c;以便在需要时随时可用。为此&#xff0c;他们必须衡量资源利用率。通过计算资源利用率&#xff0c;项目经理和企业主可以更好地了解如何安排劳动力或设备等资源&#xff0c;以尽量降低成本&#xff0c;提高生产力&#xf…

Android关于图片资源管理的思考

作者&#xff1a;流浪汉kylin 一. 前言 当我们的项目比较大时&#xff0c;迭代的时间比较长的时候&#xff0c;我们往往都会对代码进行重构&#xff0c;会对代码进行一次系统的整合和规范的讨论&#xff0c;为了之后的开发能够避免写重复的代码&#xff0c;方便代码的维护和扩…

面向对象——权限修饰符、匿名内部类

package关键字 为什么要有包&#xff1f; 将字节码&#xff08;.class&#xff09;进行分类存放 包其实就是文件夹 包的定义及注意事项 定义包的格式 package 包名 多级包用.分割&#xff0c;如package com.heima里面的.就是分隔符 定义包的注意事项 package语句必须是程序的第…

扩容系统盘【centos-root】

问题描述&#xff1a; 磁盘空间有42G&#xff0c;但是系统盘只有6G。 问题抛出&#xff1a;&#xff08;P2原本只有7G&#xff0c;其中有30G错误分配到nvmeOn1p2了&#xff09;p2的30G空间怎么合理分配给系统盘? &#xff08;执行&#xff1a; sudo growpart /dev/nvme0n1 …

[学习笔记] [机器学习] 7. 集成学习(Bagging、随机森林、Boosting、GBDT)

视频链接数据集下载地址&#xff1a;无需下载 1. 集成学习算法简介 学习目标&#xff1a; 了解什么是集成学习知道机器学习中的两个核心任务了解集成学习中的 Boosting 和 Bagging 1.1 什么是集成学习 集成学习通过建立几个模型来解决单一预测问题。它的工作原理是生成多个分…

【P53】JMeter 断言结果(Assertion Results)

文章目录 一、断言结果&#xff08;Assertion Results&#xff09;参数说明二、准备工作三、测试计划设计 一、断言结果&#xff08;Assertion Results&#xff09;参数说明 可以查看断言的成功和失败数 使用场景&#xff1a;一般在调试测试计划期间用来查看断言的成功和失败…

水库大坝的安全监测内容包括哪些?

在水库大坝的实时监测中&#xff0c;主要任务是通过无线传感网络监测各个监测点的水位、水压、渗流、流量、扬压力等数据&#xff0c;并在计算机上用数据模式或图形模式进行实时反映&#xff0c;以掌握整个水库大坝的各项变化情况。大坝安全监测系统能实现全天候远程自动监测&a…

本地项目托管到 Gitee

本地项目托管到 Gitee 1、创建远程仓库2、Git Bash Here第一步&#xff1a;初始化本地仓库 git init第二步&#xff1a;建立链接git remote add origin xxx第三步&#xff1a;将远程仓库中的文件推送至本地仓库中git pull --rebase origin master第四步&#xff1a;将本地项目放…

Paddle与AFFormer环境配置

本次重新记录一下paddle的安装过程&#xff0c;主要是因为在进行服务器环境初始化时没有进行正确的环境安装。 基础环境 云硬盘部署 conda安装 Anaconda安装 首先是下载相关包命令&#xff1a; sudo wget https://repo.anaconda.com/archive/Anaconda3-2020.02-Linux-x86_64.…

7.面向对象编程(基础部分)|Java学习笔记

文章目录 类与对象类与对象的关系类和对象的区别和联系对象在内存中的存在形式类和对象的内存分配机制 成员方法方法的调用机制原理 成员方法传参机制基本数据类型的传参机制引用数据类型的传参机制成员方法返回类型是引用类型应用实例 方法递归调用递归重要规则汉诺塔和八皇后…

有哪些内外网都能传输文件的工具-镭速

随着互联网的快速普及&#xff0c;不同地区的人们之间进行了更为频繁的交流与合作。对于企业和组织而言&#xff0c;文件的共享和传输也变得越来越重要&#xff0c;特别是在不同的地理位置之间。此时&#xff0c;一个既可在内网使用&#xff0c;又能在外网实现高速传输的工具就…

企业直播MR虚拟直播实例(混合现实直播)

MR虚拟直播带来的内容、体验和互动的升级&#xff0c;对多个行业、场景具有重大意义&#xff0c;尤其是在汽车、科技、带货、活动等对视觉呈现要求更高的行业和场景中&#xff0c;将会重塑用户的观看体验&#xff0c;​高效赋能企业业务增长​。随着用户对直播体验的需求、企业…