code

다중 스레드 환경에서 Spring Web Client를 사용하는 올바른 방법

starcafe 2023. 9. 20. 20:37
반응형

다중 스레드 환경에서 Spring Web Client를 사용하는 올바른 방법

Spring Framework 관련해서 한가지 질문이 있습니다. WebClient

애플리케이션에서 유사한 API 호출을 많이 해야 하고, 때로는 호출(Authentication Token)에서 헤더를 변경해야 합니다.따라서 다음 두 가지 옵션 중 무엇이 더 나을지에 대한 의문이 생깁니다.

  1. MyService.class로 수신되는 모든 요청에 대해 하나의 WebClient를 만들려면 다음과 같이 하십시오.private final필드, 아래 코드와 같습니다.
private final WebClient webClient = WebClient.builder()
        .baseUrl("https://another_host.com/api/get_inf")
        .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
        .defaultHeader(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE)
        .build();

여기에 또 다른 질문이 있습니다.WebClient 안전하다고요?(많은 스레드에서 서비스를 사용하기 때문에)

  1. 서비스 클래스로 들어오는 각 새 요청에 대해 새 WebClient를 만듭니다.

최대한의 성능을 제공하고 올바른 방법으로 사용하고 싶은데 방법을 모르겠습니다.WebClient그 안에서 작동하고 어떻게 사용될 것인지에 대해 생각합니다.

감사해요.

여기서 두가지 중요한 것은WebClient:

  1. HTTP 리소스(연결, 캐시 등)는 기본 라이브러리에 의해 관리되며 참조됩니다.ClientHttpConnector에 구성할 수 있습니다.WebClient
  2. WebClient불변의

이 점을 염두에 두고 동일한 것을 다시 사용하도록 노력해야 합니다.ClientHttpConnector애플리케이션 전체에 걸쳐 연결 풀을 공유할 수 있기 때문에 이는 성능에 있어 가장 중요한 것임에 틀림없습니다.이것은 당신이 모든 것을 유도해야 한다는 것을 의미합니다.WebClient같은 예에서 나온 예들WebClient.create()불러.Spring Boot를 생성하고 구성함으로써 이를 지원합니다.WebClient.Builder당신의 앱 어디에서나 주사할 수 있는 콩.

왜냐면WebClient 실을 안전하게 쓸 수 있습니다.WebClient특정 스레드에 연결된 것이 없는 반응형 환경에서 사용하도록 되어 있습니다(기존의 서블릿 애플리케이션에서는 사용할 수 없음을 의미하지는 않습니다).

요청하는 방법을 변경하려면 다음과 같은 몇 가지 방법이 있습니다.

빌드 단계에서 구성

WebClient baseClient = WebClient.create()
                                .baseUrl("https://example.org");

요청 단위로 구성합니다.

Mono<ClientResponse> response = baseClient.get()
                                          .uri("/resource")
                                          .header("token", "secret")
                                          .exchange();

기존 인스턴스에서 새 클라이언트 인스턴스 만들기

// mutate() will *copy* the builder state and create a new one out of it
WebClient authClient = baseClient.mutate()
                                 .defaultHeaders(hdrs -> {hdrs.add("token", "secret");})
                                 .build();

제 경험으로는 제어할 수 없는 서버에서 외부 API를 호출하는 경우 WebClient를 아예 사용하지 않거나 풀링 메커니즘을 끈 상태에서 사용합니다.연결 풀링으로 인한 성능 향상은 원격 호스트 등에 의해 다른 API 호출이 갑자기 종료되었을 때 한 API 호출에서 랜덤 오류를 발생시키는 (기본 reactor-netty) 라이브러리에 내장된 가정에 의해 크게 과대평가됩니다.모든 호출이 공유 작업자 스레드에서 이루어지므로 오류가 발생한 위치를 알 수 없는 경우도 있습니다.

휴지 템플릿에 대한 문서에서 앞으로 감가상각이 될 것이라고 해서 웹클라이언트를 사용하는 실수를 했습니다.나중에 생각해보면, 일반 HttpClient 또는 Apache Commons HttpClient를 사용하고 싶지만, 만약 당신이 나와 같고 WebClient로 이미 구현되어 있다면, 당신은 다음과 같이 WebClient를 만들어 풀링을 끌 수 있습니다.

private WebClient createWebClient(int timeout) {
    TcpClient tcpClient = TcpClient.newConnection();
    HttpClient httpClient = HttpClient.from(tcpClient)
        .tcpConfiguration(client -> client.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, timeout * 1000)
            .doOnConnected(conn -> conn.addHandlerLast(new ReadTimeoutHandler(timeout))));

    return WebClient.builder()
        .clientConnector(new ReactorClientHttpConnector(httpClient))
        .build();
}

*** 별도의 WebClient를 작성한다고 해서 WebClient에 별도의 연결 풀이 있는 것은 아닙니다.HttpClient.create 코드만 보면 HttpResources.get()을 호출하여 전역 리소스를 가져옵니다.수동으로 풀 설정을 제공할 수는 있지만 기본 설정에서도 발생하는 오류를 고려하면 위험을 감수할 가치가 없다고 생각합니다.

언급URL : https://stackoverflow.com/questions/49095366/right-way-to-use-spring-webclient-in-multi-thread-environment

반응형