문제 상황

간혹 아래와 같이 서버에서 의 thread가 미친듯이 생기는 경우가 있다. 2024-03-13 17:57경에 Total Thread의 max값이 2000을 돌파한다.

2024-03-13 17:57경 Total Thread max 2000 돌파

문제 원인 (추정)

서버에서 엘리베이터 호출을 담당하는데, 하나의 로비에 여러 대의 엘리베이터가 있는 경우 이를 동시에 비동기로 처리하기 위해 Thread 객체를 직접 생성하여 여러 대의 엘리베이터를 호출하고 있다.

문제는 Thread 객체를 직접 생성하면 스레드가 무한정 생긴다는 점이다.

추가로 엘리베이터 콜이 지연이 자주 일어나다 보니 톰캣 스레드로 자주 블로킹되어 점유되는 현상이 자주 있다.

개선 방안

여러 개의 엘레베이터를 부르는 경우 Thread를 통해 스레드를 생성하는 게 아닌 코루틴을 사용하여 엘리베이터를 호출하려고 한다.

엘레베이터 호출 API에서 엘리베이터 호출하는 부분을 무조건 비동기로 처리하려고 한다. 이유는 엘리베이터 호출이 지연되는 경우 해당 API가 점유하는 톰캣 스레드가 무한정 대기를 한다. 해당 API는 앱을 사용하는 입주민이 동기적으로 결과를 전달받아야 하는 이유가 없는 API이므로 비동기로 처리하기로 했다.

문제의 그 코드는 다음과 같이 생겼다.

Thread { nettyService.lobbyCall(...) }.start()

즉 엘레베이터를 부를 경우 Thread를 무한정 생성하게 된다. 최소한 스레드 풀을 사용해야 하지만 우리는 코루틴을 사용가능 하므로 다음과 같이 작성했다.

CoroutineScope(Dispatchers.IO).launch { nettyService.lobbyCall(...) }

모니터링 및 결과

24.03.18(월) ~ 24.03.22(금)

24.03.18(월)에 배포 후 추이를 지켜본 결과 24.03.22(금)까지 스레드가 max thread count가 1000 이상 넘어가는 경우는 없었다. 아무리 많아도 800개는 넘지 않았다.

특이한 건 Active Request 개수랑 thread의 max 수치와 연관이 있을 거로 예상했는데 그렇지 않아서 의문이 있다.

스레드를 생성하는 로직에서 코루틴 Dispatchers.IO를 사용하게 변경만 해도 max thread 개수가 확 줄어들었으니, 목표는 달성했다고 볼 수 있겠으나 좀 더 시간을 두고 확인해야 할 것 같다.