Spring cloud Spring云网关,Eureka获得504(网关超时)
假设我有一个Eureka服务器,一个Spring云网关和一个ServiceA运行两个实例 当我部署服务的更新版本时,在很短的一段时间内,eureka将为ServiceA保留四个实例,即不再存在的实例和刚刚启动的实例 在Eureka逐出网关上不再有效的两个实例之前,Ribbon仍将在不再存在的实例之间保持负载平衡,从而生成Spring cloud Spring云网关,Eureka获得504(网关超时),spring-cloud,netflix-eureka,spring-cloud-netflix,netflix-ribbon,Spring Cloud,Netflix Eureka,Spring Cloud Netflix,Netflix Ribbon,假设我有一个Eureka服务器,一个Spring云网关和一个ServiceA运行两个实例 当我部署服务的更新版本时,在很短的一段时间内,eureka将为ServiceA保留四个实例,即不再存在的实例和刚刚启动的实例 在Eureka逐出网关上不再有效的两个实例之前,Ribbon仍将在不再存在的实例之间保持负载平衡,从而生成ConnectTimeoutException,从而产生504(网关超时)。我已使用以下重试配置在网关中配置了这些路由 val retry = RetryGatewayFilte
ConnectTimeoutException
,从而产生504(网关超时)
。我已使用以下重试配置在网关中配置了这些路由
val retry = RetryGatewayFilterFactory.RetryConfig()
.setExceptions(ConnectException::class.java)
这允许ribbon在异常为ConnectException:Connection Rejected
时立即重试,但在异常为ConnectTimeoutException
时不会重试
我可以调整ribbon和eureka客户端的刷新间隔,但我宁愿不去碰它们
所以,我有两个问题
- 如何在筛选器中捕获超时
- 为了实现零停机时间,是否有更好的方法来处理此问题
谢谢试试功能区。retryableStatusCodes=404502504
更新: 首先在我看来,
ConnectException
应该与code502
关联,504
是SocketTimeoutException
。如果错了,请纠正我
很抱歉,请不要深入了解云网关,但其LB可以选择使用Ribbon
让我们通过Ribbon.OKHttp.enabled
确认您正在使用Ribbon和OKHttp
OkHttpRibbonConfiguration
将初始化执行请求的OkHttpLoadBalancingClient
bean。在其execute()
中,它在每个请求执行期间首先创建一个RetryCallback
匿名实现对象。RetryCallback
负责执行请求和重试执行
让我们转到RetryCallback
的逻辑。收到响应后,它检查响应状态代码是否可重试。如果类加载器中存在RetryTemplate
类,则loadBalancedRetryPolicyFactory
的实现是RibbonLoadBalancedRetryPolicyFactory
。它用于创建RibbonLoadBalancedRetryPolicy
对象(RetryPolicy
如下)
executeWithRetry()
使用RetryPolicy
创建一个RetryTemplate
。(前提条件是,通过将请求设置为可重试,在spring云网关中启用重试)
在retryableStatusCode()
中,它检查retryableStatusCodes是否包含响应状态代码
public class RibbonLoadBalancedRetryPolicy implements LoadBalancedRetryPolicy {
public static final IClientConfigKey<String> RETRYABLE_STATUS_CODES = new CommonClientConfigKey<String>("retryableStatusCodes") {};
....
List<Integer> retryableStatusCodes = new ArrayList<>();
public RibbonLoadBalancedRetryPolicy(String serviceId, RibbonLoadBalancerContext context, ServiceInstanceChooser loadBalanceChooser,
IClientConfig clientConfig) {
this.serviceId = serviceId;
this.lbContext = context;
this.loadBalanceChooser = loadBalanceChooser;
String retryableStatusCodesProp = clientConfig.getPropertyAsString(RETRYABLE_STATUS_CODES, "");
String[] retryableStatusCodesArray = retryableStatusCodesProp.split(",");
for(String code : retryableStatusCodesArray) {
if(!StringUtils.isEmpty(code)) {
try {
retryableStatusCodes.add(Integer.valueOf(code.trim()));
} catch (NumberFormatException e) {
//TODO log
}
}
}
}
...
@Override
public boolean retryableStatusCode(int statusCode) {
return retryableStatusCodes.contains(statusCode);
}
}
公共类RibbonLoadBalancedRetryPolicy实现LoadBalancedRetryPolicy{
public static final IClientConfigKey RETRYABLE_STATUS_code=new CommonClientConfigKey(“retryablestatuscode”){};
....
List retryableStatusCodes=new ArrayList();
公共RibbonLoadBalancedRetryPolicy(字符串serviceId、RibbonLoadBalancerContext、ServiceInstanceChooser loadBalanceChooser、,
IClientConfig客户端配置){
this.serviceId=serviceId;
this.lbContext=上下文;
this.loadBalanceChooser=loadBalanceChooser;
String retryableStatusCodesProp=clientConfig.getpropertyastring(retryablestatuscodes,“”);
字符串[]retryableStatusCodesArray=retryableStatusCodesProp.split(“,”);
for(字符串代码:retryableStatusCodesArray){
如果(!StringUtils.isEmpty(代码)){
试一试{
retryableStatusCodes.add(Integer.valueOf(code.trim());
}捕获(数字格式){
//待办事项日志
}
}
}
}
...
@凌驾
公共布尔值retryableStatusCode(int statusCode){
返回retryableStatusCodes.contains(状态码);
}
}
如果包含,则抛出
OkHttpStatusCodeException
,它扩展了RetryableStatusCodeException
。并且RibbonRecoveryCallback
捕获此异常,检查异常是否为RetryableStatusCodeException
的实现。如果是,则RetryTemplate
继续重试。或者,抛出不可重试的表达式以中断重试。您使用的是Hystrix吗?@Spencergib还没有,我应该为此负责吗?尝试:解释您的答案。@Anthony,最后一个答案来自手机。只需添加更多。
public class RibbonLoadBalancedRetryPolicy implements LoadBalancedRetryPolicy {
public static final IClientConfigKey<String> RETRYABLE_STATUS_CODES = new CommonClientConfigKey<String>("retryableStatusCodes") {};
....
List<Integer> retryableStatusCodes = new ArrayList<>();
public RibbonLoadBalancedRetryPolicy(String serviceId, RibbonLoadBalancerContext context, ServiceInstanceChooser loadBalanceChooser,
IClientConfig clientConfig) {
this.serviceId = serviceId;
this.lbContext = context;
this.loadBalanceChooser = loadBalanceChooser;
String retryableStatusCodesProp = clientConfig.getPropertyAsString(RETRYABLE_STATUS_CODES, "");
String[] retryableStatusCodesArray = retryableStatusCodesProp.split(",");
for(String code : retryableStatusCodesArray) {
if(!StringUtils.isEmpty(code)) {
try {
retryableStatusCodes.add(Integer.valueOf(code.trim()));
} catch (NumberFormatException e) {
//TODO log
}
}
}
}
...
@Override
public boolean retryableStatusCode(int statusCode) {
return retryableStatusCodes.contains(statusCode);
}
}