【spring】spring中的retry重试机制; resilience4j熔断限流教程;springboot整合retry+resilience4j教程

在调用三方接口时,我们一般要考虑接口调用失败的处理,可以通过spring提供的retry来实现;如果重试几次都失败了,可能就要考虑降级补偿了;

有时我们也可能要考虑熔断,在微服务中可能会使用sentinel来做熔断;在单体服务中,可以使用轻量化的resilience4j来做限流或熔断

文章目录

  • maven依赖
  • retry重试机制
  • circuitbreaker 熔断机制
  • ratelimiter限流机制

maven依赖

        <!-- web项目jar包 包含starter、spring、webmvc 等--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- aop --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><!-- spring提供的重试机制  需要@EnableRetry 注解开启 --><dependency><groupId>org.springframework.retry</groupId><artifactId>spring-retry</artifactId></dependency><!-- actuator 有健康检查、监控管理等生产环境需要使用到的功能 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><!-- resilience4j 如果是Spring Boot 2.x项目,使用resilience4j-spring-boot2替代 --><dependency><groupId>io.github.resilience4j</groupId><artifactId>resilience4j-spring-boot3</artifactId><version>2.2.0</version></dependency>

retry重试机制

  1. 引入了retry相关依赖后,需要开启@EnableRetry
    例如:
@SpringBootApplication
@MapperScan
@EnableRetry
public class Application {public static void main(String[] args) {SpringApplication.run(Application .class, args);}}
  1. 在要重试的方法加上@Retryable注解

例如:

@RestController
@RequestMapping("/test/retry")
public class RetryController {@Retryable(value = Exception.class, maxAttempts = 3,backoff = @Backoff(delay = 1000,multiplier = 1.5))@GetMapping("/test")public String test() {System.out.println("do-something:"+ LocalDateTime.now());long l = System.currentTimeMillis();System.out.println(count++);int a = 0;System.out.println( l % 2 == 0);if (l % 2 == 0) {a = 1 / 0;}System.out.println("res=" + a+"  "+LocalDateTime.now());return "200";}}

参数解释:

value:抛出指定异常才会重试
noRetryFor:指定不处理的异常
maxAttempts:最大重试次数,默认3次
backoff:重试等待策略,默认使用@Backoff,
@Backoff的value(相当于delay)表示隔多少毫秒后重试,默认为1000L;
multiplier(指定延迟倍数)默认为0,表示固定暂停1秒后进行重试。

tips: multiplier 的实际意义 当我们调用某个接口失败时,如果紧接着马上又调用,大概率接口仍然是失败的,multiplier是一个递延时间,可以起到调用间隔越来越大的作用。

  1. 如果重试到最大次数仍然失败,希望有降级处理 代码则变成:
@RestController
@RequestMapping("/test/retry")
public class RetryController {@Retryable(value = Exception.class, maxAttempts = 3,backoff = @Backoff(delay = 1000,multiplier = 1.5))@GetMapping("/test")public String test() {System.out.println("do-something:"+ LocalDateTime.now());long l = System.currentTimeMillis();System.out.println(count++);int a = 0;System.out.println( l % 2 == 0);if (l % 2 == 0) {a = 1 / 0;}System.out.println("res=" + a+"  "+LocalDateTime.now());return "200";}/*** @Recover 的返回类型,必须跟 @Retryable修饰的方法返回值一致。*/@Recoverpublic String recoverTest(ArithmeticException e) {System.out.println("test模拟记录错误日志"+e.getMessage());return "test降级处理";}}
  1. 如果一个类中,有多个方法呢?@Retryable和@Recover是怎么对应的?(即@Recover是怎么判断 来自哪个方法):
@Recover方法必须与@Retryable方法在同一个Spring管理的Bean中;确保AOP代理生效。
当存在多个可能的@Recover方法时,Spring按以下优先级选择:
异常类型最具体的方法(如子类异常优先于父类)。
返回类型最匹配的方法(避免类型转换错误)。
参数列表更匹配的方法(如包含原方法参数)

