前言

重试,我相信大家并不陌生。在我们调用Http接口的时候,总会因为某种原因调用失败,这个时候我们可以通过重试的方式,来重新请求接口。

生活中这样的事例很多,比如打电话,对方正在通话中啊,信号不好啊等等原因,你总会打不通,当你第一次没打通之后,你会打第二次,第三次...第四次就通了。

重试也要注意应用场景,读数据的接口比较适合重试的场景,写数据的接口就需要注意接口的幂等性了。还有就是重试次数如果太多的话会导致请求量加倍,给后端造成更大的压力,设置合理的重试机制才是最关键的。

今天我们来简单的了解下Spring Cloud Gateway中的重试机制和使用。

使用讲解

RetryGatewayFilter是Spring Cloud Gateway对请求重试提供的一个GatewayFilter Factory。

配置方式:

spring:cloud:gateway:routes:- id: fsh-houseuri: lb://fsh-housepredicates:- Path=/house/**filters:- name: Retryargs:retries: 3series:- SERVER_ERRORstatuses:- OKmethods:- GET- POSTexceptions:- java.io.IOException
复制代码

配置讲解

配置类源码org.springframework.cloud.gateway.filter.factory.RetryGatewayFilterFactory.RetryConfig:

public static class RetryConfig {private int retries = 3;private List<Series> series = toList(Series.SERVER_ERROR);private List<HttpStatus> statuses = new ArrayList<>();private List<HttpMethod> methods = toList(HttpMethod.GET);private List<Class<? extends Throwable>> exceptions = toList(IOException.class);// .....
}
复制代码
  • retries:重试次数,默认值是3次
  • series:状态码配置(分段),符合的某段状态码才会进行重试逻辑,默认值是SERVER_ERROR,值是5,也就是5XX(5开头的状态码),共有5个值:
public enum Series {INFORMATIONAL(1),SUCCESSFUL(2),REDIRECTION(3),CLIENT_ERROR(4),SERVER_ERROR(5);
}
复制代码
  • statuses:状态码配置,和series不同的是这边是具体状态码的配置,取值请参考:org.springframework.http.HttpStatus
  • methods:指定哪些方法的请求需要进行重试逻辑,默认值是GET方法,取值如下:
public enum HttpMethod {GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE;
}
复制代码
  • exceptions:指定哪些异常需要进行重试逻辑,默认值是java.io.IOException

代码测试

就写个接口,在接口中记录请求次数,然后抛出一个异常模拟500,通过网关访问这个接口,如果你配置了重试次数是3,那么接口中会输出4次结果才是对的,证明重试生效了。

AtomicInteger ac = new AtomicInteger();@GetMapping("/data")
public HouseInfo getData(@RequestParam("name") String name) {if (StringUtils.isBlank(name)) {throw new RuntimeException("error");}System.err.println(ac.addAndGet(1));return new HouseInfo(1L, "上海", "虹口", "XX小区");
}
复制代码

更多Spring Cloud代码尽在:github.com/yinjihuan/s…

