Java Zuul:在服务不可用的情况下,自动将传入请求重新路由到其他服务实例

Java Zuul:在服务不可用的情况下,自动将传入请求重新路由到其他服务实例,java,spring-cloud,netflix-eureka,netflix-zuul,Java,Spring Cloud,Netflix Eureka,Netflix Zuul,我用Eureka配置了Zuul,一个服务的3个相同实例并行工作。我正在调用端口8400上的网关,它以循环方式将传入请求路由到端口8420、8430和8440。它工作顺利。现在,如果我关闭3项服务中的一项,少量传入请求将出现以下异常: com.netflix.zuul.exception.ZuulException: Filter threw Exception => 1: java.util.concurrent.FutureTask.report(FutureTask.java:

我用Eureka配置了Zuul,一个服务的3个相同实例并行工作。我正在调用端口8400上的网关,它以循环方式将传入请求路由到端口8420、8430和8440。它工作顺利。现在,如果我关闭3项服务中的一项,少量传入请求将出现以下异常:

com.netflix.zuul.exception.ZuulException: Filter threw Exception
    => 1: java.util.concurrent.FutureTask.report(FutureTask.java:122)
    => 3: hu.perit.spvitamin.core.batchprocessing.BatchProcessor.process(BatchProcessor.java:106)
    caused by: com.netflix.zuul.exception.ZuulException: Filter threw Exception
    => 1: com.netflix.zuul.FilterProcessor.processZuulFilter(FilterProcessor.java:227)
    caused by: org.springframework.cloud.netflix.zuul.util.ZuulRuntimeException: com.netflix.zuul.exception.ZuulException: Forwarding error
    => 1: org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter.run(RibbonRoutingFilter.java:124)
    caused by: com.netflix.zuul.exception.ZuulException: Forwarding error
    => 1: org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter.handleException(RibbonRoutingFilter.java:198)
    caused by: com.netflix.client.ClientException: com.netflix.client.ClientException
    => 1: com.netflix.client.AbstractLoadBalancerAwareClient.executeWithLoadBalancer(AbstractLoadBalancerAwareClient.java:118)
    caused by: java.lang.RuntimeException: org.apache.http.NoHttpResponseException: scalable-service-2:8430 failed to respond
    => 1: rx.exceptions.Exceptions.propagate(Exceptions.java:57)
    caused by: org.apache.http.NoHttpResponseException: scalable-service-2:8430 failed to respond
    => 1: org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:141)
我的Zuul路由如下所示:

