微服务设计模式 - 重试模式(Retry Pattern)

微服务设计模式 - 重试模式(Retry Pattern)

retry-in-microservice

定义

重试模式(Retry Pattern)是一种微服务中的设计模式,用于在临时性失败(如网络故障或暂时不可用的服务)发生时,自动重新尝试请求,而不是立即返回错误。通过重试,可以增加操作成功的概率,从而提高系统的可靠性。

结构

重试模式通常包括以下几个组件:

  • 调用者:发起请求的实体。
  • 操作:需要重试的操作,比如API调用或数据库操作。
  • 重试策略:定义重试次数、间隔时间和重试条件的策略。

工作原理

retry-pattern-flow

重试模式的工作原理如下:

  1. 调用者发起请求
  2. 执行操作,如果成功则返回结果,如果失败则进入重试策略。
  3. 重试策略检查是否满足重试条件,如最大重试次数未达到、错误类型允许重试等。
  4. 如果满足条件,则按照重试策略重新请求操作,否则返回最终失败结果。

优点

  1. 提高可靠性:在遇到暂时性故障时,通过重试机制增加操作成功的机会。

  2. 增强用户体验:避免频繁的错误提示,提高用户的满意度。

  3. 灵活性:通过配置不同的重试策略,适应不同的业务需求。

使用场景

重试模式(Retry Pattern)在很多场景中非常有用,尤其是在处理临时性故障(transient faults)的时候。下面列举了几种典型的使用场景:

  1. 网络通信问题
    • 网络抖动:在面临暂时性网络抖动或不稳定时,重试可以帮助确保请求成功。
    • 网络超时:一些网络请求可能超时,如果这些超时是临时的,那么可以通过重试来解决问题。
  2. 外部API调用
    • 第三方服务不稳定:在调用外部API或第三方服务时,如果这些服务偶尔不稳定,通过重试可以增加成功的概率。
    • API限流:外部API可能会对请求数量进行限流,导致部分请求被拒绝,重试可以在稍后的时间段重新发送请求。
  3. 数据库操作
    • 数据库连接中断:数据库连接可能偶尔中断,通过重试机制可以重新建立连接。
    • 锁定结果:在高并发情况下,某些数据库操作可能会因行锁或表锁被暂时阻塞,通过重试可以等待锁释放。
  4. 消息队列
    • 消息消费失败:在处理消息队列中的消息时,如果某些消息因临时性问题处理失败,可以通过重试机制重新处理这些消息。
  5. 分布式系统
    • 服务依赖:在分布式系统中,多个微服务之间相互依赖,如果某个服务临时不可用,通过重试可以确保请求最终成功。
  6. 其他临时性错误
    • 资源限制:某些临时性资源限制(如内存不足或CPU过载)可能导致操作失败,通过重试可以等待资源恢复。
    • 维护或升级:某些服务可能在维护或升级过程中短暂不可用,重试机制可以在服务恢复后继续尝试请求。

影响因素

在实现重试模式时,我们需要考虑多个重要因素,包括幂等性(Idempotency)、事务一致性(Transaction Consistency)、性能影响和异常类型,以确保系统的可靠性和有效性。

以下具体介绍每一个影响因素,并以SrpingBoot相关代码,以及resilience4j(用以实现重试模式)相关配置进行辅助说明。

幂等性(Idempotency)

定义:幂等性是指在相同条件下多次执行操作,结果应保持一致。换句话说,幂等操作在被执行一次或多次后对系统的状态产生相同的影响。

重要性:重试模式通常会多次执行相同操作,因此确保操作的幂等性是至关重要的。若操作不具有幂等性,可能会导致数据不一致或重复处理。

实现示例

  • 对于HTTP请求,可以使用HTTP动词来区分幂等操作。例如,PUT和DELETE通常为幂等操作,而POST可能不是。
  • 在数据库写操作时,添加唯一约束,或在应用层实现幂等逻辑。

示例代码 - 幂等性操作

@Service
public class IdempotentService {@Autowiredprivate OrderRepository orderRepository;@Retry(name = "idempotentService", fallbackMethod = "fallback")public String createOrder(Order order) {// 检查订单是否已经存在(即幂等性检查)Optional<Order> existingOrder = orderRepository.findByOrderId(order.getOrderId());if (existingOrder.isPresent()) {return "Order already exists";}// 创建新订单orderRepository.save(order);return "Order created successfully";}private String fallback(Order order, Exception e) {return "Fallback response";}
}

事务一致性(Transaction Consistency)

定义:事务一致性确保在一组操作中,所有操作要么全部成功,要么全部失败,从而保证系统状态的一致性。

挑战:重试机制可能跨越多个事务,且每次重试都应当考虑事务的一致性问题。未能维护一致性可能导致数据混乱或部分提交的问题。

实现示例

