JHipster 微服务网关在一个服务实例终止时暂时抛出 HTTP 500 错误
JHipster microservice gateway temporarily throws HTTP 500 error when one service instance is terminating
我们有一个标准的 JHipster 设置,包括一个网关和一个微服务应用程序。 JHipster-Registry 用于服务发现。我们没有对 JHipster 生成器生成的代码或配置进行任何形式的更改。
一切正常。但是,当关闭其中一个微服务应用程序实例(SIGINT、CLI 上的 ^C、Kubernetes pod 终止)时,我们暂时收到 HTTP 500 内部服务器错误,用于通过网关向微服务端点发出请求(http://gateway/service/..)。
请在下面找到网关中 HTTP 500 错误的堆栈跟踪:
Caused by: org.apache.http.NoHttpResponseException: 172.16.94.61:8085 failed to respond
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:141)
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:56)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:259)
at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:163)
at org.apache.http.impl.conn.CPoolProxy.receiveResponseHeader(CPoolProxy.java:165)
at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:273)
at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:125)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:272)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:111)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56)
at org.springframework.cloud.netflix.ribbon.apache.RetryableRibbonLoadBalancingHttpClient.doWithRetry(RetryableRibbonLoadBalancingHttpClient.java:93)
at org.springframework.cloud.netflix.ribbon.apache.RetryableRibbonLoadBalancingHttpClient.doWithRetry(RetryableRibbonLoadBalancingHttpClient.java:71)
at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:287)
at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:164)
at org.springframework.cloud.netflix.ribbon.apache.RetryableRibbonLoadBalancingHttpClient.executeWithRetry(RetryableRibbonLoadBalancingHttpClient.java:113)
at org.springframework.cloud.netflix.ribbon.apache.RetryableRibbonLoadBalancingHttpClient.execute(RetryableRibbonLoadBalancingHttpClient.java:104)
at org.springframework.cloud.netflix.ribbon.apache.RetryableRibbonLoadBalancingHttpClient.execute(RetryableRibbonLoadBalancingHttpClient.java:50)
at com.netflix.client.AbstractLoadBalancerAwareClient.call(AbstractLoadBalancerAwareClient.java:109)
at com.netflix.loadbalancer.reactive.LoadBalancerCommand.call(LoadBalancerCommand.java:303)
at com.netflix.loadbalancer.reactive.LoadBalancerCommand.call(LoadBalancerCommand.java:287)
at rx.internal.util.ScalarSynchronousObservable.call(ScalarSynchronousObservable.java:231)
at rx.internal.util.ScalarSynchronousObservable.call(ScalarSynchronousObservable.java:228)
at rx.Observable.unsafeSubscribe(Observable.java:10211)
at rx.internal.operators.OnSubscribeConcatMap$ConcatMapSubscriber.drain(OnSubscribeConcatMap.java:286)
at rx.internal.operators.OnSubscribeConcatMap$ConcatMapSubscriber.onNext(OnSubscribeConcatMap.java:144)
at com.netflix.loadbalancer.reactive.LoadBalancerCommand.call(LoadBalancerCommand.java:185)
at com.netflix.loadbalancer.reactive.LoadBalancerCommand.call(LoadBalancerCommand.java:180)
at rx.Observable.unsafeSubscribe(Observable.java:10211)
at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:94)
at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:42)
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)
at rx.Observable.subscribe(Observable.java:10307)
at rx.Observable.subscribe(Observable.java:10274)
at rx.observables.BlockingObservable.blockForSingle(BlockingObservable.java:445)
看起来网关的负载均衡器仍在使用正在终止的微服务实例。
我们还尝试了 Consul 而不是 JHipster-Registry/Eureka 并发现了相同的行为。
重现步骤:
- 启动一个注册中心,一个网关和两个微服务实例(使用gradlew)
- 等待并确认一切正常,运行(调用 http://gateway/service/..。)
- 终止一个微服务实例
- 重读http://gateway/service/...几次
- 几秒钟后将出现 HTTP 500 错误
- 几秒钟后错误将消失,剩余的微服务接收所有流量
由于我们使用的是开箱即用的 JHipster 设置,我们很困惑,因为在 Internet 上找不到任何解决此问题的文章。
有没有人遇到同样的问题,知道这里出了什么问题或如何解决这个问题?我们尝试了很长时间来寻找原因和解决方案,但我们觉得我们被困在这里了。
如果您需要更多信息(日志、配置、跟踪等),我们很乐意 post 在这里。
您可以通过在 application.yml 中设置 zuul.retryable: true
来启用 spring-retry
(包含在默认 JHipster 网关的 pom.xml 中)。然后将再次尝试任何失败的 GET 请求。如果您还希望多次尝试其他 HTTP 方法,例如 POST,请设置 ribbon.OkToRetryOnAllOperations: true
http://cloud.spring.io/spring-cloud-static/Dalston.SR1/#retrying-failed-requests
我们有一个标准的 JHipster 设置,包括一个网关和一个微服务应用程序。 JHipster-Registry 用于服务发现。我们没有对 JHipster 生成器生成的代码或配置进行任何形式的更改。
一切正常。但是,当关闭其中一个微服务应用程序实例(SIGINT、CLI 上的 ^C、Kubernetes pod 终止)时,我们暂时收到 HTTP 500 内部服务器错误,用于通过网关向微服务端点发出请求(http://gateway/service/..)。
请在下面找到网关中 HTTP 500 错误的堆栈跟踪:
Caused by: org.apache.http.NoHttpResponseException: 172.16.94.61:8085 failed to respond
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:141)
at org.apache.http.impl.conn.DefaultHttpResponseParser.parseHead(DefaultHttpResponseParser.java:56)
at org.apache.http.impl.io.AbstractMessageParser.parse(AbstractMessageParser.java:259)
at org.apache.http.impl.DefaultBHttpClientConnection.receiveResponseHeader(DefaultBHttpClientConnection.java:163)
at org.apache.http.impl.conn.CPoolProxy.receiveResponseHeader(CPoolProxy.java:165)
at org.apache.http.protocol.HttpRequestExecutor.doReceiveResponse(HttpRequestExecutor.java:273)
at org.apache.http.protocol.HttpRequestExecutor.execute(HttpRequestExecutor.java:125)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:272)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:185)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:111)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:185)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56)
at org.springframework.cloud.netflix.ribbon.apache.RetryableRibbonLoadBalancingHttpClient.doWithRetry(RetryableRibbonLoadBalancingHttpClient.java:93)
at org.springframework.cloud.netflix.ribbon.apache.RetryableRibbonLoadBalancingHttpClient.doWithRetry(RetryableRibbonLoadBalancingHttpClient.java:71)
at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:287)
at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:164)
at org.springframework.cloud.netflix.ribbon.apache.RetryableRibbonLoadBalancingHttpClient.executeWithRetry(RetryableRibbonLoadBalancingHttpClient.java:113)
at org.springframework.cloud.netflix.ribbon.apache.RetryableRibbonLoadBalancingHttpClient.execute(RetryableRibbonLoadBalancingHttpClient.java:104)
at org.springframework.cloud.netflix.ribbon.apache.RetryableRibbonLoadBalancingHttpClient.execute(RetryableRibbonLoadBalancingHttpClient.java:50)
at com.netflix.client.AbstractLoadBalancerAwareClient.call(AbstractLoadBalancerAwareClient.java:109)
at com.netflix.loadbalancer.reactive.LoadBalancerCommand.call(LoadBalancerCommand.java:303)
at com.netflix.loadbalancer.reactive.LoadBalancerCommand.call(LoadBalancerCommand.java:287)
at rx.internal.util.ScalarSynchronousObservable.call(ScalarSynchronousObservable.java:231)
at rx.internal.util.ScalarSynchronousObservable.call(ScalarSynchronousObservable.java:228)
at rx.Observable.unsafeSubscribe(Observable.java:10211)
at rx.internal.operators.OnSubscribeConcatMap$ConcatMapSubscriber.drain(OnSubscribeConcatMap.java:286)
at rx.internal.operators.OnSubscribeConcatMap$ConcatMapSubscriber.onNext(OnSubscribeConcatMap.java:144)
at com.netflix.loadbalancer.reactive.LoadBalancerCommand.call(LoadBalancerCommand.java:185)
at com.netflix.loadbalancer.reactive.LoadBalancerCommand.call(LoadBalancerCommand.java:180)
at rx.Observable.unsafeSubscribe(Observable.java:10211)
at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:94)
at rx.internal.operators.OnSubscribeConcatMap.call(OnSubscribeConcatMap.java:42)
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:48)
at rx.internal.operators.OnSubscribeLift.call(OnSubscribeLift.java:30)
at rx.Observable.subscribe(Observable.java:10307)
at rx.Observable.subscribe(Observable.java:10274)
at rx.observables.BlockingObservable.blockForSingle(BlockingObservable.java:445)
看起来网关的负载均衡器仍在使用正在终止的微服务实例。
我们还尝试了 Consul 而不是 JHipster-Registry/Eureka 并发现了相同的行为。
重现步骤:
- 启动一个注册中心,一个网关和两个微服务实例(使用gradlew)
- 等待并确认一切正常,运行(调用 http://gateway/service/..。)
- 终止一个微服务实例
- 重读http://gateway/service/...几次
- 几秒钟后将出现 HTTP 500 错误
- 几秒钟后错误将消失,剩余的微服务接收所有流量
由于我们使用的是开箱即用的 JHipster 设置,我们很困惑,因为在 Internet 上找不到任何解决此问题的文章。
有没有人遇到同样的问题,知道这里出了什么问题或如何解决这个问题?我们尝试了很长时间来寻找原因和解决方案,但我们觉得我们被困在这里了。
如果您需要更多信息(日志、配置、跟踪等),我们很乐意 post 在这里。
您可以通过在 application.yml 中设置 zuul.retryable: true
来启用 spring-retry
(包含在默认 JHipster 网关的 pom.xml 中)。然后将再次尝试任何失败的 GET 请求。如果您还希望多次尝试其他 HTTP 方法,例如 POST,请设置 ribbon.OkToRetryOnAllOperations: true
http://cloud.spring.io/spring-cloud-static/Dalston.SR1/#retrying-failed-requests