Spring Cloud Gateway重试机制的实现

2025-05-29 0 80

前言

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

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

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

今天我们来简单的了解下spring cloud gateway中的重试机制和使用。

使用讲解

retrygatewayfilter是spring cloud gateway对请求重试提供的一个gatewayfilter factory。

配置方式:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21
spring:

cloud:

gateway:

routes:

- id: fsh-house

uri: lb://fsh-house

predicates:

- path=/house/**

filters:

- name: retry

args:

retries: 3

series:

- server_error

statuses:

- ok

methods:

- get

- post

exceptions:

- java.io.ioexception

配置讲解

配置类源码org.springframework.cloud.gateway.filter.factory.retrygatewayfilterfactory.retryconfig:

?

1

2

3

4

5

6

7

8

9

10

11

12

13
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个值:

?

1

2

3

4

5

6

7
public enum series {

informational(1),

successful(2),

redirection(3),

client_error(4),

server_error(5);

}

statuses:状态码配置,和series不同的是这边是具体状态码的配置,取值请参考:org.springframework.http.httpstatus

methods:指定哪些方法的请求需要进行重试逻辑,默认值是get方法,取值如下:

?

1

2

3
public enum httpmethod {

get, head, post, put, patch, delete, options, trace;

}

exceptions:指定哪些异常需要进行重试逻辑,默认值是java.io.ioexception

代码测试

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

?

1

2

3

4

5

6

7

8

9

10
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代码尽在:https://github.com/yinjihuan/spring-cloud

源码欣赏

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103
@override

public 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 series

retryablestatuscode = 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 builder

retry<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 iteration

return 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) -> {

// 获取已经重试的次数,默认值为-1

int 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 repeat

publisher = ((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);

};

}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持快网idc。

原文链接:https://segmentfault.com/a/1190000018469096

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 Spring Cloud Gateway重试机制的实现 https://www.kuaiidc.com/109968.html

相关文章

发表评论
暂无评论