DataBufferLimitException
Spring Webflux의 WebClient를 사용하던 중 특정 api를 호출하여 응답받는 경우 아래와 같은 예외가 발생했다.
org.springframework.core.io.buffer.DataBufferLimitException: Exceeded limit on max bytes to buffer : 262144
원인은?
WebClient 설정에는 애플리케이션의 메모리 이슈를 방지할 수 있도록 코덱(codec)의 메모리 버퍼 사이즈 제한 값을 갖고 있다. 이 값은 기본적으로 256KB로 설정되어 있는데, 이 값을 넘어가는 경우 DataBufferLimitException 예외가 발생한다.
해결 방법
@Bean
fun webClient(): WebClient {
val strategies = ExchangeStrategies.builder()
.codecs { codecs: ClientCodecConfigurer ->
codecs.defaultCodecs().maxInMemorySize(64 * 1024 * 1024)
}
.build()
return WebClient.builder()
.exchangeStrategies(strategies)
.build()
}
DataBufferLimitException 예외가 발생하지 않도록 WebClient를 설정할 때 코덱(codec)의 메모리 버퍼 사이즈 제한 값을 maxInMemorySize 메서드의 파라미터로 넣어주면 된다.
만약 사이즈 제한을 두고싶지 않은 경우 메서드 파라미터로 -1을 전달하면 된다.
클라이언트 사이드
참고로 해당 설정의 코덱은 client side의 코덱이다.
public interface ClientCodecConfigurer extends CodecConfigurer {
/**
* {@inheritDoc}
* <p>On the client side, built-in default also include customizations related
* to multipart readers and writers, as well as the decoder for SSE.
*/
@Override
ClientDefaultCodecs defaultCodecs();
}
서버 사이드
만약 서버사이드쪽 버퍼 사이즈를 변경하고 싶다면 WebFluxConfigurer 인터페이스를 사용하여 구성이 가능하다.
@Configuration
class WebConfig : WebFluxConfigurer {
override fun configureHttpMessageCodecs(configurer: ServerCodecConfigurer) {
configurer.defaultCodecs().maxInMemorySize(10*1024*1024)
}
}
WebClient Timeout 관련
추가적으로 WebClient의 타임 아웃 관련 설정도 알아보자. WebClient의 타임아웃을 설정하는 쉬운 방법은 기본 http 클라이언트를 사용하여 전역적으로 설정하는 것이다. 기본적으로 Reactor Netty가 사용된다.
Response Timeout
요청을 보낸 후 응답을 받기까지 기다리는 시간 제한이다. responseTimeout() 메서드를 통해 설정 가능하다.
val httpClient = HttpClient.create()
.responseTimeout(Duration.ofMillis(5000))
return WebClient.builder()
.clientConnector(ReactorClientHttpConnector(httpClient))
.build()
Connection Timeout
커넥션 타임아웃은 클라이언트와 서버간의 연결이 이루어져야하는 시간 제한이다. option() 메서드를 통해 다양한 옵션 키값들을 설정할 수 있다. 커넥션이 이루어지지 않거나 끊어지면 ConnectTimeoutException 예외가 발생한다.
val client = HttpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10000);
val client = HttpClient.create()
.option(ChannelOption.SO_KEEPALIVE, true)
.option(EpollChannelOption.TCP_KEEPIDLE, 300)
.option(EpollChannelOption.TCP_KEEPINTVL, 60)
.option(EpollChannelOption.TCP_KEEPCNT, 8);
Read and Write Timeout
read timeout은 특정 시간 내에 데이터를 읽지 못햇을 때, write timeout은 특정 시간에 쓰기 작업을 완료할 수 없을 때 발생한다.
val httpClient = HttpClient.create()
.doOnConnected { conn: Connection ->
conn.addHandlerLast(ReadTimeoutHandler(5000, TimeUnit.MILLISECONDS))
.addHandlerLast(WriteTimeoutHandler(5000, TimeUnit.MILLISECONDS))
}
그 외
이 외에도 SSL/TLS timeout, Proxy timeout, Request level의 timeout 설정 또한 가능하다.
참고
'spring' 카테고리의 다른 글
[spring data mongo] Query를 Type-safe 하게 작성하기 (작성 중) (0) | 2024.11.19 |
---|---|
TestExecutionListener를 이용한 테스트 격리 방법 (1) | 2024.11.05 |
Spring Async (0) | 2024.08.02 |
Spring Webclient (0) | 2024.08.02 |
Spring AOP (0) | 2024.08.02 |