microservices - 当一个服务实例正在终止时,JHipster 微服务网关暂时抛出 HTTP 500 错误
问题描述
我们有一个标准的 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$1.doWithRetry(RetryableRibbonLoadBalancingHttpClient.java:93)
at org.springframework.cloud.netflix.ribbon.apache.RetryableRibbonLoadBalancingHttpClient$1.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$1.call(AbstractLoadBalancerAwareClient.java:109)
at com.netflix.loadbalancer.reactive.LoadBalancerCommand$3$1.call(LoadBalancerCommand.java:303)
at com.netflix.loadbalancer.reactive.LoadBalancerCommand$3$1.call(LoadBalancerCommand.java:287)
at rx.internal.util.ScalarSynchronousObservable$3.call(ScalarSynchronousObservable.java:231)
at rx.internal.util.ScalarSynchronousObservable$3.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$1.call(LoadBalancerCommand.java:185)
at com.netflix.loadbalancer.reactive.LoadBalancerCommand$1.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/.. .)
- 终止一个微服务实例
- Relaod http://gateway/service/ ... 几次
- 几秒钟后会出现 HTTP 500 错误
- 再过几秒钟,错误就会消失,剩下的微服务会收到所有流量
由于我们使用的是开箱即用的 JHipster 设置,因此我们很困惑,因为在 Internet 上找不到任何解决此问题的文章。
有没有人遇到同样的问题,知道这里出了什么问题或如何解决这个问题?我们尝试了很长时间来寻找原因和解决方案,但我们觉得我们被困在这里。
如果您需要更多信息(日志、配置、跟踪等),我们很乐意在此处发布。
解决方案
您可以通过在 application.yml 中设置来启用spring-retry
(包含在默认 JHipster 网关的 pom.xml 中) 。zuul.retryable: true
然后将再次尝试任何失败的 GET 请求。如果您还希望多次尝试其他 HTTP 方法(例如 POST),请设置ribbon.OkToRetryOnAllOperations: true
http://cloud.spring.io/spring-cloud-static/Dalston.SR1/#retrying-failed-requests
推荐阅读
- java - 如何通过在 Java 中恢复数据来设置 int 值
- python - 从数据框列表中查找匹配项。Stupid Backoff 算法的实现
- typescript - 打字稿中的类型安全字典
- git - 带有docker执行器的gitlab-ci:maven无法检索scmbranch,buildScmBranch:未知
- node.js - 如何使用 Windows Server 2019 在 IIS 10 上托管 Node JS 应用程序
- android - 小吃店 - 不能在小吃店设置边距
- javascript - 点击事件页面滚动
- keycloak - 如何在 keycloak 中导入多个领域?
- android - RecyclerView 高度限制
- ios - 如何在 Swift UI 中获取过滤列表的索引?