77 застрявших потоков на фальшивой конечной точке ajax RestTemplate - PullRequest
1 голос
/ 08 июля 2019

В последние несколько дней я обнаружил проблему с моим Spring RestTemplate: не было установлено соединение и тайм-аут чтения, как вы можете видеть в следующем коде:

try {           
    RestTemplate restTemplate = new RestTemplate();
    restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(Charset.forName("UTF-8")));
    response = restTemplate.exchange(url, request.getMethod(), entity,responseClass);
}

Затем япроанализировали дамп потока, чтобы найти некоторые проблемы, возникающие из-за этого недостатка.

У меня 77 потоков, застрявших в java.net.SocketInputStream.socketRead0 в состоянии RUNNABLE с той же трассировкой стека, которая связана с моим RestTemplate:

priority:5 - threadId:0x00007f3e742f3000 - nativeId:0x3c67 - nativeId (decimal):15463 - state:RUNNABLE
stackTrace:
java.lang.Thread.State: RUNNABLE
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at java.io.BufferedInputStream.fill(BufferedInputStream.java:246)
at java.io.BufferedInputStream.read1(BufferedInputStream.java:286)
at java.io.BufferedInputStream.read(BufferedInputStream.java:345)
- locked <0x000000045e2643d0> (a java.io.BufferedInputStream)
at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:735)
at sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:678)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1569)
- locked <0x0000000454b57eb8> (a sun.net.www.protocol.http.HttpURLConnection)
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1474)
- locked <0x0000000454b57eb8> (a sun.net.www.protocol.http.HttpURLConnection)
at java.net.HttpURLConnection.getResponseCode(HttpURLConnection.java:480)
at org.springframework.http.client.SimpleClientHttpResponse.getRawStatusCode(SimpleClientHttpResponse.java:48)
at org.springframework.http.client.AbstractClientHttpResponse.getStatusCode(AbstractClientHttpResponse.java:33)
at org.springframework.web.client.DefaultResponseErrorHandler.getHttpStatusCode(DefaultResponseErrorHandler.java:56)
at org.springframework.web.client.DefaultResponseErrorHandler.hasError(DefaultResponseErrorHandler.java:50)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:604)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:572)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:532)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:450)
at com.project.pencil.external.rest.client.Client.performRequest(Client.java:86)
at com.project.pencil.external.rest.proxy.CalendarProxy.performRequest(CalendarProxy.java:33)
at com.project.pencil.external.rest.proxy.CalendarProxy.performRequest(CalendarProxy.java:22)
at com.project.pencil.rest.services.application.resources.CalendarResource.getCalendarElements(CalendarResource.java:99)
at sun.reflect.GeneratedMethodAccessor2149.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.cxf.service.invoker.AbstractInvoker.performInvocation(AbstractInvoker.java:180)
at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:96)
at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:189)
at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:99)

ЗдесьВот где происходит остальной вызов:

at com.project.pencil.external.rest.client.Client.performRequest(Client.java:86)
at com.project.pencil.external.rest.proxy.CalendarProxy.performRequest(CalendarProxy.java:33)
at com.project.pencil.external.rest.proxy.CalendarProxy.performRequest(CalendarProxy.java:22)
at com.project.pencil.rest.services.application.resources.CalendarResource.getCalendarElements(CalendarResource.java:99)

Действительно, отсутствие соединения и тайм-аут чтения вызывало проблемы.

Итак, сначала я попытался использовать «обходной путь» (избегая развертывания), я установил поддельную конечную точку для своего вызова ajax: http://800055.

Таким образом,RestTemplate не смог выполнить вызов, как вы можете видеть в трассировке стека исключения:

2019-07-05 11:00:46 [papa.smurf] INFO [com.project.pencil.external.rest.client.Client] (Client.java:75 - performRequest) - Request url: http://800055
2019-07-05 11:00:46 [papa.smurf] ERROR [com.project.pencil.external.client.Client] (Client.java:98 - performRequest) - An error occurred
org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://800055": Invalid argument or cannot assign requested address; nested exception is java.net.SocketException: Invalid argument or cannot assign requested address
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:582)
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:532)
    at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:450)
    at com.project.pencil.external.rest.client.Client.performRequest(Client.java:86)
    at com.project.pencil.external.rest.proxy.CalendarProxy.performRequest(CalendarProxy.java:33)
    at com.project.pencil.external.rest.proxy.CalendarProxy.performRequest(CalendarProxy.java:22)
    at com.project.pencil.rest.services.application.resources.CalendarResource.getCalendarElements(CalendarResource.java:99)
    at sun.reflect.GeneratedMethodAccessor1780.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.apache.cxf.service.invoker.AbstractInvoker.performInvocation(AbstractInvoker.java:180)
    at org.apache.cxf.service.invoker.AbstractInvoker.invoke(AbstractInvoker.java:96)
    at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:189)
    at org.apache.cxf.jaxrs.JAXRSInvoker.invoke(JAXRSInvoker.java:99)
    at org.apache.cxf.interceptor.ServiceInvokerInterceptor$1.run(ServiceInvokerInterceptor.java:59)
    at org.apache.cxf.interceptor.ServiceInvokerInterceptor.handleMessage(ServiceInvokerInterceptor.java:96)
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308)
    at org.apache.cxf.transport.ChainInitiationObserver.onMessage(ChainInitiationObserver.java:121)
    at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:252)
    at org.apache.cxf.transport.servlet.ServletController.invokeDestination(ServletController.java:234)
    at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:208)
    at org.apache.cxf.transport.servlet.ServletController.invoke(ServletController.java:160)
    at org.apache.cxf.transport.servlet.CXFNonSpringServlet.invoke(CXFNonSpringServlet.java:180)
    at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:299)
    at org.apache.cxf.transport.servlet.AbstractHTTPServlet.doGet(AbstractHTTPServlet.java:223)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:687)
    at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:274)

Я думал, что используя поддельную конечную точку, я мог бы избежать проблем с таймаутом, но застрявшие потоки были там, снова.

Как это возможно?Моя конечная точка не существует.

...