例如:

@RestController
@RequestMapping("/test/retry")
public class RetryController {int count = 0;String noete = """@Recover方法必须与@Retryable方法在同一个Spring管理的Bean中,确保AOP代理生效。当存在多个可能的@Recover方法时,Spring按以下优先级选择:异常类型最具体的方法(如子类异常优先于父类)。返回类型最匹配的方法(避免类型转换错误)。参数列表更匹配的方法(如包含原方法参数)value:抛出指定异常才会重试noRetryFor:指定不处理的异常maxAttempts:最大重试次数,默认3次backoff:重试等待策略,默认使用@Backoff,@Backoff的value(相当于delay)表示隔多少毫秒后重试,默认为1000L;multiplier(指定延迟倍数)默认为0,表示固定暂停1秒后进行重试。""";@Retryable(value = Exception.class, maxAttempts = 3,backoff = @Backoff(delay = 1000,multiplier = 1.5))@CircuitBreaker(name = "backendA",fallbackMethod = "fallback")@GetMapping("/test")public String test() {System.out.println("do-something:"+ LocalDateTime.now());long l = System.currentTimeMillis();System.out.println(count++);int a = 0;System.out.println( l % 2 == 0);if (l % 2 == 0) {a = 1 / 0;}System.out.println("res=" + a+"  "+LocalDateTime.now());return "200";}@Retryable(value = Exception.class, maxAttempts = 3,backoff = @Backoff(delay = 1000,multiplier = 1.5))@GetMapping("/test1")public String test1() {System.out.println("do-something:"+ LocalDateTime.now());// NumberFormatExceptionInteger a = Integer.parseInt(null);System.out.println("res=" + a +"  "+LocalDateTime.now());return "200";}@Retryable(value = Exception.class, maxAttempts = 3,backoff = @Backoff(delay = 1000,multiplier = 1.5))@GetMapping("/test2")public String test2(String name) {System.out.println("do-something:"+ LocalDateTime.now());int a = 1 / 0;System.out.println("res=" + a+"  "+LocalDateTime.now());return "200";}/*** @Recover 的返回类型,必须跟 @Retryable修饰的方法返回值一致。*/@Recoverpublic String recoverTest(ArithmeticException e) {System.out.println("test模拟记录错误日志"+e.getMessage());return "test降级处理";}@Recoverpublic String recoverTest1(NumberFormatException e) {System.out.println("test1模拟记录错误日志"+e.getMessage());return "test1降级处理";}@Recoverpublic String recoverTest2(ArithmeticException e,String name) {System.out.println("test2模拟记录错误日志"+e.getMessage());return "test2降级处理";}}

circuitbreaker 熔断机制