  • 在Java中使用Spring的@Transactional注解来管理事务一致性。
  • 在分布式系统中,使用2PC(两阶段提交)或Saga模式等事务管理策略。

示例代码 - 事务一致性

@Service
public class TransactionalService {@Autowiredprivate OrderRepository orderRepository;@Transactional@Retry(name = "transactionalService", fallbackMethod = "fallback")public String createOrderTransactional(Order order) {// 创建新订单orderRepository.save(order);// 下单后其他相关操作...return "Order created successfully with transaction";}private String fallback(Order order, Exception e) {return "Fallback response in transaction";}
}

性能影响(Impact on Performance)

定义:重试机制可能引入额外的延迟和资源消耗,因此需要谨慎管理以减少性能影响。

优化策略

  • 限次数:限制重试次数,避免无限重试。
  • 指数退避:每次重试时增加等待时间,减少系统负载。
  • 快速失败:在明显不可恢复的情况下,尽早返回错误而不是反复重试。

实现示例

  • 配置如maxAttemptswaitDuration等参数来控制重试策略。

示例配置 - 性能相关

resilience4j.retry:instances:myService:max-attempts: 3wait-duration: 500msmax-wait-duration: 2sexponential-backoff:multiplier: 2

异常类型(Exception Type)

定义:不同类型的异常可能需要不同的重试策略。有些异常是暂时性的,可以通过重试解决;另一些则是不可恢复的,不应重试。

实现示例

