thread per request
api 서버로 들어온 요청을 처리하는 여러 방식이 있다.
'thread per request'도 그중 하나이다.
이름 그대로 요청 하나마다 하나의 스레드가 담당하여 처리할 수 있도록 하는 것이다.
이때 서버에 들어오는 요청마다 스레드를 새롭게 만들어서 처리하고 요청에 대한 처리를 마친 스레드는 사라지는 식으로 동작한다면 어떻게 될까?
스레드 생성에는 오랜 시간이 소요되기 때문에 요청에 대한 처리가 증가하게 될 것이다.
또한 처리 속도보다 빠르게 요청이 늘어나게 되면 스레드는 계속해서 생성되고 이로 인해
- 컨텍스트 스위칭은 더 자주 발생하게 되며 CPU 오버헤드 증가로 CPU time이 낭비되고, 어느 순간 서버 전체가 응답 불가능한 장애 상태로 번질 수 있다.
- 스레드마다 점유하는 메모리가 있기 때문에 스레드 수 증가에 따라 메모리가 점점 고갈될 것이다.
Thread per request model
미리 제한된 개수만큼 스레드를 생성해 놓는다. (스레드풀)
요청들은 스레드풀에서 내부적으로 관리하는 큐에서 순차적으로 대기하면서 스레드풀에 있는 스레드 중에 일이 없는 스레드를 할당받아 요청이 처리된다.
요청을 처리한 스레드는 버려지는 것이 아니라 다시 스레드풀로 돌아와서 다음 요청을 대기한다.
이렇게 스레드풀에 미리 스레드를 여러 개 만들어놓고 재사용하면서 스레드 생성 시간을 절약하고 그만큼 빠르게 요청을 처리할 수 있다.
또한 스레드풀 설정을 통해 제한된 개수만큼만 스레드가 생성되도록 하여 스레드가 무제한으로 생성되는 것을 방지할 수 있게 된다.
Thread pool, 언제 사용할까?
여러 작업을 동시에 처리할 때
- thread per request 모델
- task를 subtask로 나누어 동시 처리
ex) 모든 선수들의 주급 합산을 구한다고 할 때 선수가 20명이면 1~10/11~20번 선수의 합산을 병렬적으로 하고 그 뒤에 최종 합산을 하는 방식으로 계산할 수 있을 것이다. - 순서 상관없이 동시 처리가 가능한 task 처리
스레드풀 생성 시 고려 사항
몇 개의 스레드를 만들어야 할까?
CPU 코어 개수와 task의 성향에 따라 다르다.
만약 CPU를 많이 잡아먹는 CPU-bound task(영상 편집, 빅데이터 처리 등)이면 코어 개수 혹은 코어 개수보다 몇 개 더 많은 정도로 유지하는 것이 좋다.
I/O-bound task라면 CPU-bound에 비해서 많게 설정한다. 코어 개수의 1.5~N 배까지 테스트해 보면서 알맞게 찾아나가야 한다.
스레드풀에서 실행될 task 개수에 제한이 없는 상황
만약 스레드풀에 있는 모든 스레드가 요청을 처리하고 있는 상황에서 요청 처리 속도보다 요청이 더 빠른 속도로 들어와 큐에 요청이 무한정 쌓이게 된다면 메모리가 고갈될 수 있는 위험성이 있다.
스레드 풀에 할당된 모든 스레드가 요청을 처리하고 있는 상황에서, 추가적인 요청이 많이 들어온다면 WAS 내에서 해당 요청들을 순차적으로 관리하는 대기큐가 필요하다.
해당 큐가 무한정 커진다면 서버가 감당할 수 있는 메모리 임계치를 넘어 서버가 죽어버리는 현상이 발생할 수 있을 것이다.
스레드풀의 큐 사이즈에 제한을 두고 제한을 넘어가는 요청에 대해서는 정상적인 처리를 해주지 못하더라도 전체 시스템의 장애로 이어지지 않도록 해주어야 한다.
특정 큐의 사이즈가 넘어가면 요청을 거절하도록 서버를 설정
WAS의 최대 스레드 수 설정
너무 낮게 설정하면?
- 동시 요청이 많을 때, 서버 리소스는 여유로운 반면 클라이언트는 금방 응답 지연 상황이 된다.
너무 높게 설정하면?
- 동시 요청이 많을 때, CPU/메모리 리소스의 임계점을 초과하여 서버가 다운될 수 있다.
기본적으로 aws를 사용한다면 장애 발생 시에는 우선 서버를 늘려 피해를 막고, 적절한 조치를 취해야 할 것이다.
체크 필요 사항
실제 대량 요청이 들어왔을 때 최대 스레드 수 설정에 따른 리소스 사용량(ex. CPU 사용량)을 확인하여 적절하게 설정되었는지 확인이 필요하다.
동시 요청이 최대 스레드 수 이상으로 들어와 응답 대기가 발생하는 상황에서 CPU 사용량이 낮다면 굳이 서버 인스턴스를 늘리는 것이 아니라 기존 서버의 최대 스레드 수 설정만 잘해주더라도 충분히 더 많은 요청을 응답해 줄 수 있는 상황일 것이다.
적정 값은 어떻게 찾을 수 있을까?
애플리케이션 로직의 복잡도 / CPU / 메모리 / IO 리소스 상황에 따라 모두 다르다.
성능 테스트
- 최대한 실제 서비스와 유사하게 성능 테스트 시도
- 아파치 ab, 제이미터, nGrinder
참고
스프링 부트 내장 톰캣의 기본 최대 스레드 수(스레드풀 사이즈)는 200개이다. (조정 가능)
'소프트웨어 개발' 카테고리의 다른 글
웹 브라우저에 URL을 입력하면 어떤 일이 일어날까? (0) | 2024.02.16 |
---|---|
'DB 커넥션풀'에 대해 알아보자 (0) | 2024.02.15 |
'NoSQL'에 대해 알아보자 (0) | 2024.02.12 |
'파티셔닝, 샤딩, 레플리케이션'에 대해 알아보자 (0) | 2024.02.11 |
'DB 인덱스'에 대해 알아보자 (1) | 2024.02.10 |