【问题标题】:Ribbon Retry Config not working功能区重试配置不起作用
【发布时间】:2018-02-14 02:49:54
【问题描述】:

我有 Spring Cloud 打包的 Zuul API 网关,使用以下配置运行 -

# Eureka Client Config to register ZUUL with Eureka
eureka:
client:
    healthcheck:
      enabled: true
    lease:
      duration: 5
    service-url:
      defaultZone: http://localhost:8761/eureka/

# Ribbon Global Config
ribbon:
  OkToRetryOnAllOperations: false
  ReadTimeout: 30000
  ConnectTimeout: 1000
  MaxTotalHttpConnections: 1600
  MaxConnectionsPerHost: 800
  MaxAutoRetries: 11
  MaxAutoRetriesNextServer: 111

# Ribbon Named Client Config for Ingest API
ingestService:
  ribbon:
    eureka:
      enabled: false
    NIWSServerListClassName: com.netflix.loadbalancer.ConfigurationBasedServerList
    listOfServers: http://test-nlb-zuul-us-west-2c-6af11a3ede8a872a.elb.us-west-2.amazonaws.com
    OkToRetryOnAllOperations: true
    MaxAutoRetries: 1
    MaxAutoRetriesNextServer: 1
    MaxTotalHttpConnections: 500
    MaxConnectionsPerHost: 200
    retryableStatusCodes: 500, 501, 502, 503
    ReadTimeout: 10000
    ConnectTimeout: 1000

# Zuul Routes
zuul:
  debug:
    request: true
    parameter: true
  host: # timeout config for direct URL based requests from Zuul to external URLs
    connect-timeout-millis: 10000
    socket-timeout-millis: 20000
  ignored-services: '*'
  routes:
    ingest:
      path: /ingest/**
      retryable: true
      stripPrefix: false
      serviceId: ingestService

management.security.enabled : false

spring:
  application:
    name: zuul-gateway
  cloud:
    loadbalancer:
      retry:
        enabled: true

logging:
  level:
    org:
      springframework:
        retry: DEBUG
      apache:
        http: DEBUG
    com:
      netflix:
        ribbon: DEBUG
        eureka: DEBUG
        discovery: DEBUG

hystrix:
  command:
    default:
      execution:
        isolation:
          strategy: THREAD
          thread:
            timeoutInMilliseconds: 30000

当我点击 zuul /ingest 端点时,请求被重定向到 ingestService 的功能区 serviceId 配置下列出的服务器。但是,我看到功能区重试配置被完全忽略。

当服务器暂时出现 HTTP 500 错误时,全局功能区配置 - ribbon.MaxAutoRetries=11 和命名客户端配置 - ingestService.ribbon.MaxAutoRetries=1 都会被忽略。我看到重试发生正好 10 次,我不知道重试配置来自哪里,这似乎完全违反了可用的文档。我不知道从哪里开始调试,因为我是整个 netflix 工具生态系统的新手。想检查我是否犯了一些配置错误。请指教。

这是我的 pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.mycomp</groupId>
    <artifactId>zuul-gateway</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>zuul-gateway</name>
    <description>Spring Boot Zuul</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Edgware.SR1</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zuul</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.retry</groupId>
            <artifactId>spring-retry</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

以及spring应用启动

package com.mycomp.zuulgateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
@EnableZuulProxy
@EnableDiscoveryClient
@EnableCircuitBreaker
public class ZuulGatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(ZuulGatewayApplication.class, args);
    }
}

【问题讨论】:

    标签: netflix-zuul spring-cloud-netflix spring-retry


    【解决方案1】:

    当我开始这个项目时,我从

    开始
    • spring-cloud-dependencies 与版本 Edgware.SR1

    因此,根据 pom/bom 声明 - 我的功能区应用程序客户端似乎正在使用 spring-cloud-netflix-core-1.4.2.RELEASE.jar

    spring-cloud-netflix-core-1.4.2.RELEASE.jar 中,org.springframework.cloud.netflix.ribbon.apache.RetryableRibbonLoadBalancingHttpClient 类有一个错误/缺陷 -

    从方法——

    public RibbonApacheHttpResponse execute(final RibbonApacheHttpRequest request, final IClientConfig configOverride) throws Exception {
        Builder builder = RequestConfig.custom();
        IClientConfig config = configOverride != null ? configOverride : this.config;
        builder.setConnectTimeout((Integer)config.get(CommonClientConfigKey.ConnectTimeout, this.connectTimeout));
        builder.setSocketTimeout((Integer)config.get(CommonClientConfigKey.ReadTimeout, this.readTimeout));
        builder.setRedirectsEnabled((Boolean)config.get(CommonClientConfigKey.FollowRedirects, this.followRedirects));
        final RequestConfig requestConfig = builder.build();
        final LoadBalancedRetryPolicy retryPolicy = this.loadBalancedRetryPolicyFactory.create(this.getClientName(), this);
        RetryCallback retryCallback = new RetryCallback() {
            public RibbonApacheHttpResponse doWithRetry(RetryContext context) throws Exception {
                RibbonApacheHttpRequest newRequest = request;
                if (context instanceof LoadBalancedRetryContext) {
                    ServiceInstance service = ((LoadBalancedRetryContext)context).getServiceInstance();
                    if (service != null) {
                        newRequest = newRequest.withNewUri(new URI(service.getUri().getScheme(), newRequest.getURI().getUserInfo(), service.getHost(), service.getPort(), newRequest.getURI().getPath(), newRequest.getURI().getQuery(), newRequest.getURI().getFragment()));
                    }
                }
    
                // ***** after getting a newRequest in the if block above, the newRequest is not passed to the getSecureRequest() below ***** 
                newRequest = RetryableRibbonLoadBalancingHttpClient.this.getSecureRequest(request, configOverride);
                // the above should have been -
                // newRequest = RetryableRibbonLoadBalancingHttpClient.this.getSecureRequest(newRequest, configOverride);
    
                HttpUriRequest httpUriRequest = newRequest.toRequest(requestConfig);
                HttpResponse httpResponse = ((CloseableHttpClient)RetryableRibbonLoadBalancingHttpClient.this.delegate).execute(httpUriRequest);
                if (retryPolicy.retryableStatusCode(httpResponse.getStatusLine().getStatusCode())) {
                    if (CloseableHttpResponse.class.isInstance(httpResponse)) {
                        ((CloseableHttpResponse)httpResponse).close();
                    }
    
                    throw new RetryableStatusCodeException(RetryableRibbonLoadBalancingHttpClient.this.clientName, httpResponse.getStatusLine().getStatusCode());
                } else {
                    return new RibbonApacheHttpResponse(httpResponse, httpUriRequest.getURI());
                }
            }
        };
        return this.executeWithRetry(request, retryPolicy, retryCallback);
    }
    

    由于上面代码中的错误,虽然功能区配置(用于 maxAutoRetries 和 maxAutoRetriesNextServer)是基于 yaml 文件设置的,但使用下一个服务器 uri 对请求对象的更新被忽略并且总是与相同的服务器并导致副作用。

    这似乎在spring-cloud-netflix-core-1.4.3.RELEASE.jar 中得到修复。

    所以,更新 pom/bom

    • spring-cloud-dependencies 与版本 Edgware.SR2

    将功能区客户端依赖项更新为spring-cloud-netflix-core-1.4.3.RELEASE.jar,此问题现已解决。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-11-03
      • 1970-01-01
      • 1970-01-01
      • 2018-05-21
      • 2019-04-05
      • 1970-01-01
      • 2013-05-29
      相关资源
      最近更新 更多