spring-cloud-netflix: may be found a bug for httpclient connection leak
refer #2814
I use a subclass of DefaultErrorAttributes to deal with exceptions
@Component("unifyErrorAttributes")
public class UnifyErrorAttributes extends DefaultErrorAttributes {
But I found that when exception generated,the http client connection can not be released.
here is normal routed request log,there are leased and released both exist,it’s normal:
But when route failed,only the http connection leased action exists but no released action,bcz the coming exception disturbed the release action in future:
the PostErrorHandlerFilter.java is a post filter,it throw an exception when route failed.
@Override
public Object filter() {
HttpServletResponse response = RequestContext.getCurrentContext().getResponse();
int cde = response.getStatus();
String uri=getOriginalRequest().getRequestURI();
HttpStatus status=HttpStatus.valueOf(cde);
String req_detail= (String)
ThreadLocalCache.get(GatewayFilterConstants.CacheKey.HTTP_REQ_DETAIL);
String body= (String)
ThreadLocalCache.get(GatewayFilterConstants.CacheKey.HTTP_REQ_BODY_DETAIL);
if(status.isError()){//||status.is3xxRedirection()){
runtimeURLCollection.errorUrls(uri,";"+cde+"[route response error]");
throw new GateWayException(BasicErrorEnum.ERROR_1001,"status:"+cde);
}
return null;
}
so, at last,all of the connections are not released,my app is down.‘netstat’ shows all TCP in CLOSE_WAIT my question: 1、is this a problem? 2、how to deal with that?
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Comments: 28 (12 by maintainers)
@brenuart The codes you provided works fine. Fixed my issue. Thanks. @zhangxsh Thanks for your explanation and guide. It helps me a lot.
@hooverhe no idea… But if you want to make sure connections and other resources are always disposed after the request is processed and can’t wait for this issue to be fixed, you can add the following to your Zuul application:
1/ Create a custom RequestContext implementation as follows:
2/ Add the following in your
@Configuration
class:That should help… 😉
My feeling is the issue is larger than what originally described. In short: there is no guarantee the upstream response is always closed.
For instance, although
SendResponseFilter#writeResponse()
does it’s best to guarantee that the response stream from origin is properly closed in all cases (cfr. release pooled connection). However, it does not cover exceptions thrown outside of thath method, like duringaddResponseHeader()
for instance. A first solution could be to wrap the entire run() method with a try/finally and move the close logic there.But still, this would only guarantee that the response is closed IF it goes through the SendResponseFilter. What would happen if an exception is raised somewhere between, say, the RibbonRoutingFilter and SendResponseFilter filters? Zuul should normally direct the request to the “error” filters - but none of them seems to care about closing the response like what the SendResponseFilter does.
A more robust approach would be:
unset()
is invoked.What you think ?
@hooverhe @brenuart bcz the expire close timer only close the connections which are expired but leak,leak means the connection can not to close or reuse.
bcz: 1、if exception throws,then the SendResponseFilter can not be invoked,and the connection are not to close:
To see the stack trace,the close activity is doing by the method of “releaseConnection” in ConnectionHolder.java ,close means:
-------------------------------------split-----------------------------------------
if ConnectionHolder not close the connection,the the connection can not reuse and can not cleared by the timer(bcz the timer will find the connection is active although it is idle in fact).
at last,the connection is terminated by the nginx(bcz of keepAlive_timeout config) unilaterally.
when nginx send a FIN package to zuul,then the tcp protocol return ACK and changes the status of this tcp to CLOSE_WAIT locally and notify the http client to close the socket,but the application do not response(no thread to use the socket,the connection is idle in fact),then the connection remains in the status of CLOSE_WAIT。 as the pic shows:
then the connection remains in CLOSE_WAIT . As we mentioned over that,more and more connections are in close_wait.the number of close_wait equals to the value of “max-per-route-connections”