WebFlux를 선택한 이유
고성능 API를 위해 WebFlux를 선택한 이유
Spring MVC
- Thread Per Request Model
- Thread 개수 == 200(SpringBoot AutoConfig default value)
- Thread에서 REST API 호출 시 응답을 받기까지 Waiting 상태가 되며 blocking
- 200개의 Thread가 얼마 되지 않는 CPU Core를 점유하기 위해서 Thread 경합하는 현상 발생
- 대부분의 API 개발자가 사용하는 Machine Core 개수는 2,4,8 정도
Spring WebFlux
- EventLoop Model
- 사용자들의 요청이나 애플리케이션 내부에서 처리해야하는 작업들은 모두 Event라는 단위로 관리
- Event Queue에 적재되어 순서대로 처리되는 구조
- EventLoop
- Event로 처리하는 Thread Pool
- Event Queue에서 Event를 뽑아서 하나씩 처리
- 리액터 라이브러리와 Netty를 기반으로 동작
- Netty는 Tomcat과 달리 Thread Pool의 Thread 개수가 Machine Core 개수의 두배
- Spring MVC처럼 Thread가 Block 되어 I/O가 끝날 때까지 Waiting 하는 대신 I/O가 시작되기 전 작업도 Event I/O가 종료되면 처리할 작업도 Event로 만들어져 Queue에 들어감
- NIO를 이용하여 I/O 작업 처리를 하기 때문에 Thread 상태가 Block 되지 않음
- Thread Per Request Model 방식 보다 Context Switch 오버헤드가 줄고 Thread 숫자도 작기 때문에 Core를 차지하기 위한 경합도 줄어듬
- 높은 처리량이 가능한 이유
- EventLoop 사용과 Non-blocking I/O 사용
- Non-blocking I/O 대신 Blocking I/O 를 사용한다면?
- 전반적인 성능 하락 발생
- 상대적으로 적은 Thread Pool을 유지하기에 EventLoop가 Event Queue에 있는 Event를 빨리 처리 할 수 없음
- Runnable 상태의 Thread들이 CPU 점유
나의 WebFlux가 느린 이유
테스트 시나리오 아키텍처
- 중간에 있는 API 서버가 성능 부하 클라이언트의 부하를 받고 Redis에서 데이터를 가지고 와서 응답하는 시나리오
비교대상
- Spring MVC 애플리케이션
- Spring WebFlux 애플리케이션
성능 측정 결과
- Spring MVC: 3,775 tps
- Spring WebFlux
- 1차: 706 tps
- 2차: 693 tps
- 3차: 4,453 tps
- 4차: 5,977 tps
성능 개선 사항
- 2차: LogBack의 AsyncAppender 적용
- 3차: log() 제거 및 RollingFileAppender로 변경
- 4차: map(), flatMap() 수정
문제 및 개선
- 1차: log() 메서드
- 2차: AsyncAppender 사용
- 3차: log() 메서드 제거
- 4차: flatMap, map 리팩토링
다른 성능 개선 사항
- BlockHound
- Lettuce 설정
- Avoiding Reactor Meltdown(from InfoQ)
컨퍼런스 영상
'dev > 기타' 카테고리의 다른 글
| Angular Git Commit Message Convention (0) | 2022.06.13 |
|---|---|
| REST 리소스 명명 가이드 (0) | 2022.06.06 |
| M1 Macbook 윈도우 설치(UTM) (0) | 2022.04.11 |
| JUnit 5 (0) | 2020.11.22 |
| [디자인 패턴] 스트래티지 패턴 (0) | 2020.04.30 |