Spring Cloud Gateway重试机制
前言
重试,我相信大家并不陌生。在我们调用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重试机制相关推荐
- Spring Cloud Zuul重试机制探秘
简介 本文章对应spring cloud的版本为(Dalston.SR4),具体内容如下: 开启Zuul功能 通过源码了解Zuul的一次转发 怎么开启zuul的重试机制 Edgware.RC1版本的优 ...
- Spring Cloud Gateway之路由断言工厂篇
1. 背景 最近,需要提升系统安全性,市面上有很多款网关服务的技术方案,最终选择了Spring Cloud Gateway. 2. Spring Cloud Gateway工作机制 官网配图: 客户端 ...
- 实战 Spring Cloud Gateway 之限流篇
来源:https://www.aneasystone.com/archives/2020/08/spring-cloud-gateway-current-limiting.html 话说在 Sprin ...
- 网关服务Spring Cloud Gateway(三)
上篇文章介绍了 Gataway 和注册中心的使用,以及 Gataway 中 Filter 的基本使用,这篇文章我们将继续介绍 Filter 的一些常用功能. 修改请求路径的过滤器 StripPrefi ...
- Spring Cloud Gateway (六) 自定义 Global Filter
Spring Cloud Gateway (六) 自定义 Global Filter 简介 在前面五篇的分析中,对 Spring Cloud Gateway 的 filter 组件有了一个大概 ...
- ws配置 zuul_微服务网关 Spring Cloud Gateway
1. 为什么是Spring Cloud Gateway 一句话,Spring Cloud已经放弃Netflix Zuul了.现在Spring Cloud中引用的还是Zuul 1.x版本,而这个版本是 ...
- Spring Cloud Gateway 2.1.0 中文官网文档
目录 1. How to Include Spring Cloud Gateway 2. Glossary 3. How It Works 4. Route Predicate Factories 5 ...
- Spring Cloud Gateway 3.1.3最新版中文手册官网2022
Spring Cloud Gateway 3.1.3 该项目提供了一个库,用于在 Spring WebFlux 之上构建 API 网关.Spring Cloud Gateway 旨在提供一种简单而有效 ...
- Spring Cloud Gateway自带RequestRateLimiter限流应用及扩展 | Spring Cloud 16
一.限流算法 限流是对某一时间窗口内的请求数进行限制,保持系统的可用性和稳定性,防止因流量暴增而导致的系统运行缓慢或宕机. 在开发高并发系统时有三把利器用来保护系统: 缓存:缓存的目的是提升系统访问速 ...
最新文章
- android edittext 默认不获取焦点
- 一文总结词向量的计算、评估与优化
- 【廖雪峰python入门笔记】tuple_“元素可变”
- cmake使用教程(十一)-使用cpack打包源码并编写自动化脚本上传到仓库
- mysql odbc 配置详解
- python使用@property @x.setter @x.deleter
- html判断是否有某个元素,jquery怎么判断元素是否存在?
- 深数据 - Deep Data
- 访问者模式 php,php设计模式 Visitor 访问者模式
- 用commons-fileupload-1.2 实现文件上传
- Hadoop实战-中高级部分 之 Hadoop 集群安装
- jzoj3384-理工男【欧拉定理,gcd,数论】
- python concat_python-pd.concat()不合并在同一索引上
- Python中的from import和import的区别?没有比这回答的更好了
- 解读 2018之Go语言篇(上):为什么Go语言越来越热?
- AT88SC104 加密认证过程
- php mysql apache vbb
- 产品需求文档五分钟轻松搞定!这可能史上最全PRD文档模板
- 本地项目第一次上传到SmartSvn
- U盘文件夹被隐藏能够解决方法
热门文章
- HDFS Namenode启动过程
- Vlan中的 PVID vid tag untag 常识理论
- Windows 2008 ×××与 CA
- 轻量级Web渗透测试工具jSQL
- 解决Xamarin Android SDK Manager闪退问题
- 配置JDKAndroid 2D游戏引擎AndEngine
- jq 控制td只显示一行_9月22日现货黄金、白银TD、黄金TD、纸黄金、纸白银价格走势分析...
- mysql报错2_MySQL基于报错注入2
- centos得mysql安装教程_Centos下Mysql安装图文教程_MySQL
- python中break可以用在for和if中吗_Python的for和break循环结构中使用else语句的技巧...