Netflix 功能区和 Hystrix 超时
Netflix Ribbon and Hystrix Timeout
我们在项目中使用 Spring 云。我们有几个微服务,每个都有自己的 .yml 文件。
以下属性仅在 zuul 服务器中
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 60000
ribbon:
ConnectTimeout: 3000
ReadTimeout: 60000
测试 1:
账户服务:
我正在调用此服务来测试超时,我正在通过 zuul 调用请求,即使用端口 8006。
@RequestMapping(value = "/accountholders/{cardHolderId}/accounts", produces = "application/json; charset=utf-8", method = RequestMethod.GET)
@ResponseBody
public AllAccountsVO getAccounts(@PathVariable("cardHolderId") final String cardHolderId,
@RequestHeader("userContextId") final String userContextId,
@RequestParam final MultiValueMap<String, String> allRequestParams, final HttpServletRequest request) {
return iAccountService.getCardHolderAccountsInfo(cardHolderId, userContextId, request, allRequestParams,
ApplicationConstants.ACCOUNTHOLDER);
}
上述服务使用 Spring RestTemplate 在内部调用以下服务。
我通过在 Association Service 中添加 5000ms 的睡眠时间开始测试,并向 Accounts Service 发出请求(getAccounts 调用)。
关联服务:
@RequestMapping(value = "/internal/userassociationstatus", produces = "application/json; charset=utf-8", consumes = "application/json", method = RequestMethod.GET)
@ResponseBody
public UserAssociationStatusVO getUserAssociationStatus(@RequestParam final Map<String, String> allRequestParams) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return iUserAssociationsService.getUserAssociationStatus(allRequestParams);
}
下面是我在Association Service
中得到的错误
org.apache.catalina.connector.ClientAbortException: java.io.IOException: An established connection was aborted by the software in your host machine
at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:393) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:426) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:342) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
以下是我在 Accounts Service
中遇到的错误
org.springframework.web.client.ResourceAccessException: I/O error on GET request for "http://USERASSOCIATIONS-V1/user/v1/internal/userassociationstatus?cardholderid=123&usercontextid=222&role=ACCOUNT": com.sun.jersey.api.client.ClientHandlerException: java.net.SocketTimeoutException: Read timed out; nested exception is java.io.IOException: com.sun.jersey.api.client.ClientHandlerException: java.net.SocketTimeoutException: Read timed out
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:607) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:557) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:475) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
如果我将睡眠时间保持为 4500,它会给我响应,但如果 >=4800,它会抛出上述异常。我认为这与功能区超时无关,但与其他因素有关。特定点后出现上述异常的任何具体原因。
测试 2
然后我尝试直接在 Accounts Service 中保持 75000 毫秒的休眠时间并删除休眠时间 Association Service.
@RequestMapping(value = "/accountholders/{cardHolderId}/accounts", produces = "application/json; charset=utf-8", method = RequestMethod.GET)
@ResponseBody
public AllAccountsVO getAccounts(@PathVariable("cardHolderId") final String cardHolderId,
@RequestHeader("userContextId") final String userContextId,
@RequestParam final MultiValueMap<String, String> allRequestParams, final HttpServletRequest request) {
try {
Thread.sleep(75000);
} catch (InterruptedException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
}
return iAccountService.getCardHolderAccountsInfo(cardHolderId, userContextId, request, allRequestParams,
ApplicationConstants.ACCOUNTHOLDER);
}
在这种情况下我得到了 "exception": "com.netflix.zuul.exception.ZuulException",
并且在我的 APIGateway(Zuul 应用程序)日志中我看到以下错误。
com.netflix.zuul.exception.ZuulException: Forwarding error
at org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter.forward(RibbonRoutingFilter.java:134) ~[spring-cloud-netflix-core-1.1.0.M5.jar:1.1.0.M5]
at org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter.run(RibbonRoutingFilter.java:76) ~[spring-cloud-netflix-core-1.1.0.M5.jar:1.1.0.M5]
at com.netflix.zuul.ZuulFilter.runFilter(ZuulFilter.java:112) ~[zuul-core-1.1.0.jar:1.1.0]
at com.netflix.zuul.FilterProcessor.processZuulFilter(FilterProcessor.java:197) ~[zuul-core-1.1.0.jar:1.1.0]
Caused by: com.netflix.hystrix.exception.HystrixRuntimeException: useraccounts-v1RibbonCommand timed-out and no fallback available.
at com.netflix.hystrix.AbstractCommand.call(AbstractCommand.java:806) ~[hystrix-core-1.4.23.jar:1.4.23]
at com.netflix.hystrix.AbstractCommand.call(AbstractCommand.java:790) ~[hystrix-core-1.4.23.jar:1.4.23]
at rx.internal.operators.OperatorOnErrorResumeNextViaFunction.onError(OperatorOnErrorResumeNextViaFunction.java:99) ~[rxjava-1.0.14.jar:1.0.14]
at rx.internal.operators.OperatorDoOnEach.onError(OperatorDoOnEach.java:70) ~[rxjava-1.0.14.jar:1.0.14]
我认为这与 Ribbon ConnectTimeout 或 ReadTimeout 无关。这个错误是因为属性"execution.isolation.thread.timeoutInMilliseconds: 60000"。我还将此 属性 减少到 10000 毫秒以测试行为,如果睡眠时间更长(例如:12000),我会得到相同的异常。
我想了解 Ribbon ConnectTimeout 和读取超时与 Hystrix 超时以及如何在我的应用程序中测试 Ribbon 超时。另外,如果我想为不同的微服务设置不同的超时时间,我是否将这些属性保留在各自的 .yml 文件中? 有什么想法吗?
我正在尝试创建一个供我的团队使用的文档,以便开发人员可以轻松了解这些超时选项在 Spring 云中的工作原理。
(很长的描述,但为了更清楚,我必须详细写)
ribbon 中的connectTimeout
和readTimeout
向下传递给底层HTTP 客户端。它们适用于 HTTP 连接(连接建立后不适用于 HTTP 请求)。我不确定为什么您真的需要像这样测试它,但是对于健康的服务器来说很难。例如,对于 connectTimeout
,您需要一个可以接受 TCP 连接但不完成 HTTP 层连接的。对于 readTimeout
,您需要一个建立连接但随后不发送任何数据(根本不发送)的设备。
我们在项目中使用 Spring 云。我们有几个微服务,每个都有自己的 .yml 文件。
以下属性仅在 zuul 服务器中
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 60000
ribbon:
ConnectTimeout: 3000
ReadTimeout: 60000
测试 1:
账户服务:
我正在调用此服务来测试超时,我正在通过 zuul 调用请求,即使用端口 8006。
@RequestMapping(value = "/accountholders/{cardHolderId}/accounts", produces = "application/json; charset=utf-8", method = RequestMethod.GET)
@ResponseBody
public AllAccountsVO getAccounts(@PathVariable("cardHolderId") final String cardHolderId,
@RequestHeader("userContextId") final String userContextId,
@RequestParam final MultiValueMap<String, String> allRequestParams, final HttpServletRequest request) {
return iAccountService.getCardHolderAccountsInfo(cardHolderId, userContextId, request, allRequestParams,
ApplicationConstants.ACCOUNTHOLDER);
}
上述服务使用 Spring RestTemplate 在内部调用以下服务。 我通过在 Association Service 中添加 5000ms 的睡眠时间开始测试,并向 Accounts Service 发出请求(getAccounts 调用)。
关联服务:
@RequestMapping(value = "/internal/userassociationstatus", produces = "application/json; charset=utf-8", consumes = "application/json", method = RequestMethod.GET)
@ResponseBody
public UserAssociationStatusVO getUserAssociationStatus(@RequestParam final Map<String, String> allRequestParams) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return iUserAssociationsService.getUserAssociationStatus(allRequestParams);
}
下面是我在Association Service
中得到的错误org.apache.catalina.connector.ClientAbortException: java.io.IOException: An established connection was aborted by the software in your host machine
at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:393) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
at org.apache.tomcat.util.buf.ByteChunk.flushBuffer(ByteChunk.java:426) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:342) ~[tomcat-embed-core-8.0.30.jar:8.0.30]
以下是我在 Accounts Service
中遇到的错误org.springframework.web.client.ResourceAccessException: I/O error on GET request for "http://USERASSOCIATIONS-V1/user/v1/internal/userassociationstatus?cardholderid=123&usercontextid=222&role=ACCOUNT": com.sun.jersey.api.client.ClientHandlerException: java.net.SocketTimeoutException: Read timed out; nested exception is java.io.IOException: com.sun.jersey.api.client.ClientHandlerException: java.net.SocketTimeoutException: Read timed out
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:607) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:557) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:475) ~[spring-web-4.2.4.RELEASE.jar:4.2.4.RELEASE]
如果我将睡眠时间保持为 4500,它会给我响应,但如果 >=4800,它会抛出上述异常。我认为这与功能区超时无关,但与其他因素有关。特定点后出现上述异常的任何具体原因。
测试 2
然后我尝试直接在 Accounts Service 中保持 75000 毫秒的休眠时间并删除休眠时间 Association Service.
@RequestMapping(value = "/accountholders/{cardHolderId}/accounts", produces = "application/json; charset=utf-8", method = RequestMethod.GET)
@ResponseBody
public AllAccountsVO getAccounts(@PathVariable("cardHolderId") final String cardHolderId,
@RequestHeader("userContextId") final String userContextId,
@RequestParam final MultiValueMap<String, String> allRequestParams, final HttpServletRequest request) {
try {
Thread.sleep(75000);
} catch (InterruptedException ex) {
// TODO Auto-generated catch block
ex.printStackTrace();
}
return iAccountService.getCardHolderAccountsInfo(cardHolderId, userContextId, request, allRequestParams,
ApplicationConstants.ACCOUNTHOLDER);
}
在这种情况下我得到了 "exception": "com.netflix.zuul.exception.ZuulException",
并且在我的 APIGateway(Zuul 应用程序)日志中我看到以下错误。
com.netflix.zuul.exception.ZuulException: Forwarding error
at org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter.forward(RibbonRoutingFilter.java:134) ~[spring-cloud-netflix-core-1.1.0.M5.jar:1.1.0.M5]
at org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter.run(RibbonRoutingFilter.java:76) ~[spring-cloud-netflix-core-1.1.0.M5.jar:1.1.0.M5]
at com.netflix.zuul.ZuulFilter.runFilter(ZuulFilter.java:112) ~[zuul-core-1.1.0.jar:1.1.0]
at com.netflix.zuul.FilterProcessor.processZuulFilter(FilterProcessor.java:197) ~[zuul-core-1.1.0.jar:1.1.0]
Caused by: com.netflix.hystrix.exception.HystrixRuntimeException: useraccounts-v1RibbonCommand timed-out and no fallback available.
at com.netflix.hystrix.AbstractCommand.call(AbstractCommand.java:806) ~[hystrix-core-1.4.23.jar:1.4.23]
at com.netflix.hystrix.AbstractCommand.call(AbstractCommand.java:790) ~[hystrix-core-1.4.23.jar:1.4.23]
at rx.internal.operators.OperatorOnErrorResumeNextViaFunction.onError(OperatorOnErrorResumeNextViaFunction.java:99) ~[rxjava-1.0.14.jar:1.0.14]
at rx.internal.operators.OperatorDoOnEach.onError(OperatorDoOnEach.java:70) ~[rxjava-1.0.14.jar:1.0.14]
我认为这与 Ribbon ConnectTimeout 或 ReadTimeout 无关。这个错误是因为属性"execution.isolation.thread.timeoutInMilliseconds: 60000"。我还将此 属性 减少到 10000 毫秒以测试行为,如果睡眠时间更长(例如:12000),我会得到相同的异常。
我想了解 Ribbon ConnectTimeout 和读取超时与 Hystrix 超时以及如何在我的应用程序中测试 Ribbon 超时。另外,如果我想为不同的微服务设置不同的超时时间,我是否将这些属性保留在各自的 .yml 文件中? 有什么想法吗?
我正在尝试创建一个供我的团队使用的文档,以便开发人员可以轻松了解这些超时选项在 Spring 云中的工作原理。
(很长的描述,但为了更清楚,我必须详细写)
ribbon 中的connectTimeout
和readTimeout
向下传递给底层HTTP 客户端。它们适用于 HTTP 连接(连接建立后不适用于 HTTP 请求)。我不确定为什么您真的需要像这样测试它,但是对于健康的服务器来说很难。例如,对于 connectTimeout
,您需要一个可以接受 TCP 连接但不完成 HTTP 层连接的。对于 readTimeout
,您需要一个建立连接但随后不发送任何数据(根本不发送)的设备。