### Zuul routes
zuul.routes.scalable-service.path=/scalable/**
#Authorization header will be forwarded to scalable-service
zuul.routes.scalable-service.sensitiveHeaders: Cookie,Set-Cookie
zuul.routes.scalable-service.serviceId=template-scalable-service
services:
    discovery:
        container_name: discovery
        image: template-eureka
        environment:
            #agentlib for remote debugging
            - JAVA_OPTS=-DEUREKA_SERVER=https://discovery:8400/eureka -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
            - TEMPLATE_EUREKA_OPTS=-Dspring.profiles.active=default,dev,discovery
            - EUREKA_ENVIRONMENT_PROFILE=dev
        ports:
            - '8400:8400'
            - '5500:5005'

        networks: 
            - back-tier-net
            - monitoring
        hostname: 'discovery'
Eureka需要一段时间才能发现该服务不再可用


我的问题是:是否有可能配置Zuul,以便在出现NoHttpResponseException的情况下,它将请求转发到池中的另一个可用实例?

Eureka
,默认情况下,要求每隔
90秒续订租约。也就是说,如果一个服务实例在
90年代
内没有获得续约,
Eureka
服务器将收回该实例。在您的情况下,
实例
尚未退出-实例的续订窗口有效

为此,您可以通过在
eureka客户端
eureka服务器
上的配置设置来缩短
续订
的持续时间,如前所述


注意:如果您点击
执行器/关机
端点,实例将立即

最终我找到了问题的解决方案。合适的搜索短语是“容错”。该键是以下application.properties文件中的autoretry配置。如果有3个池服务,则template-scalable-service.ribbon.MaxAutoRetriesNextServer的值必须至少设置为6,以实现完全容错。有了这个设置,我可以随时杀死3个服务中的2个,传入的请求不会出错。最后我将其设置为10,没有不必要的超时增加,hystrix将中断该行

### Eureka config
eureka.instance.hostname=${hostname:localhost}
eureka.instance.instanceId=${eureka.instance.hostname}:${spring.application.name}:${server.port}
eureka.instance.non-secure-port-enabled=false
eureka.instance.secure-port-enabled=true
eureka.instance.secure-port=${server.port}
eureka.instance.lease-renewal-interval-in-seconds=5
eureka.instance.lease-expiration-duration-in-seconds=10

eureka.datacenter=perit.hu
eureka.environment=${EUREKA_ENVIRONMENT_PROFILE:dev}
eureka.client.serviceUrl.defaultZone=${EUREKA_SERVER:https://${server.fqdn}:${server.port}/eureka}
eureka.client.server.waitTimeInMsWhenSyncEmpty=0
eureka.client.registry-fetch-interval-seconds=5
eureka.dashboard.path=/gui

eureka.server.enable-self-preservation=false
eureka.server.expected-client-renewal-interval-seconds=10
eureka.server.eviction-interval-timer-in-ms=2000

### Ribbon
ribbon.IsSecure=true
ribbon.NFLoadBalancerPingInterval=5
ribbon.ConnectTimeout=30000
ribbon.ReadTimeout=120000

### Zuul config
zuul.host.connectTimeoutMillis=30000
zuul.host.socketTimeoutMillis=120000
zuul.host.maxTotalConnections=2000
zuul.host.maxPerRouteConnections=200
zuul.retryable=true

### Zuul routes
#template-scalable-service
zuul.routes.scalable-service.path=/scalable/**
#Authorization header will be forwarded to scalable-service
zuul.routes.scalable-service.sensitiveHeaders=Cookie,Set-Cookie
zuul.routes.scalable-service.serviceId=template-scalable-service
# Autoretry config for template-scalable-service
template-scalable-service.ribbon.MaxAutoRetries=0
template-scalable-service.ribbon.MaxAutoRetriesNextServer=10
template-scalable-service.ribbon.OkToRetryOnAllOperations=true

#template-auth-service
zuul.routes.auth-service.path=/auth/**
#Authorization header will be forwarded to scalable-service
zuul.routes.auth-service.sensitiveHeaders=Cookie,Set-Cookie
zuul.routes.auth-service.serviceId=template-auth-service
# Autoretry config for template-auth-service
template-auth-service.ribbon.MaxAutoRetries=0
template-auth-service.ribbon.MaxAutoRetriesNextServer=0
template-auth-service.ribbon.OkToRetryOnAllOperations=false

### Hystrix
hystrix.command.default.execution.timeout.enabled=false
除此之外,我在application-discovery.properties中有一个特定于配置文件的设置

#Microservice environment
eureka.client.registerWithEureka=false
eureka.client.fetchRegistry=true
spring.cloud.loadbalancer.ribbon.enabled=true
我在docker容器中启动服务器,如下所示:

### Zuul routes
zuul.routes.scalable-service.path=/scalable/**
#Authorization header will be forwarded to scalable-service
zuul.routes.scalable-service.sensitiveHeaders: Cookie,Set-Cookie
zuul.routes.scalable-service.serviceId=template-scalable-service
services:
    discovery:
        container_name: discovery
        image: template-eureka
        environment:
            #agentlib for remote debugging
            - JAVA_OPTS=-DEUREKA_SERVER=https://discovery:8400/eureka -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005
            - TEMPLATE_EUREKA_OPTS=-Dspring.profiles.active=default,dev,discovery
            - EUREKA_ENVIRONMENT_PROFILE=dev
        ports:
            - '8400:8400'
            - '5500:5005'

        networks: 
            - back-tier-net
            - monitoring
        hostname: 'discovery'

查看

中的完整解决方案非常感谢链接,我可以改进我的设置。现在更好了,不正常终止的服务客户端在10秒内消失,但在这10秒内,Eureka继续将请求转发给终止的客户端。我正在寻找一种解决方案,只要有1个以上的实例使用相同的应用程序名称注册,Eureka就会尝试在服务不可用和逐出之间将请求转发给其他同类服务。@PeterNagy但在这10秒内Eureka会不断将请求转发给被杀死的客户端。这件事是用尤里卡密码处理的。所以,在这种情况下你无能为力。缩短(
~2s
)续费时间,并在Zuul设置重试机制,或点击执行器/停机
端点进行停机。这将向Eureka发送显式调用以逐出实例