源码欣赏

    @Overridepublic GatewayFilter apply(RetryConfig retryConfig) {// 验证重试配置格式是否正确retryConfig.validate();Repeat<ServerWebExchange> statusCodeRepeat = null;if (!retryConfig.getStatuses().isEmpty() || !retryConfig.getSeries().isEmpty()) {Predicate<RepeatContext<ServerWebExchange>> repeatPredicate = context -> {ServerWebExchange exchange = context.applicationContext();// 判断重试次数是否已经达到了配置的最大值if (exceedsMaxIterations(exchange, retryConfig)) {return false;}// 获取响应的状态码HttpStatus statusCode = exchange.getResponse().getStatusCode();// 获取请求方法类型HttpMethod httpMethod = exchange.getRequest().getMethod();// 判断响应状态码是否在配置中存在boolean retryableStatusCode = retryConfig.getStatuses().contains(statusCode);if (!retryableStatusCode && statusCode != null) { // null status code might mean a network exception?// try the seriesretryableStatusCode = retryConfig.getSeries().stream().anyMatch(series -> statusCode.series().equals(series));}// 判断方法是否包含在配置中boolean retryableMethod = retryConfig.getMethods().contains(httpMethod);// 决定是否要进行重试return retryableMethod && retryableStatusCode;};statusCodeRepeat = Repeat.onlyIf(repeatPredicate).doOnRepeat(context -> reset(context.applicationContext()));}//TODO: support timeout, backoff, jitter, etc... in BuilderRetry<ServerWebExchange> exceptionRetry = null;if (!retryConfig.getExceptions().isEmpty()) {Predicate<RetryContext<ServerWebExchange>> retryContextPredicate = context -> {if (exceedsMaxIterations(context.applicationContext(), retryConfig)) {return false;}// 异常判断for (Class<? extends Throwable> clazz : retryConfig.getExceptions()) {             if (clazz.isInstance(context.exception())) {return true;}}return false;};// 使用reactor extra的retry组件exceptionRetry = Retry.onlyIf(retryContextPredicate).doOnRetry(context -> reset(context.applicationContext())).retryMax(retryConfig.getRetries());}return apply(statusCodeRepeat, exceptionRetry);}public boolean exceedsMaxIterations(ServerWebExchange exchange, RetryConfig retryConfig) {Integer iteration = exchange.getAttribute(RETRY_ITERATION_KEY);//TODO: deal with null iterationreturn iteration != null && iteration >= retryConfig.getRetries();}public void reset(ServerWebExchange exchange) {//TODO: what else to do to reset SWE?exchange.getAttributes().remove(ServerWebExchangeUtils.GATEWAY_ALREADY_ROUTED_ATTR);}public GatewayFilter apply(Repeat<ServerWebExchange> repeat, Retry<ServerWebExchange> retry) {return (exchange, chain) -> {if (log.isTraceEnabled()) {log.trace("Entering retry-filter");}// chain.filter returns a Mono<Void>Publisher<Void> publisher = chain.filter(exchange)//.log("retry-filter", Level.INFO).doOnSuccessOrError((aVoid, throwable) -> {// 获取已经重试的次数,默认值为-1int iteration = exchange.getAttributeOrDefault(RETRY_ITERATION_KEY, -1);// 增加重试次数exchange.getAttributes().put(RETRY_ITERATION_KEY, iteration + 1);});if (retry != null) {// retryWhen returns a Mono<Void>// retry needs to go before repeatpublisher = ((Mono<Void>)publisher).retryWhen(retry.withApplicationContext(exchange));}if (repeat != null) {// repeatWhen returns a Flux<Void>// so this needs to be last and the variable a Publisher<Void>publisher = ((Mono<Void>)publisher).repeatWhen(repeat.withApplicationContext(exchange));}return Mono.fromDirect(publisher);};}复制代码

Spring Cloud Gateway重试机制相关推荐

  1. Spring Cloud Zuul重试机制探秘

    简介 本文章对应spring cloud的版本为(Dalston.SR4),具体内容如下: 开启Zuul功能 通过源码了解Zuul的一次转发 怎么开启zuul的重试机制 Edgware.RC1版本的优 ...

  2. Spring Cloud Gateway之路由断言工厂篇

    1. 背景 最近,需要提升系统安全性,市面上有很多款网关服务的技术方案,最终选择了Spring Cloud Gateway. 2. Spring Cloud Gateway工作机制 官网配图: 客户端 ...

  3. 实战 Spring Cloud Gateway 之限流篇

    来源:https://www.aneasystone.com/archives/2020/08/spring-cloud-gateway-current-limiting.html 话说在 Sprin ...

  4. 网关服务Spring Cloud Gateway(三)

    上篇文章介绍了 Gataway 和注册中心的使用,以及 Gataway 中 Filter 的基本使用,这篇文章我们将继续介绍 Filter 的一些常用功能. 修改请求路径的过滤器 StripPrefi ...

  5. Spring Cloud Gateway (六) 自定义 Global Filter

    Spring Cloud Gateway (六) 自定义 Global Filter 简介     在前面五篇的分析中,对 Spring Cloud Gateway 的 filter 组件有了一个大概 ...

  6. ws配置 zuul_微服务网关 Spring Cloud Gateway

    1.  为什么是Spring Cloud Gateway 一句话,Spring Cloud已经放弃Netflix Zuul了.现在Spring Cloud中引用的还是Zuul 1.x版本,而这个版本是 ...

  7. Spring Cloud Gateway 2.1.0 中文官网文档

    目录 1. How to Include Spring Cloud Gateway 2. Glossary 3. How It Works 4. Route Predicate Factories 5 ...

  8. Spring Cloud Gateway 3.1.3最新版中文手册官网2022

    Spring Cloud Gateway 3.1.3 该项目提供了一个库,用于在 Spring WebFlux 之上构建 API 网关.Spring Cloud Gateway 旨在提供一种简单而有效 ...

  9. Spring Cloud Gateway自带RequestRateLimiter限流应用及扩展 | Spring Cloud 16

    一.限流算法 限流是对某一时间窗口内的请求数进行限制,保持系统的可用性和稳定性,防止因流量暴增而导致的系统运行缓慢或宕机. 在开发高并发系统时有三把利器用来保护系统: 缓存:缓存的目的是提升系统访问速 ...

最新文章

  1. android edittext 默认不获取焦点
  2. 一文总结词向量的计算、评估与优化
  3. 【廖雪峰python入门笔记】tuple_“元素可变”
  4. cmake使用教程(十一)-使用cpack打包源码并编写自动化脚本上传到仓库
  5. mysql odbc 配置详解
  6. python使用@property @x.setter @x.deleter
  7. html判断是否有某个元素,jquery怎么判断元素是否存在?
  8. 深数据 - Deep Data
  9. 访问者模式 php,php设计模式 Visitor 访问者模式
  10. 用commons-fileupload-1.2 实现文件上传
  11. Hadoop实战-中高级部分 之 Hadoop 集群安装
  12. jzoj3384-理工男【欧拉定理,gcd,数论】
  13. python concat_python-pd.concat()不合并在同一索引上
  14. Python中的from import和import的区别?没有比这回答的更好了
  15. 解读 2018之Go语言篇(上):为什么Go语言越来越热?
  16. AT88SC104 加密认证过程
  17. php mysql apache vbb
  18. 产品需求文档五分钟轻松搞定!这可能史上最全PRD文档模板
  19. 本地项目第一次上传到SmartSvn
  20. U盘文件夹被隐藏能够解决方法

热门文章

  1. HDFS Namenode启动过程
  2. Vlan中的 PVID vid tag untag 常识理论
  3. Windows 2008 ×××与 CA
  4. 轻量级Web渗透测试工具jSQL
  5. 解决Xamarin Android SDK Manager闪退问题
  6. 配置JDKAndroid 2D游戏引擎AndEngine
  7. jq 控制td只显示一行_9月22日现货黄金、白银TD、黄金TD、纸黄金、纸白银价格走势分析...
  8. mysql报错2_MySQL基于报错注入2
  9. centos得mysql安装教程_Centos下Mysql安装图文教程_MySQL
  10. python中break可以用在for和if中吗_Python的for和break循环结构中使用else语句的技巧...