  1. yml中配置
# resilience4j (轻量级熔断)
resilience4j:circuitbreaker:instances:# 自定义的熔断名称backendA:sliding-window-type: count_based # 默认是count, 还可以配置 TIME_BASED sliding-window-size则表示最近几秒sliding-window-size: 4 # 只看最近四次调用(为了方便测试)minimum-number-of-calls: 1 #只需一次调用就开始评估failure-rate-threshold: 50 # 失败率超过50 就开启熔断 (开启熔断后,后面请求就直接进入熔断了)wait-duration-in-open-state: 5s # 开启后5s进入半开状态  (半开启是个灵活的状态,后续服务恢复就不用进入熔断了)permitted-number-of-calls-in-half-open-state: 2 # 半开状态允许有两次测试调用 如果低于 failure-rate-threshold 失败率 ,则不会进入熔断automatic-transition-from-open-to-half-open-enabled: true # 半开启状态
  1. 代码中使用,fallback如果是只接收限流异常 则定义成CallNotPermittedException,如果定义成Exception , 则只要发生异常就会进入方法(不会基于yml的配置),如何定义取决于业务需要。
@RestController
@RequestMapping("/test/retry")
public class RetryController {String noete = """@Recover方法必须与@Retryable方法在同一个Spring管理的Bean中,确保AOP代理生效。当存在多个可能的@Recover方法时,Spring按以下优先级选择:异常类型最具体的方法(如子类异常优先于父类)。返回类型最匹配的方法(避免类型转换错误)。参数列表更匹配的方法(如包含原方法参数)value:抛出指定异常才会重试noRetryFor:指定不处理的异常maxAttempts:最大重试次数,默认3次backoff:重试等待策略,默认使用@Backoff,@Backoff的value(相当于delay)表示隔多少毫秒后重试,默认为1000L;multiplier(指定延迟倍数)默认为0,表示固定暂停1秒后进行重试。""";@Retryable(value = Exception.class, maxAttempts = 3,backoff = @Backoff(delay = 1000,multiplier = 1.5))// name指定的值和我们yml配置保持一致@CircuitBreaker(name = "backendA",fallbackMethod = "fallback")@GetMapping("/test")public String test() {System.out.println("do-something:"+ LocalDateTime.now());long l = System.currentTimeMillis();int a = 0;System.out.println( l % 2 == 0);if (l % 2 == 0) {a = 1 / 0;}System.out.println("res=" + a+"  "+LocalDateTime.now());return "200";}/*** 熔断器指定的方法* 返回值类型也要一致*/public String fallback(CallNotPermittedException e) {System.out.println("进入熔断");return "进入了熔断";}
}

相关源码:
在这里插入图片描述
在这里插入图片描述

  1. @Retryable+@CircuitBreaker 一起使用注意事项:
    Recover 执行顺序 > fallbackMethod ;
    如果 @Recover 吞了异常(即没有手动抛出异常) 是不会再进入fallbackMethod 的,所以很可能造成@Retryable+@CircuitBreaker 一起使用 导致CircuitBreaker失效。如果一定要一起使用,我们可以在Recover把异常抛出去

完整版测试代码:


@RestController
@RequestMapping("/test/retry")
public class RetryController {String noete = """@Recover方法必须与@Retryable方法在同一个Spring管理的Bean中,确保AOP代理生效。当存在多个可能的@Recover方法时,Spring按以下优先级选择:异常类型最具体的方法(如子类异常优先于父类)。返回类型最匹配的方法(避免类型转换错误)。参数列表更匹配的方法(如包含原方法参数)value:抛出指定异常才会重试noRetryFor:指定不处理的异常maxAttempts:最大重试次数,默认3次backoff:重试等待策略,默认使用@Backoff,@Backoff的value(相当于delay)表示隔多少毫秒后重试,默认为1000L;multiplier(指定延迟倍数)默认为0,表示固定暂停1秒后进行重试。""";@Retryable(value = Exception.class, maxAttempts = 3,backoff = @Backoff(delay = 1000,multiplier = 1.5))@CircuitBreaker(name = "backendA",fallbackMethod = "fallback")@GetMapping("/test")public String test() {System.out.println("do-something:"+ LocalDateTime.now());long l = System.currentTimeMillis();int a = 0;System.out.println( l % 2 == 0);if (l % 2 == 0) {a = 1 / 0;}System.out.println("res=" + a+"  "+LocalDateTime.now());return "200";}@Retryable(value = Exception.class, maxAttempts = 3,backoff = @Backoff(delay = 1000,multiplier = 1.5))@GetMapping("/test1")public String test1() {System.out.println("do-something:"+ LocalDateTime.now());// NumberFormatExceptionInteger a = Integer.parseInt(null);System.out.println("res=" + a +"  "+LocalDateTime.now());return "200";}@Retryable(value = Exception.class, maxAttempts = 3,backoff = @Backoff(delay = 1000,multiplier = 1.5))@GetMapping("/test2")public String test2(String name) {System.out.println("do-something:"+ LocalDateTime.now());int a = 1 / 0;System.out.println("res=" + a+"  "+LocalDateTime.now());return "200";}/*** @Recover 的返回类型,必须跟 @Retryable修饰的方法返回值一致。*  注意 Recover 执行顺序 >  fallbackMethod ; 如果 @Recover 吞了异常(即没有手动抛出) 是不会再进入fallbackMethod 的*  如果一定要 Recover +  fallbackMethod 同时使用,可以在Recover 把异常抛出去*/@Recoverpublic String recoverTest(ArithmeticException e) {System.out.println("test模拟记录错误日志"+e.getMessage());throw e;
//        return "test降级处理";}@Recoverpublic String recoverTest1(NumberFormatException e) {System.out.println("test1模拟记录错误日志"+e.getMessage());return "test1降级处理";}@Recoverpublic String recoverTest2(ArithmeticException e,String name) {System.out.println("test2模拟记录错误日志"+e.getMessage());return "test2降级处理";}/*** 熔断器指定的方法* 返回值类型也要一致*/public String fallback(CallNotPermittedException e) {System.out.println("进入熔断");return "进入了熔断";}

ratelimiter限流机制

