Spring cloud Spring云网关,Eureka获得504(网关超时)

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

假设我有一个Eureka服务器,一个Spring云网关和一个ServiceA运行两个实例

当我部署服务的更新版本时,在很短的一段时间内,eureka将为ServiceA保留四个实例,即不再存在的实例和刚刚启动的实例

在Eureka逐出网关上不再有效的两个实例之前,Ribbon仍将在不再存在的实例之间保持负载平衡,从而生成
ConnectTimeoutException
,从而产生
504(网关超时)
。我已使用以下重试配置在网关中配置了这些路由

val retry = RetryGatewayFilterFactory.RetryConfig()
                 .setExceptions(ConnectException::class.java)
这允许ribbon在异常为
ConnectException:Connection Rejected
时立即重试,但在异常为
ConnectTimeoutException
时不会重试

我可以调整ribbon和eureka客户端的刷新间隔,但我宁愿不去碰它们

所以,我有两个问题

  • 如何在筛选器中捕获超时
  • 为了实现零停机时间,是否有更好的方法来处理此问题

谢谢

试试功能区。retryableStatusCodes=404502504


更新:

首先在我看来,
ConnectException
应该与code
502
关联,
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);
    }
}