복붙노트

[SPRING] Spring REST 템플릿을 사용하여 너무 많은 연결을 만들거나 느려진다.

SPRING

Spring REST 템플릿을 사용하여 너무 많은 연결을 만들거나 느려진다.

매우 빠르게 작동하는 RESTful 서비스가 있습니다. 내가 localhost에서 테스트하고있다. 클라이언트가 Spring REST 템플릿을 사용 중입니다. 나는 순진한 접근법을 사용하여 시작했다.

RestTemplate restTemplate = new RestTemplate(Collections.singletonList(new GsonHttpMessageConverter()));

Result result = restTemplate.postForObject(url, payload, Result.class);

이러한 요청을 많이하면 다음과 같은 예외가 발생합니다.

Caused by: org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://localhost:8080/myservice":No buffer space available (maximum connections reached?): connect; nested exception is java.net.SocketException: No buffer space available (maximum connections reached?): connect

이것은 연결이 닫히지 않고 TIME_WAIT 상태에 매달려 있기 때문에 발생합니다. 임시 포트가 고갈되면 예외가 발생하기 시작합니다. 그런 다음 실행은 포트가 다시 사용 가능하게 될 때까지 대기합니다. 나는 긴 휴식으로 최고 성능을보고있다. 내가 얻는 비율은 거의 필요하다. 물론 TIME_WAIT 연결은 좋지 않다. Linux (Ubuntu 14) 및 Windows (7)에서 테스트 한 결과 서로 다른 포트 범위로 인해 서로 다른 시간에 유사한 결과가 나타났습니다.

이 문제를 해결하기 위해 Apache HTTP 구성 요소 라이브러리에서 HttpClientBuilder를 사용하여 HttpClient를 사용해 보았습니다.

RestTemplate restTemplate = new RestTemplate(Collections.singletonList(new GsonHttpMessageConverter()));
HttpClient httpClient = HttpClientBuilder.create()
        .setMaxConnTotal(TOTAL)
        .setMaxConnPerRoute(PER_ROUTE)
        .build();
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory(httpClient));

Result result = restTemplate.postForObject(url, payload, Result.class);

이 클라이언트를 사용하면 예외가 없습니다. 클라이언트는 현재 임시 포트를 매우 제한적으로 사용하고 있습니다. 그러나 내가 사용하는 모든 설정 (TOTAL 및 PER_ROUTE)은 필요한 성능을 얻을 수 없습니다.

netstat 명령을 사용하여 서버에 많은 연결이 이루어지지 않았 음을 알았습니다. 숫자를 수천 개로 설정하려했지만 클라이언트가 그만큼 사용하지 않는 것 같습니다.

너무 많은 연결을 열지 않고 성능을 향상시키기 위해 할 수있는 일이 있습니까?

업데이트 : 나는 5000과 2500에 대한 총 및 경로 연결 당 설정 수를 시도했지만 클라이언트가 백 (netstat -n | wc -l에서 판단) 이상을 생성하지 않는 것처럼 보입니다. REST 서비스는 JAX-RS를 사용하고 Jetty에서 실행된다.

업데이트 2 : 이제 일부 메모리 설정으로 서버를 조정했고 실제로 처리량이 좋아지고 있습니다. 순진적인 접근법은 여전히 ​​조금 더 빠르지 만 클라이언트 측에서 풀링에 약간의 오버 헤드가 있다고 생각합니다.

해결법

  1. ==============================

    1.실제로 Spring Boot는 연결을 유출하지 않습니다. 여기서 볼 수있는 것은 Linux 커널 (및 모든 주요 OS)의 표준 동작입니다. 시스템에서 닫힌 모든 소켓은 일정 시간 동안 TIME_WAIT 상태가됩니다. 이는 임시 포트를 사용하는 다음 소켓이 실제로 그 포트의 이전 소켓을위한 패킷을 수신하지 못하도록하기위한 것입니다. 이 둘 사이에 나타나는 차이점은 각 연결 풀링 접근 방식의 결과입니다.

    실제로 Spring Boot는 연결을 유출하지 않습니다. 여기서 볼 수있는 것은 Linux 커널 (및 모든 주요 OS)의 표준 동작입니다. 시스템에서 닫힌 모든 소켓은 일정 시간 동안 TIME_WAIT 상태가됩니다. 이는 임시 포트를 사용하는 다음 소켓이 실제로 그 포트의 이전 소켓을위한 패킷을 수신하지 못하도록하기위한 것입니다. 이 둘 사이에 나타나는 차이점은 각 연결 풀링 접근 방식의 결과입니다.

    보다 구체적으로 RestTemplate은 기본적으로 연결 풀링을 사용하지 않습니다. 즉, 모든 나머지 호출은 새 로컬 임시 포트와 서버에 대한 새 연결을 엽니 다. 서비스가 매우 빠르면 사용 가능한 로컬 포트 ​​범위를 통해 즉시 중단됩니다. Apache HttpClient를 사용하면 연결 풀링을 활용할 수 있습니다. 이렇게하면 응용 프로그램에서 설명한 문제를 볼 수 없습니다. 그러나 서비스가 Linux 커널이 TIME_WAIT에서 소켓을 꺼내는 것보다 빠르게 응답 할 수 있다고 가정하면 연결 풀링은 사용자가하는 일에 상관없이 클라이언트를 느리게 만듭니다 (아무 것도 느려지지 않는다면 클라이언트가 느려질 것입니다. 지방 임시 항구의 다시).

    리눅스 커널에서 TCP 재사용을 가능하게하는 것은 위험 할 수 있습니다 (패킷이 지연 될 수 있고 모든 종류의 문제를 일으킬 수있는 임의의 패킷을 수신하는 임시 포트를 얻을 수 있습니다). 여기의 솔루션은 두 번째 예제에서와 같이 연결 풀링을 사용하는 것으로, 원하는 성능에 가까운 값을 충분히 확보 할 수 있습니다.

    연결 풀을 조정하는 데 도움이되도록 maxConnPerRoute 및 maxConnTotal 매개 변수를 조정해야합니다. maxConnPerRoute는 단일 IP : 포트 쌍에 대해 수행 될 연결 수를 제한하며 maxTotal은 열 수있는 총 연결 수를 제한합니다. 귀하의 경우, 모든 요청이 동일한 위치에 작성되었으므로 동일한 (높은) 값으로 설정할 수 있습니다.

  2. from https://stackoverflow.com/questions/31869193/using-spring-rest-template-either-creating-too-many-connections-or-slow by cc-by-sa and MIT license