  1. yml配置
    限流和熔断的配置是类似的:
# resilience4j (轻量级熔断)
resilience4j:# 限流配置ratelimiter:instances:# 自定义的限流名称commonRateLimiter:limitForPeriod: 10  # 每个刷新周期内允许的最大请求数limitRefreshPeriod: 1s  # 限流刷新周期timeoutDuration: 100ms  # 获取许可的等待超时时间registerHealthIndicator: true  # 是否注册健康指标eventConsumerBufferSize: 100  # 事件缓冲区大小# 熔断配置      circuitbreaker:instances:# 自定义的熔断名称backendA:sliding-window-type: count_based # 默认是count, 还可以配置 TIME_BASED sliding-window-size则表示最近几秒sliding-window-size: 4 # 只看最近四次调用(为了方便测试)minimum-number-of-calls: 1 #只需一次调用就开始评估failure-rate-threshold: 50 # 失败率超过50 就开启熔断 (开启熔断后,后面请求就直接进入熔断了)wait-duration-in-open-state: 5s # 开启后5s进入半开状态  (半开启是个灵活的状态,后续服务恢复就不用进入熔断了)permitted-number-of-calls-in-half-open-state: 2 # 半开状态允许有两次测试调用 如果低于 failure-rate-threshold 失败率 ,则不会进入熔断automatic-transition-from-open-to-half-open-enabled: true # 半开启状态
  1. 代码中使用,注意限流的补偿方法入参需要定义成RequestNotPermitted
  @GetMapping("/limit")@RateLimiter(name = "commonRateLimiter",fallbackMethod = "limit")public String limitTest() {System.out.println("do-something:"+ LocalDateTime.now());int a = 1 / 0;System.out.println("res=" + a+"  "+LocalDateTime.now());return "200";}/*** 注意入参根据业务情况 定义RequestNotPermitted还是Exception * 如果定义成Exception则被@RateLimiter修饰的方法 一旦发生异常就会进入该方法,而不是优先读取yml的配置* @param e RequestNotPermitted*/public String limit(RequestNotPermitted e) {System.out.println("被限流了");return "被限流了";}
}
  1. 简单看一下源码,看看为什么要定义成相关异常
    io.github.resilience4j.ratelimiter.RateLimiter 类:
    下面这行代码表示被限流了会抛出RequestNotPermitted 异常;
    在这里插入图片描述
    下面这行则是fallback的一个公用处理,会去找到接收这个异常的方法
    在这里插入图片描述

tips: 为什么能找到源码位置? 首先把logging调成debug级别, 找到关键输出的日志对应的类 先打上断点 再把上下源码一行一行跟踪

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

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

相关文章

(21)量子计算对密码学的影响

文章目录 2️⃣1️⃣ 量子计算对密码学的影响 &#x1f30c;&#x1f50d; TL;DR&#x1f680; 量子计算&#xff1a;密码学的终结者&#xff1f;⚡ 量子计算的破坏力 &#x1f510; Java密码学体系面临的量子威胁&#x1f525; 受影响最严重的Java安全组件 &#x1f6e1;️ 后…

经营分析会,财务该怎么做?

目录 一、业绩洞察&#xff1a;从「现象描述」到「因果分析」 1.分层拆解 2.关联验证 3.根因追溯 二、预算管理&#xff1a;从「刚性控制」到「动态平衡」 1.分类管控 2.滚动校准 3.价值评估 三、客户与市场&#xff1a;从「交易记录」到「价值评估」 1.价值分层 2.…

进阶智能体实战九、图文需求分析助手(ChatGpt多模态版)(帮你生成 模块划分+页面+表设计、状态机、工作流、ER模型)

🧠 基于 ChatGPT 多模态大模型的需求文档分析助手 本文将介绍如何利用 OpenAI 的 GPT-4o 多模态能力,构建一个智能的需求文档分析助手,自动提取功能模块、菜单设计、字段设计、状态机、流程图和 ER 模型等关键内容。 一、🔧 环境准备 在开始之前,请确保您已经完成了基础…

图书管理系统的设计与实现

湖南软件职业技术大学 本科毕业设计(论文) 设计(论文)题目 图书管理系统的设计与实现 学生姓名 学生学号 所在学院 专业班级 毕业设计(论文)真实性承诺及声明 学生对毕业设计(论文)真实性承诺 本人郑重声明:所提交的毕业设计(论文)作品是本人在指导教师的指导下,独…

直线模组在手术机器人中有哪些技术挑战?

手术机器人在现代医疗领域发挥着越来越重要的作用&#xff0c;直线模组作为其关键部件&#xff0c;对手术机器人的性能有着至关重要的影响。然而&#xff0c;在手术机器人中使用直线模组面临着诸多技术挑战&#xff0c;具体如下&#xff1a; 1、‌高精度要求‌&#xff1a;手术…

技术-工程-管用养修保-智能硬件-智能软件五维黄金序位模型

融智学工程技术体系&#xff1a;五维协同架构 基于邹晓辉教授的框架&#xff0c;工程技术体系重构为&#xff1a;技术-工程-管用养修保-智能硬件-智能软件五维黄金序位模型&#xff1a; math \mathbb{E}_{\text{技}} \underbrace{\prod_{\text{Dis}} \text{TechnoCore}}_{\…

InnoDB引擎逻辑存储结构及架构

简化理解版 想象 InnoDB 是一个高效运转的仓库&#xff1a; 核心内存区 (大脑 & 高速缓存 - 干活超快的地方) 缓冲池 Buffer Pool (最最核心&#xff01;)&#xff1a; 作用&#xff1a; 相当于仓库的“高频货架”。把最常用的数据&#xff08;表数据、索引&#xff09;从…

贫血模型与充血模型:架构设计的分水岭

在企业级应用的架构设计中&#xff0c;贫血模型和充血模型一直是架构师们争论的热点话题。两者背后分别代表着“事务脚本模式”和“领域模型模式”两种截然不同的设计思想。而理解这两者的差异&#xff0c;有助于开发者根据实际业务场景做出更合理的架构决策。 贫血模型&#…

Linux的调试器--gbd/cgbd

1.引入 #include <stdio.h> int Sum(int s, int e) {int result 0;for(int i s; i < e; i){result i;}return result; } int main() {int start 1;int end 100;printf("I will begin\n");int n Sum(start, end);printf("running done, result i…

PPIO × AstrBot:多平台接入聊天机器人,开启高效协同 | 教程

在消息平台接入专属聊天机器人&#xff0c;能快速生成精准答案&#xff0c;与项目管理、CRM等系统集成后&#xff0c;机器人还能根据任务进展自动建群、推送进度提醒&#xff0c;并精准相关人员&#xff0c;实现信息的高效传递。 AstrBot 是一个多平台聊天机器人及开发框架&…

HAProxy 可观测性最佳实践

HAProxy 简介 HAProxy&#xff08;High Availability Proxy&#xff09;是一款广泛使用的高性能负载均衡器&#xff0c;支持 TCP 和 HTTP 协议&#xff0c;提供高可用性、负载均衡和代理服务。它特别适用于负载较大的 Web 站点&#xff0c;能够支持数以万计的并发连接&#xf…

增强LangChain交互体验:消息历史(记忆)功能详解

背景 在构建聊天机器人时,将对话状态传入和传出链至关重要。 LangGraph 实现了内置的持久层,允许链状态自动持久化在内存或外部后端(如 SQLite、Postgres 或 Redis)中。在本文我们将演示如何通过将任意 LangChain runnables 包装在最小的 LangGraph 应用程序中来添加持久性…

EasyRTC音视频实时通话助力微信小程序:打造低延迟、高可靠的VoIP端到端呼叫解决方案

一、方案概述​ 在数字化通信浪潮下&#xff0c;端到端实时音视频能力成为刚需。依托庞大用户生态的微信小程序&#xff0c;是实现此类功能的优质载体。基于WebRTC的EasyRTC音视频SDK&#xff0c;为小程序VoIP呼叫提供轻量化解决方案&#xff0c;通过技术优化实现低延迟通信&a…

WebVm:无需安装,一款可以在浏览器运行的 Linux 来了

WebVM 是一款可以在浏览器中运行的Linux虚拟机。不是那种HTMLJavaScript模拟的UI&#xff0c;完全通过HTML5/WebAssembly技术实现客户端运行。通过集成CheerpX虚拟化引擎&#xff0c;可直接在浏览器中运行未经修改的Debian系统。 Stars 数13054Forks 数2398 主要特点 完整 Lin…

CesiumInstancedMesh 实例

CesiumInstancedMesh 实例 import * as Cesium from cesium;// Three.js 风格的 InstancedMesh 类, https://threejs.org/docs/#api/en/objects/InstancedMesh export class CesiumInstancedMesh {/*** Creates an instance of InstancedMesh.** param {Cesium.Geometry} geom…

创建型模式之Abstract Factory(抽象工厂)

创建型模式之Abstract Factory&#xff08;抽象工厂&#xff09; 摘要&#xff1a; 本文介绍了抽象工厂模式&#xff08;Abstract Factory&#xff09;&#xff0c;它是一种创建型设计模式&#xff0c;提供了一种创建一系列相关对象的接口而无需指定具体类。文章通过手机工厂示…

多卡训练核心技术详解

多卡训练核心技术详解 多卡训练 主要围绕分布式环境初始化、模型并行化、数据分片和梯度同步展开。下面结合您的代码,详细解释这些核心部分: 并行执行命令 torchrun --nproc_per_node=5 TokenLossMulCard.py 1. 分布式环境初始化 def init_distributed():init_process_…

OpenCV---minAreaRect

一、基本概念与用途 minAreaRect是OpenCV中用于计算点集的最小面积旋转矩形的函数。在计算机视觉领域&#xff0c;它常被用于&#xff1a; 目标检测中获取倾斜对象的边界框&#xff08;如倾斜的车牌、文本行、工业零件&#xff09;形状分析与识别&#xff08;如确定物体的主方…

高端装备制造企业如何选择适配的项目管理系统提升项目执行效率?附选型案例

高端装备制造项目通常涉及多专业协同、长周期交付和高风险管控&#xff0c;因此系统需具备全生命周期管理能力。例如&#xff0c;北京奥博思公司出品的 PowerProject 项目管理系统就是一款非常适合制造企业使用的项目管理软件系统。 国内某大型半导体装备制造企业与奥博思软件达…

如何科学测量系统的最高QPS?

要准确测量系统的最高QPS&#xff08;Queries Per Second&#xff09;&#xff0c;既不能简单依赖固定请求数&#xff08;如2万次&#xff09;&#xff0c;也不能盲目压到服务器崩溃。以下是专业的方法论和步骤&#xff1a; 1. 核心原则 目标&#xff1a;找到系统在稳定运行&a…