WebFlux 에서 파일 업로드를 사용하고 계신가요?
안녕하세요. 네이버 파이낸셜에서 금융 서비스를 만들고 있는 윤현준입니다. 최근 WebFlux 에 파일 업로드 기능을 추가하며 겪었던 이슈를 공유하려고 합니다.
3줄 요약
- 특별한 설정 없이 WebFlux 로 파일을 업로드하는 경우 256kb를 초과하는 파일은 로컬 임시 폴더에 저장되고 자동 삭제 기능이 없기 때문에 디스크의 사용량이 점점 늘어난다
- 로컬에 저장하지 않고 않고 메모리에서 처리하기 원하는 경우 SpringBoot 2.6 미만인 경우
spring.codec.max-in-memory-size
을, 이상일 때spring.webflux.multipart.max-in-memory-size
을 설정한다 - 추후 Spring 6.0.0 버전 이상을 사용하게 되면 자동 삭제 기능이 추가되어 신경 쓰지 않아도 된다
WebFlux 를 적용한 서버에 파일 업로드 API 를 추가했습니다. 운영에 배포하고 며칠 뒤 디스크 사용량이 위험하다는 알림이 울리기 시작합니다. 스토리지 용량을 확인해 보니 배포 후 디스크 사용량이 급격히 늘며 컨테이너의 생명을 위협하는 모습이 보입니다. 😳
무슨 일이지? 서버에 접속해 root 부터 디렉터리 별 용량을 확인해 봅니다.
du -h . -d 1 // 현재 디렉토리 용량 확인
사용량이 많은 경로를 찾아보니 Spring 에서 생성한 multipart 임시 저장소(/tmp/spring-multipart)에 업로드 된 임시 파일들이 쌓여가고 있었습니다.
PartGenerator#InMemoryState#body 일정 크기(default: 256kb) 를 넘어가면 로컬 저장소에 파일로 저장합니다
이전에 사용했던 Spring MVC 는 업로드한 파일을 자동으로 삭제하는 기능(MultipartResolver#cleanupMultipart)을 제공해 주었고 WebFlux 도 동일할 것이라고 생각했습니다. 코드를 분석해 보니 업로드 된 임시파일을 자동으로 삭제하는 기능을 제공하지 않았습니다. 😭
업로드 파일을 남기지 않으려면 주기적으로 파일을 지우거나 버퍼를 사용해 임시 파일로 쓰지 않도록 설정을 변경해야 할 것 같습니다. 서비스에 업로드하는 파일의 사이즈가 크지 않은 점을 고려해 후자의 방법을 적용하고 모니터링 해보니 스토리지 사용량이 늘지 않았습니다. (spring.codec.max-in-memory-size
값을 충분하게 설정해 일정 크기 이하의 파일들은 더 이상 디스크에 쓰지 않도록 설정합니다)
문제없이 잘 지내던 와중 SpringBoot 의 버전을 올려 배포하게 됩니다. (2.4.4 -> 2.6.4) 며칠 후 이전과 동일한 알람이 울리기 시작하여 컨테이너의 임시 저장소를 확인해 보니 업로드 된 파일들이 다시 쌓이기 시작합니다.
무슨 일이… 디버깅 해보자 설정했던 max-in-memory-size 값이 기본값으로 적용되어 있었습니다. 조금 더 따라가보니 SpringBoot 2.6 버전부터 추가된 spring.webflux.multipart.max-in-memory-size(default: 256kb) 프로퍼티가 서버가 기동할 때 기존 설정값(spring.codec.max-in-memory-size) 을 덮어쓰고 있었습니다. 😨 새로운 설정값으로 적용하니 정상적으로 동작하네요!
WebFlux 로 파일 업로드 기능을 사용하실 때 이 부분을 조심해야 하며 로컬 저장소에 쓰지 않고 메모리로 처리하기 원하시는 경우 SpringBoot 2.6 미만에서 spring.codec.max-in-memory-size
를, 이상에서 spring.webflux.multipart.max-in-memory-size
설정값을 사용하시면 될 것 같습니다.
관련 문서를 찾아보니 Spring 에서 자동으로 삭제하는 기능을 제공하려고 준비하는 것 같으며 Spring 6.0.0 버전부터 사용이 가능할 것 같습니다.