  • 使用防御性编程和异常分类来确定哪些异常应该触发重试。
  • 自定义重试规则来处理不同类型的异常。

示例代码 - 异常类型识别

@Service
public class ExceptionHandlingService {@Retry(name = "exceptionHandlingService", fallbackMethod = "fallback", retryExceptions = {TemporaryException.class }, ignoreExceptions = { PermanentException.class })public String handleService() {// 假设某操作可能抛出TemporaryException或PermanentExceptionriskyOperation();return "Operation completed";}private void riskyOperation() throws TemporaryException, PermanentException {// 实现一些逻辑,可能抛出不同类型的异常}private String fallback(Exception e) {return "Fallback response for exceptions";}
}

重试策略

在实现重试模式时,选择合适的重试策略(Retry Strategy)是至关重要的。不同的重试策略会影响系统的可靠性、性能和响应时间。以下是常见的重试策略:

固定间隔重试(Fixed Interval Retry)

定义:固定间隔重试策略在每次重试之间使用相同的时间间隔。例如,重试每次间隔500毫秒。

优点:实现简单,适用于简单的重试场景。

缺点:在高负载或问题持续存在的情况下,可能会导致系统过载。

示例配置

resilience4j.retry:instances:myService:max-attempts: 3wait-duration: 500ms

指数退避重试(Exponential Backoff Retry)

定义:每次重试时,等待时间逐步增加。例如,第一次重试后等待500毫秒,第二次重试后等待1秒,第三次重试后等待2秒,以此类推。

优点:逐步增加的等待时间可以有效减少系统负载,适用于网络抖动或外部服务不稳定的情形。

缺点:实现稍微复杂,可能导致较长的重试时间。

示例配置

resilience4j.retry:instances:myService:max-attempts: 3wait-duration: 500msexponential-backoff:multiplier: 2

抛出异常后退避重试(Backoff with Jitter Retry)

定义:在指数退避的基础上,加入随机时间间隔(称为“抖动”),以避免重试请求出现峰值。

优点:通过在重试间隔中加入随机性,进一步减少了系统因重试请求同时发出的风险,适用于高并发场景。

缺点:实现复杂度更高。

示例代码(Java示例):

RetryConfig config = RetryConfig.custom().maxAttempts(3).waitDuration(Duration.ofMillis(500)).retryOnException(throwable -> throwable instanceof TemporaryException).intervalFunction(IntervalFunction.ofExponentialBackoff(500, 2).withRandomizedWait()).build();

增量退避重试(Incremental Backoff Retry)

定义:每次重试等待时间按照固定的增量增加。例如,第一次重试后等待500毫秒,第二次重试后等待1秒,第三次重试后等待1.5秒。

优点:控制每次重试的等待时间增加量,简单易理解。

缺点:在一定情况下,性能可能不如指数退避策略。

示例代码

resilience4j.retry:instances:myService:max-attempts: 3wait-duration: 500msinterval-function:increment-interval:interval: 500ms

固定次数重试(Retry with Max Attempts)

定义:限制重试的次数,当超过重试次数时停止重试。

优点:防止过多重试导致资源消耗,保护系统稳定。

缺点:可能导致在某些情况下无效重试。

示例代码

resilience4j.retry:instances:myService:max-attempts: 5wait-duration: 500ms

自定义重试策略(Custom Retry Strategy)

定义:根据特定的业务需求和场景,设计定制化的重试策略。

优点:灵活、满足特定需求。

缺点:需要更多的开发和测试工作。

示例代码(Java自定义实现):

RetryConfig config = RetryConfig.custom().maxAttempts(5).intervalFunction(IntervalFunction.of(Duration.ofMillis(500), IntervalFunction.of(Random::nextGaussian))).retryOnException(throwable -> {// Define your custom retry condition here.return throwable instanceof TemporaryException;}).build();

综合以上,在选择重试策略时,建议如下:

  1. 分析场景:根据实际业务场景选择合适的重试策略。例如,网络波动适合使用指数退避重试。
  2. 测试不同策略:通过负载测试和性能测试,评估不同重试策略对系统的实际影响。
  3. 结合多种策略:可以组合多个重试策略,例如固定次数重试加上指数退避,满足更复杂的需求。
  4. 监控与调整:定期监控重试机制的效果,根据实际情况动态调整重试策略。

完整实例代码

这个示例展示了如何在Spring Boot应用中使用Resilience4j实现重试模式。配置文件中定义了重试策略,包括最大尝试次数、等待时间和指数退避参数。服务层通过重试注解@Retry实现重试逻辑,并在错误情况下调用回退方法。通过这一模式,系统可以有效应对各种临时性故障,提高整体的可靠性和稳定性。

项目结构

.
├── src/
│   ├── main/
│   │   ├── java/
│   │   │   └── com/
│   │   │       └── example/
│   │   │           └── retry/
│   │   │               ├── RetryApplication.java
│   │   │               ├── controller/
│   │   │               │   └── RetryController.java
│   │   │               ├── service/
│   │   │               │   └── RetryService.java
│   │   │               └── exception/
│   │   │                   ├── TemporaryException.java
│   │   │                   └── PermanentException.java
│   │   ├── resources/
│   │   │   ├── application.yaml
└── pom.xml

Maven 依赖

首先,在Maven的pom.xml文件中添加Resilience4j依赖项:

<dependencies><!-- Spring Boot dependencies --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Resilience4j dependencies --><dependency><groupId>io.github.resilience4j</groupId><artifactId>resilience4j-spring-boot2</artifactId><version>1.7.1</version></dependency><dependency><groupId>io.github.resilience4j</groupId><artifactId>resilience4j-retry</artifactId><version>1.7.1</version></dependency>
</dependencies>

Retry配置

在Spring Boot应用程序的配置文件application.yaml中配置Resilience4j的重试策略:

resilience4j.retry:instances:myService:max-attempts: 5wait-duration: 500msexponential-backoff:multiplier: 2retry-exceptions:- com.example.retry.exception.TemporaryExceptionignore-exceptions:- com.example.retry.exception.PermanentException

代码说明

RetryApplication.java

主应用程序文件:

package com.example.retry;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class RetryApplication {public static void main(String[] args) {SpringApplication.run(RetryApplication.class, args);}
}
RetryController.java

控制器类:

package com.example.retry.controller;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import com.example.retry.service.RetryService;@RestController
public class RetryController {@Autowiredprivate RetryService retryService;@GetMapping("/retry-test")public ResponseEntity<String> retryTest() {return ResponseEntity.ok(retryService.callExternalService());}
}
RetryService.java

服务层实现重试逻辑:

package com.example.retry.service;import org.springframework.stereotype.Service;
import io.github.resilience4j.retry.annotation.Retry;
import com.example.retry.exception.TemporaryException;
import com.example.retry.exception.PermanentException;@Service
public class RetryService {@Retry(name = "myService", fallbackMethod = "fallback")public String callExternalService() throws TemporaryException, PermanentException {// 模拟外部服务调用double random = Math.random();if (random < 0.5) {throw new TemporaryException("Temporary issue occurred");} else if (random < 0.8) {throw new PermanentException("Permanent issue occurred");}return "Success";}private String fallback(Exception e) {return "Fallback response: " + e.getMessage();}
}
TemporaryException.java

自定义临时异常类型:

package com.example.retry.exception;public class TemporaryException extends Exception {public TemporaryException(String message) {super(message);}
}
PermanentException.java

自定义永久异常类型:

package com.example.retry.exception;public class PermanentException extends Exception {public PermanentException(String message) {super(message);}
}

类序列图

retry-pattern-class

运行测试

运行Spring Boot应用程序后,访问 http://localhost:8080/retry-test 可以触发重试逻辑。根据随机数的不同,有时会成功,有时会触发临时异常进行重试,如果次数用尽则返回回退响应。

总结

Robert-C-Martin-Quote-Software-has-two-types-of-value-the-value-of

在云计算和微服务架构中,重试模式是一种重要的设计模式,通过处理暂时性故障来增强系统的可靠性。当实现重试模式时,必须考虑幂等性、事务一致性、性能影响和异常类型,以确保系统的整体稳定性和正确性。Resilience4j库提供了实现重试模式的便利方法,通过合理配置可以满足各种不同的业务需求。希望本文能帮助您更好地理解和选择合适的重试策略,为系统设计和实现提供参考。

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

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

相关文章

从源码到成品应用:互联网医院系统与在线问诊APP的开发全解析

今天将全面解析互联网医院系统和在线问诊APP的开发过程&#xff0c;从源码到成品应用&#xff0c;帮助您理解其中的关键技术和实施策略。 一、系统架构设计 互联网医院系统和在线问诊APP的开发首先需要一个合理的系统架构。通常&#xff0c;系统架构分为前端和后端两个部分。…

简记 Vue3(一)—— setup、ref、reactive、toRefs、toRef

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…

ZooKeeper 客户端API操作

文章目录 一、节点信息1、创建节点2、获取子节点并监听节点变化3、判断节点是否存在4、客户端向服务端写入数据写入请求直接发给 Leader 节点写入请求直接发给 follow 节点 二、服务器动态上下线监听1、监听过程2、代码 三、分布式锁1、什么是分布式锁?2、Curator 框架实现分布…

C++/list

目录 1.list的介绍 2.list的使用 2.1list的构造 2.2list iterator的使用 2.3list capacity 2.4list element access 2.5list modifers 2.6list的迭代器失效 3.list的模拟实现 4.list与vector的对比 欢迎 1.list的介绍 list的文档介绍 cplusplus.com/reference/list/li…

计算机图形学中向量相关知识chuizhi

一、向量加法 平行四边形法则 两个向量统一起点&#xff0c;构成平行四边形&#xff0c;对角线为向量加和的结果 三角形法则 两个向量尾首相连&#xff0c;从a起点连接到b终点&#xff0c;为向量加法的结果 多向量首尾相连的加法结果为第一个向量的起点到最后一个向量的终点…

私有化视频平台EasyCVR视频汇聚平台接入RTMP协议推流为何无法播放?

私有化视频平台EasyCVR视频汇聚平台兼容性强、支持灵活拓展&#xff0c;平台可提供视频远程监控、录像、存储与回放、视频转码、视频快照、告警、云台控制、语音对讲、平台级联等视频能力。 有用户反馈&#xff0c;项目现场使用RTMP协议接入EasyCVR平台&#xff0c;但是视频却不…

【教程】Git 标准工作流

目录 前言建仓&#xff0c;拉仓&#xff0c;关联仓库修改代码更新本地仓库&#xff0c;并解决冲突提交代码&#xff0c;合入代码其他常用 Git 工作流删除本地仓库和远程仓库中的文件日志打印commit 相关 前言 Git 是日常开发中常用的版本控制工具&#xff0c;配合代码托管仓库…

VMware workstation的3种网络类型

虚拟机想要和主机进行通信必须借助网桥或者交换机&#xff0c;VMware workstation提供了3种网络交换机&#xff1a;仅主机类型交换机、NAT类型交换机、桥接类型交换机。 介绍下这三种类型的交换机 仅主机类型 通过VMware workstation添加一个仅主机类型的虚拟交换机后&#…

【RAG】自动化RAG框架-“AutoML风”卷到了RAG?

AutoML&#xff08;自动机器学习&#xff09;是指通过自动化过程&#xff0c;简化机器学习模型的开发、训练和优化&#xff0c;使非专业用户也能有效地构建高性能模型。 今天分享的自动RAG框架&#xff0c;该框架能够自动识别给定数据集的合适RAG模块。自动RAG探索并近似数据集…

Qt/C++地图雷达扫描/动态扇形区域/标记线实时移动/轮船货轮动态轨迹/雷达模拟/跟随地图缩放

一、前言说明 地图雷达扫描的需求场景也不少&#xff0c;很多人的做法是直接搞个覆盖层widget&#xff0c;在widget上绘制雷达&#xff0c;优缺点很明显&#xff0c;优点是性能高&#xff0c;毕竟直接在widget上绘制性能明显比js中绘制要高&#xff0c;缺点是要么动态计算经纬…

CodeS:构建用于文本到 SQL 的开源语言模型

发布于&#xff1a;2024 年 10 月 29 日 #RAG #Text2 SQL #NL2 SQL 语言模型在将自然语言问题转换为 SQL 查询&#xff08;文本到 SQL &#xff09;的任务中显示出良好的性能。然而&#xff0c;大多数最先进的 &#xff08;SOTA&#xff09; 方法都依赖于强大但闭源的大型语言…

新一代Webshell管理器

工具介绍 游魂是一个开源的Webshell管理器&#xff0c;提供更为方便的界面和更为简单易用的功能&#xff0c;可配合或代替其他webshell管理器&#xff0c;帮助用户在各类渗透场景中控制目标机器。游魂不仅支持常见的一句话webshell以及常见Webshell管理器的功能&#xff0c;还…

SQL 常用语句

目录 我的测试环境 学习文档 进入数据库 基础通关测验 语句-- 查 展示数据库&#xff1b; 进入某个数据库&#xff1b; 展示表&#xff1a; 展示某个表 desc 查询整个表&#xff1a; 查询特定列&#xff1a; 范围查询 等于特定值 不等于 介于 特定字符查询 Li…

pycharm小游戏飞机射击

导入pygame模块 下载成功 图片略显粗糙 python 复制 import pygame import random # 初始化 pygame pygame.init() # 屏幕大小 SCREEN_WIDTH 800 SCREEN_HEIGHT 600 # 颜色 WHITE (255, 255, 255) BLACK (0, 0, 0) GREEN (0, 255, 0) RED (255, 0, 0) # 飞机速度 P…

ELK实现加载多个配置日志文件

服务器准备3台133为ELS存储服务器&#xff0c;135为Kibana前台显示收集服务器&#xff0c;136为logstash客户端 打开136logstash配置pipelines.yml文件path.config:配置模块 打开136的logstash.yml配置文件 在136服务器上查看logstash配置文件 需要将mysql_log.conf和nginx_log…

深入理解Redis的四种模式

Redis是一个内存数据存储系统&#xff0c;支持多种不同的部署模式。以下是Redis的四种主要部署模式。 1、单机模式 单机模式是最简单的部署模式&#xff0c;Redis将数据存储在单个节点上。这个节点包括一个Redis进程和一个持久化存储。单机模式非常适合小型应用程序或者开发和…

微服务设计模式 - 断路器模式 (Circuit Breaker Pattern)

微服务设计模式 - 断路器模式 (Circuit Breaker Pattern) 定义 断路器模式&#xff08;Circuit Breaker Pattern&#xff09;是云计算和微服务架构中的一种保护性设计模式&#xff0c;其目的是避免系统中的调用链出现故障时&#xff0c;导致系统瘫痪。通过断路器模式&#xff…

【react】基础知识点学习

1. 创建项目 npm install -g create-react-app npx create-react-app my-app cd my-app npm startindex.js为入口文件&#xff0c;App.js为根组件。 如何将react应用挂载在页面上&#xff1f; 将App组件渲染到id为root的DOM元素中 2. JSX JSX是|avaScript和XML(HTML)的缩写…

校园社团信息管理:Spring Boot技术的应用与挑战

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

LeetCode3226题. 使两个整数相等的位更改次数解法二(原创)

我之前文章LeetCode3226题. 使两个整数相等的位更改次数&#xff08;原创&#xff09;-CSDN博客对于LeetCode第3226题中给出了解法&#xff0c;后来思考了一下可以用位操作来完成更简洁优雅的实现&#xff1a; 首先计算n和k的异或值m.m中的所有位数中为1的值就是n中为1k中为0&…