Springboot Webflux with Blockhound
안녕하세요. Kevin 입니다.
스프링 Webflux를 통해 리액티브 기반의 비동기 / 논블록킹 서비스를 개발할 수 있습니다. 점점 많은 곳에서 Webflux를 도입하고 있는데요. 동일한 Rest API를 MVC와 Webflux를 비교했을 때 Webflux의 처리량이 약 3배 정도 좋았습니다. 단일 건에 대한 응답은 조금 느릴 수 밖에 없는데요. 부하가 있는 서비스라면 Webflux를 도입을 고려해보시는 것도 좋은 것 같습니다.
Webflux로 개발을 하다 보면 블록킹이 발생 여부에 대해 인지하기 어려울 때가 있습니다. 그럴때 사용할 수 있는 Blockhound 에 대해 소개해 드립니다.
Blockhound는 Java agent to detect blocking calls from non-blocking threads 라 소개하고 있습니다. 테스트 프레임워크와 통합되어 쉽게? 사용 할 수 있는데요. 저는 조금 힘들게… 설정에 삽질을…
먼저, 환경구성은 java16, SpringBoot2.5.0, r2dbc, Gradle7.0.2 으로 구성하였습니다. java13 이상의 경우 JVM 옵션 AllowRedefinitionToAddDeleteMethods 가 필요한데요 이건 Known 이슈로 아래 참고자료에서 확인 할 수 있습니다.
// build.gradletasks.withType(Test).all {
if (JavaVersion.current() >= JavaVersion.VERSION_13) {
jvmArgs += [
"-XX:+AllowRedefinitionToAddDeleteMethods"
]
}
}
그리고 Junit 테스트에서 필요한 라이브러리를 추가 합니다.
// build.gradletestImplementation 'io.projectreactor.tools:blockhound-junit-platform:1.0.6.RELEASE'
testImplementation 'org.junit.platform:junit-platform-launcher:1.8.0-M1'
testImplementation 'com.google.auto.service:auto-service:1.0'
이제 Custom integrations를 추가 하여 필요한 옵션들을 추가 합니다.
@AutoService(BlockHoundIntegration.class)
public class CustomBlockHoundIntegration implements BlockHoundIntegration {
@Override
public void applyTo(BlockHound.Builder builder) {
builder
// r2dbc initScript FilterInputStream 처리 시 RandomAccessFile.readBytes blocking 허용
.allowBlockingCallsInside(FilterInputStream.class.getName(), "read")
// LocaleContextMessage ResourceBundle 처리 시 RandomAccessFile.readBytes 허용
.allowBlockingCallsInside(ResourceBundle.class.getName(), "getBundle");
}
}
저는 spring2.5.0에 추가 된 spring.sql.init 을 사용(r2dbc 지원)하여 schema 를 생성합니다. schema 파일을 읽을 때 RandomAccessFile.readBytes 를 이용하는데 해당 부분은 블록킹 코드지만 구동 시에만 발생하는 블록킹이므로 허용 처리 하였습니다. 그리고 i18n 사용 시 Message를 가져오는 부분도 블록킹 허용 하였습니다.
그리고 추가로 Lettuce를 사용하는 경우 RedisClient.connect에서 블록킹이 발생하는데 해당 부분은 참고자료의 내용 처럼 EagerInitialization를 true로 처리하여 해결할 수 있습니다.
lettuceConnectionFactory.setEagerInitialization(true);
설정이 완료 되었다면 테스트를 실행하여 블록킹 발생하는 곳을 개선 또는 허용하여 Webflux를 조금 더 Webflux 스럽게? 구현 할 수 있습니다.
감사합니다.