Webclient recv: Connection reset by peer

UnknownUnknown
2 min read

Java 21, Webclient(Webflux), VirtualThread 환경에서 외부 API와 통신 할 때 아래와 같은 오류가 빈번히 발생하였습니다. 이를 해결하기 위해 어떤 작업을 진행하였는지 간략히 설명하고자 합니다.

Errors.NativeIoException: recvAddress(..) failed: Connection reset by peer

"Connection reset by peer"는 일반적으로 TCP 연결이 예기치 않게 종료되었을 때 발생하는 오류입니다. 이 오류의 원인과 해결 방법에 대해 LLM에 물어본 결과 아래와 같은 원인이 있을 수 있다고 답변 받았습니다.

  • 가능한 원인:
    • 네트워크 불안정성: 클라이언트와 서버 사이의 네트워크 연결이 불안정하거나 끊어질 때 발생할 수 있습니다.
    • 서버 측 문제:
      • 서버가 갑자기 연결을 종료했을 수 있습니다.
      • 서버의 리소스 부족(메모리, CPU 등)으로 인해 연결을 처리하지 못할 수 있습니다.
      • 서버의 방화벽이나 보안 설정이 연결을 차단했을 수 있습니다.
    • 타임아웃 설정: WebClient나 서버의 타임아웃 설정이 너무 짧아 연결이 조기에 종료될 수 있습니다.
    • SSL/TLS 문제: HTTPS 연결을 사용하는 경우, 인증서 문제나 프로토콜 불일치로 인해 연결이 리셋될 수 있습니다.
    • 로드 밸런서 문제: 로드 밸런서가 연결을 적절히 관리하지 못하는 경우 이런 오류가 발생할 수 있습니다.

처음에는 네트워크 불안정과 외부 Server문제점에 초점을 두고 외부 Server의 Timeout이나 방화벽 등의 문제가 있는지 접근하고 문의 하였습니다. 그리고, ssl/tsl, loadbalancer 등도 확인하였지만 별다른 문제를 확인할 수가 없었습니다. (오류가 수정이 되지를 않았습니다)

그래서 생각을 바꿔 우리의 클라이언트의 설정 혹은 코드 단의 문제가 아닐까 하고 의심을 하게 되었습니다. 그래서 먼저 클라이언트 라이브러리를 Webclient에서 okhttp로 바꾸어 처리를 해보았습니다. 놀랍게도 해당 현상이 해결이 되었습니다. 다만, Webclient의 문제라면 앞으로 다른 프로젝트에서도 사용하기에는 안정성에 문제가 발생할 수 있어 Webclient 설정과 코딩 변경으로 해결 될 수 있는지 방법을 확인하였고 결과적으로는 아래의 코드로 해결할 수 있었습니다.

아직 왜 해결이 된 것인지 상세하게 분석을 하지 못해 상세한 내용은 추후 다시 요약하여 추가하겠습니다.

  • Webclient Thread Pool 설정 해보기 :
  • virtualthread 사용 :
  • virtualthread 미사용 :

다만, 이런 저런 설정을 바꾸었는데 잘 안되신다면 아래의 방법을 시도해보시는건 어떨까요? 혹시라도 변경해서 잘 되신다면 댓글 부탁드립니다.

# 변경 전
WebClient webClient = WebClient.create();
String response = webClient .post()
                        .uri("/api/url/")
                        .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)
                        .retrieve()
                        .bodyToMono(String.class)
                        .block()
return response;

# 변경 후
WebClient webClient = WebClient.create();
ExecutorService virtualThreadExecutor = Executors.newVirtualThreadPerTaskExecutor(); // virtualthread

try {
        String response = CompletableFuture.supplyAsync(() ->
                webClient .post()
                        .uri("/api/url/")
                        .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)
                        .retrieve()
                        .bodyToMono(String.class)
                        .block(Duration.ofSeconds(59))
        , virtualThreadExecutor).get(60, TimeUnit.SECONDS); // 60초 동안 결과를 기다림
        return response;
} catch (InterruptedException | ExecutionException | TimeoutException e) {
        // 예외 처리
        e.printStackTrace();
        return null; // 또는 적절한 에러 처리
}

위 방식으로 해결이 안되신다면 아래의 트러블 슈팅 내용을 참고해보세요!

  • https://px201226.github.io/socket_internal/
  • https://velog.io/@youngerjesus/Connection-Reset-by-Peer-%EB%AC%B8%EC%A0%9C-%ED%95%B4%EA%B2%B0
1
Subscribe to my newsletter

Read articles from Unknown directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Unknown
Unknown