Zuul:在服务不可用时自动将传入的请求重新路由到其他服务实例。

huangapple go评论62阅读模式
英文:

Zuul: automatic rerouting incoming requests to other service instance in case of unavailable service

问题

I've translated the provided text for you:

我已经按照一种方式配置了Eureka的Zuul,以便让三个相同的服务实例可以并行工作。我在端口8400上调用网关,该网关将传入的请求以循环方式路由到端口8420、8430和8440。它运行得很顺利。现在,如果我关闭了三个服务中的一个,一小部分传入的请求将出现以下异常:

    => 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: 过滤器抛出异常
    => 1: com.netflix.zuul.FilterProcessor.processZuulFilter(FilterProcessor.java:227)
    caused by: org.springframework.cloud.netflix.zuul.util.ZuulRuntimeException: com.netflix.zuul.exception.ZuulException: 转发错误
    => 1: org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter.run(RibbonRoutingFilter.java:124)
    caused by: com.netflix.zuul.exception.ZuulException: 转发错误
    => 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 未能响应
    => 1: rx.exceptions.Exceptions.propagate(Exceptions.java:57)
    caused by: org.apache.http.NoHttpResponseException: scalable-service-2:8430 未能响应
    => 1: org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:141)

我的Zuul路由配置如下:

zuul.routes.scalable-service.path=/scalable/**
#Authorization 标头将被转发到 scalable-service
zuul.routes.scalable-service.sensitiveHeaders: Cookie,Set-Cookie
zuul.routes.scalable-service.serviceId=template-scalable-service

直到Eureka发现服务不再可用,这需要一些时间。

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

英文:

I have configured Zuul with Eureka in a way, that 3 identical instances of a service are working parallely. I am calling the gateway on the port 8400, which routes incoming requests to ports 8420, 8430 and 8440 in a round-robin manner. It works smoothly. Now, if I switching off one of the 3 services, a small amount of incoming requests will go wrong with the following exception:

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)

My Zuul routing looks like this:

### 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

It takes a while until Eureka discovers the service is not available any more.

My question is: Is there a possibility, to configure Zuul so that in case of a NoHttpResponseException, it forwards the requests to another available instance in the pool?

答案1

得分: 1

Eureka默认情况下要求每90秒更新一次租约。也就是说,如果一个服务实例在90秒内没有更新它的租约,Eureka服务器将会将该实例驱逐。在你的情况下,该实例尚未被驱逐 - 该实例的更新窗口是有效的。

为此,你可以通过在eureka客户端eureka服务器的配置设置中减少renew持续时间来进行配置,具体方法请参考这里

注意: 如果你访问actuator /shutdown端点,该实例将立即被驱逐

英文:

Eureka, by default, requires lease to be renewed every 90s. That is, if a service instance doesn't get its lease renewed in 90s, Eureka server will evict the instance. In your case, the instance has not been evicted yet - the renew window for the instance was valid.

For this, you can decrease the renew duration through config setup at eureka client and eureka server as described here.

Note: If you hit the actuator /shutdown endpoint, the instance is immediately evicted

答案2

得分: 0

最终我找到了解决问题的方法。适当的搜索词组是'fault tolerance'(容错性)。关键在于以下application.properties文件中的自动重试配置autoretry config。在具有3个池化服务的情况下,template-scalable-service.ribbon.MaxAutoRetriesNextServer的值必须至少设置为6,以实现完全的容错性。通过这样的设置,我随时可以关闭其中的2个服务,而没有任何进入的请求会出错。最终我将其设置为10,没有不必要的超时增加,hystrix会中断连接。

此外,我在application-discovery.properties中还有一个特定配置的设置:

#微服务环境
eureka.client.registerWithEureka=false
eureka.client.fetchRegistry=true
spring.cloud.loadbalancer.ribbon.enabled=true

我像这样在docker容器中启动服务器:

services:
    discovery:
        container_name: discovery
        image: template-eureka
        environment:
            #agentlib用于远程调试
            - 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'

GitHub上查看完整的解决方案。

英文:

Finally I found the solution to the problem. The appropriate search phrase was 'fault tolerance'. The key is the autoretry config in the following application.properties file. The value of template-scalable-service.ribbon.MaxAutoRetriesNextServer must be set at least to 6 in case of 3 pooled services to achieve full fault tolerance. With that setup I can kill 2 of 3 services any time, no incoming request will go wrong. Finally I have set it to 10, there is no unnecessary increase of timeout, hystrix will break the line.

### 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

Beside of this, I have a profile specific setup in application-discovery.properties

#Microservice environment
eureka.client.registerWithEureka=false
eureka.client.fetchRegistry=true
spring.cloud.loadbalancer.ribbon.enabled=true

I start my server in a docker container like this:

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'

See the complete solution in GitHub.

huangapple
  • 本文由 发表于 2020年8月14日 20:46:33
  • 转载请务必保留本文链接:https://go.coder-hub.com/63413050.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定