[Spring] Netty 쓰레드 풀 조정하기
[Spring] reactor-netty 쓰레드 풀 조정하기
1. 서론
스프링 부트 버전업을 하고나서 베타 환경에 배포를 진행한 뒤 APM으로 애플리케이션 지표를 확인했다. 확인 중 쓰레드 중 Netty 관련 쓰레드 개수가 이전과는 확연하게 차이나는 것을 발견했다.


Netty 관련 쓰레드 (기존 파드)
버전업한 파드에서는 lettuce-epollEventLoop는 32개, reactor-http-epoll은 64개나 생성되었다. 왜 이런 일이 발생했는지 어떻게 기존 파드와 같이 조절하였는지 기록해보았다.
2. 원인
사실 원인은 금방 파악할 수 있었다. 쿠버네티스 환경에서 deployment에 requests, limits을 정의해주지 않았기 때문에 노드의 코어 수 또는 코어 수 X 2 만큼 쓰레드의 개수가 생성된 것이다. (X 2는 네티 내부 설정마다 다르다.) Netty의 이벤트 루프 쓰레드 개수는 서버의 코어수에 따라 생성된다는 것을 인지하고 있었다. 우리 서비스가 requests, limits를 정의하지 않고 사용하는 이유는 가장 중요한 비즈니스 서비스이기에 설령 자원이 부족한 상황이 닥치게 되면 해당 서비스가 다른 자원을 땡겨써도 무방하다고 판단했기 때문이다. 그렇다면 기존 파드는 어째서 2개, 4개를 유지했던걸까? 그 이유를 파악해봤다.
2–1. 기존 파드에서 쓰레드가 적게 생성되었던 이유
쓰레드를 생성하는 쪽을 찾아가기 위해 WebClient 부분을 먼저 살펴봤다. 우리 서비스는 WebMVC 기반으로 동작하는 애플리케이션이지만 Netty 쓰레드가 존재하는 이유는 WebClient를 사용하고 있기 때문이다. 또한 redis-client 라이브러리로 lettuce를 사용하고 있는데 lettuce는 reactor-netty 기반 클라이언트이다.
Webclient 객체를 생성할 때 reactor-netty 라이브러리에 있는 ConnectionProvider 객체를 이용해서 설정을 주입한다. reactor-netty의 코드를 clone해서 확인해보면 IO_WORKER_COUNT 라는 값이 있다.

딱히 IO_WORKER_COUNT 값을 조정하지 않으니 기본값을 사용할 것이다. 그렇다면 이 값을 어디서 쓰고 있을까? 아래 스샷을 보자.

DEFAULT_IO_WORKER_COUNT라는 값을 설정할 때 사용하게 되는데, 최소값을 보장하기 위해 Math.max를 사용하고 있다. 즉, Runtime 객체의 availableProcessors() 함수를 호출해서 현재 머신의 코어수를 가져오고 4보다 크다면 그 값을 사용한다. availableProcessors() 함수를 살펴보니 native 함수이다. native 함수이기 때문에 jshell로 확인해 볼 수 있을 것 같았다. 기존 파드에 들어가서 jshell을 치고 해당 함수를 호출해봤다.

jshell 예시 사진
위 스샷은 예시 사진이다. 기존 파드에 쳐보니 1이 나왔다. 이전 스샷의 코드에 대입해보면 Math.max(1, 4) 이었기 때문에 4개 쓰레드가 유지되었던 것이다. 왜 이런 일이 발생했을까? 정확한 원인은 파악하지 못했지만 kubernetes 버전, OS 버전, JVM의 버전 등 여러가지 문제가 원인이 되었을 것으로 파악된다.
일단 기존에 kubernetes 버전이 1.1x였고 cgroup v1을 사용하고 있었다. v1은 비교적 버그가 많았다고 얘기를 들어서 제대로된 값을 못가져오나 했다. 그러나 최근에 kubernetes 1.2x로 마이그레이션을 진행했고 이는 cgroup v2를 사용하고 있는데도 동일한 결과가 나오는 것을 보니 JVM 버전에 이슈가 있다고 판단했다.
OpenJDK: 15 and later라고 써있었지만 우리가 기존에 사용하고 있던 것이 15.0.2 버전이었다. 비교적 오래된 버전이었기에 v2와 호환이 잘 안되었다고 판단된다. JVM 버전을 올리니 예측된 결과값인 노드의 개수만큼 결과가 나왔다.
3. 해결
위 코드를 보면 System.getProperty를 볼 수 있다. 이것은 환경변수로 설정해줘야 적용되는 옵션이다. 스프링의 옵션을 주듯이 application.yaml에 기입하면 안되고 환경변수처럼 서버를 기동하는 스크립트나 명령어에
-Dreactor.netty.ioWorkerCount
이런식으로 기입해주면 쓰레드 수를 조정할 수 있다.
(application.yaml에 기입해도 안되서 한참 헤멨다;;)
4. 결론
좀 찾아보니 비슷한 이슈를 겪은 글이 있었다. 하이퍼커넥트의 기술블로그 글이다. 이 글을 읽어보니 cgroup에 대해 좀 더 이해하고 있어야 예상치 못한 현상이 발생했을 때 실마리를 좀 찾을 수 있을 것 같다. 그래서 추후에는 cgroup 관련 글을 작성해 볼 예정이다.
메타데이터
- post_id
- 8eb2a4bbdc9d
- slug
- spring-netty-쓰레드-풀-조정하기-8eb2a4bbdc9d
- url
- https://medium.com/@kindtiger95/spring-netty-%EC%93%B0%EB%A0%88%EB%93%9C-%ED%92%80-%EC%A1%B0%EC%A0%95%ED%95%98%EA%B8%B0-8eb2a4bbdc9d
- canonical_url
- https://medium.com/@kindtiger95/spring-netty-%EC%93%B0%EB%A0%88%EB%93%9C-%ED%92%80-%EC%A1%B0%EC%A0%95%ED%95%98%EA%B8%B0-8eb2a4bbdc9d
- author_url
- https://medium.com/@kindtiger95
- status
- ok
- fetched_at
- 2026-06-26 21:52:29