CPU, Thread, TomCat의 상관관계
서론
- 컴퓨팅 세계에서 CPU, 스레드, 그리고 Tomcat 서버는 웹 애플리케이션의 성능에 큰 영향을 미치는 핵심 요소다.
- 이 세 요소의 상호 작용을 이해하는 것은 애플리케이션의 효율적인 실행과 관리에 있어 필수적이다.
- 이 글에서는 이 세 요소의 상관관계와 컨텍스트 스위칭이 어떻게 성능에 영향을 미치는지 살펴볼 것이다.
본론
개념 설명
- CPU (Central Processing Unit)
- CPU는 컴퓨터의 두뇌로, 모든 명령어 실행과 데이터 처리를 담당한다.
- 현대의 CPU는 멀티코어 구조를 가지며, 이는 단일 CPU가 여러 처리 단위(코어)를 포함해 병렬 처리 능력을 향상시키는 방식이다.
- 멀티코어와 멀티프로세싱은 컴퓨터가 동시에 여러 작업을 처리할 수 있게 해주어 성능을 크게 향상시킨다.
- Thread
- 쓰레드는 프로그램 내에서 실행되는 흐름의 단위로, 프로세스 내에서 실제로 작업을 수행하는 주체이다.
- 멀티쓰레딩은 하나의 프로세스 내에서 여러 쓰레드가 동시에 작업을 수행하게 함으로써, 자원을 효율적으로 사용하고 응용 프로그램의 반응 속도를 향상시킨다.
- 그러나, 쓰레드 관리 및 동기화에 대한 고려가 필요하다.
- Tomcat
- Tomcat은 자바 애플리케이션을 실행하기 위한 웹 컨테이너 및 서버이다.
- Tomcat은 서블릿과 JSP(JavaServer Pages)를 지원하며, 웹 애플리케이션 서버로서의 역할을 한다.
- Tomcat에서 쓰레드는 클라이언트의 요청을 처리하기 위해 사용되며, Tomcat은 쓰레드 풀을 관리하여 효율적으로 요청을 처리한다.
CPU와 Thread(CPU)의 상관관계
- 쓰레드 스케줄링은 운영 체제가 쓰레드에 CPU 시간을 할당하는 과정이다.
- 멀티쓰레딩 환경에서는 여러 쓰레드가 동시에 실행되기 때문에, CPU 코어는 활성 쓰레드 사이에서 작업을 전환하며 병렬 처리를 수행한다.
- 이 과정에서 CPU의 오버헤드가 발생할 수 있으며, 이를 최소화하기 위한 최적화를 해야할 필요하다.
- 다음 그림은 CPU가 2개인 4코어 8스레드를 의미한다. 8개의 작업을 동시에 처리할 수 있음을 의미한다.

- 여기서 말하는 Thread와 톰캣에서 사용하는 Thread는 동일한거는 아니다. 여태 얘기한건 하드웨어적 Thread이다.
Tomcat과 Thread(Tomcat) 상관관계
- Tomcat은 Java 기반의 웹 애플리케이션 서버로, HTTP 요청을 처리하는 컨테이너 역할을 한다.
- Tomcat의 성능은
maxThreads
설정에 크게 의존한다. 이 설정은 Tomcat이 동시에 처리할 수 있는 최대 요청 수, 즉 스레드 수를 정의한다.
- 기본적으로 Tomcat의
maxThreads
값은 버전에 따라 다를 수 있지만, 일반적으로 200으로 설정된다.
- CPU 코어의 개수가 늘어난다고 해서 Tomcat의
maxThreads
기본 값이 자동으로 증가하는 것은 아니다. maxThreads
값을 조정하여 Tomcat의 처리 능력을 늘릴 수 있다.
- 톰캣 스레드는 동시성을 가지고 있기 때문에 하드웨어적 스레드 개수보다 더 많은 스레드를 생성하여 하드웨어적 스레드를 번갈아 가면서 사용하여 작업을 처리한다.
- 밑 사진은 N개의 톰캣 스레드가 CPU가 2개인 4코어 8스레드를 번갈아 가면서 사용함을 의미한다.

CPU 자원 관리와 Tomcat
- Tomcat의 성능은 CPU 사용률과 밀접한 관계가 있다.
- 고성능을 유지하기 위해서는 Tomcat 설정을 통해 CPU 자원이 효율적으로 사용되도록 해야 한다.
- 예를 들어, 쓰레드 풀의 크기를 조정하여 동시에 처리할 수 있는 요청의 수를 최적화할 수 있다.
- 또한, 모니터링 도구를 사용하여 Tomcat의 성능을 지속적으로 관찰하고, 필요에 따라 설정을 조정해야 한다.
- 아래는 몇가지 시뮬레이션을 진행해 봤을 때 고려사항들이다.
1개의 1v CPU 서버에서 1개의 Tomcat 인스턴스 실행 시의 고려사항
- CPU 리소스 최적화: 단일 vCPU 환경에서는 모든 애플리케이션 로직과 웹 요청 처리가 하나의 CPU 코어에 의존한다. 이 때문에, 애플리케이션의 CPU 사용률 최적화가 매우 중요하다. CPU 집약적인 작업을 최소화하고, 효율적인 코드 작성이 필수적이다.
- 스레드 풀 관리: Tomcat의
maxThreads
설정이 해당 서버의 CPU 리소스와 잘 맞도록 조정해야 한다. 단일 vCPU에서 너무 많은 스레드를 할당하면 컨텍스트 스위칭 오버헤드가 증가하므로, 적절한 스레드 수를 설정하여 리소스를 효율적으로 사용해야 한다.
- 메모리 사용 최적화: 1v CPU 서버는 통상적으로 제한된 메모리 리소스를 가지고 있다. Tomcat 및 JVM 설정을 통해 메모리 사용을 최적화하고, 가비지 컬렉션 오버헤드를 최소화하여 애플리케이션의 응답성을 유지해야 한다.
- I/O 작업 최적화: I/O 바운드 작업(예: 데이터베이스 쿼리, 파일 I/O)은 CPU 리소스 사용과 직접적으로 관련이 없을 수 있지만, 이러한 작업의 대기 시간이 애플리케이션의 전체 응답 시간에 영향을 줄 수 있다. 비동기 I/O 처리나 캐싱 전략을 적용하여 I/O 작업의 효율을 높이는 것이 좋다.
- 성능 모니터링 및 튜닝: 실시간 모니터링 도구를 사용하여 애플리케이션의 성능 지표를 지속적으로 관찰하고, 필요에 따라 Tomcat 설정이나 애플리케이션 로직을 조정해야 한다. CPU 사용률, 메모리 사용량, 응답 시간 등을 모니터링하여 성능 병목을 식별하고 해결하는 것이 중요하다.
1개의 1v CPU 서버에서 여러 개의 Tomcat 인스턴스 실행 시의 고려사항
- 리소스 제한: 단일 vCPU 서버에서 여러 Tomcat 인스턴스를 실행하는 것은 CPU 리소스를 과도하게 분할하여 각 인스턴스의 성능이 저하될 수 있다. vCPU가 하나뿐인 서버에서는 리소스의 한계로 인해 실제 성능 향상이 제한적일 수 있다.
- 컨텍스트 스위칭 오버헤드: 여러 인스턴스가 동시에 CPU 자원을 경쟁하게 되면, 운영 체제는 빈번한 컨텍스트 스위칭을 수행해야 할 수 있다. 이는 CPU의 유휴 시간을 증가시키고, 전반적인 성능을 저하시킬 수 있다.
- 구성 복잡성 증가: 여러 Tomcat 인스턴스를 관리하려면 포트 번호, 설정 파일, 로그 파일 등을 각 인스턴스별로 구분하여 관리해야 한다. 이는 관리의 복잡성을 증가시키며, 잘못된 구성으로 인한 오류 발생 가능성이 높아진다.
1개의 Nv CPU 서버에서 여러 개의 Tomcat 인스턴스 실행 시의 고려사항
- 병렬 처리 향상: N개의 vCPU를 가진 서버에서 여러 Tomcat 인스턴스를 실행하면, 병렬 처리 능력이 향상된다. 각 인스턴스가 별도의 CPU 코어를 활용할 수 있기 때문에, 전반적인 처리량과 응답 시간이 개선될 수 있다.
- 리소스 분배 전략: 서버의 리소스(CPU, 메모리, I/O)를 여러 Tomcat 인스턴스 간에 효율적으로 분배해야 한다. 리소스 사용량을 모니터링하고, 필요에 따라 인스턴스별 리소스 할당량을 조절하여 최적의 성능을 달성해야 한다.
- 로드 밸런싱: 여러 Tomcat 인스턴스를 통해 애플리케이션의 가용성을 높일 수 있다. 앞단에 로드 밸런서를 배치하여 요청을 여러 인스턴스에 균등하게 분산시키는 방식으로, 단일 실패 지점을 방지하고, 서비스의 안정성을 향상시킬 수 있다.
- 세션 관리: 여러 Tomcat 인스턴스 간의 세션을 공유하려면 추가적인 세션 관리 전략이 필요하다. 예를 들어, 스티키 세션 또는 세션 클러스터링을 통해 사용자 세션의 일관성을 유지할 수 있다.
Tomcat과 스레드와 DB 컨넥션 풀
- 웹 애플리케이션에서 네트워크와 디스크 I/O는 주로 데이터베이스와의 상호작용을 통해 발생한다.
- 데이터베이스 컨넥션 풀은 사전에 데이터베이스 연결을 여러 개 생성해 두고, 애플리케이션에서 필요할 때마다 이 연결들을 재사용하는 방식으로 관리된다.
- 컨넥션 풀의 크기, 즉 동시에 유지할 수 있는 데이터베이스 연결의 최대 개수는 애플리케이션의 동시 처리 능력과 직결된다.
- Tomcat 서버에서 스레드 수를 늘리는 것은 애플리케이션이 동시에 처리할 수 있는 요청의 수를 증가시킨다.
- 그러나, 데이터베이스 컨넥션 풀의 크기가 고정되어 있거나 충분하지 않은 경우, 동시에 처리되는 요청 중 많은 부분이 데이터베이스 I/O를 기다리는 상태에 놓이게 된다.
- 이러한 상황에서는 스레드 수를 늘려도 실제 처리량의 증가가 제한되며, 오히려 컨텍스트 스위칭과 같은 오버헤드로 인해 성능이 저하될 수 있다.
- 즉, Tomcat의 스레드 수와 데이터베이스 컨넥션 풀 사이의 균형이 중요하다.
- 스레드 수를 늘리려 할 때는 동시에 데이터베이스 컨넥션 풀의 크기도 적절히 조정하여, 모든 스레드가 데이터베이스 작업을 효율적으로 수행할 수 있도록 해야 한다.
- 또한, 데이터베이스 자체의 성능과 I/O 처리 능력도 고려해야 한다.
- 데이터베이스와의 상호작용이 애플리케이션 성능의 병목이 되는 경우, 다음과 같은 방법을 고려할 수 있다.
- 컨넥션 풀 크기 조정: 애플리케이션의 요구 사항과 데이터베이스 서버의 성능에 맞춰 컨넥션 풀의 크기를 조정한다.
- 캐싱 전략 적용: 자주 조회되는 데이터를 애플리케이션 서버나 클라이언트 측에서 캐싱하여, 데이터베이스 접근을 줄인다.
- 비동기 처리: 가능한 경우, 데이터베이스 작업을 비동기적으로 처리하여, I/O 대기 시간 동안 다른 작업을 진행한다.
CPU 부하가 있을 때 고려사항
- 코드 프로파일링 및 최적화
- 프로파일링 도구를 사용하여 성능 병목을 식별합니다. 가장 많은 CPU 시간을 소비하는 메서드나 작업을 찾아내고, 이를 최적화한다.
- 불필요한 연산 제거, 루프 최적화, 효율적인 자료구조 사용 등으로 코드의 효율성을 높인다.
- 캐싱 전략 적용
- 자주 접근하는 데이터나 계산 결과를 캐시에 저장하여 반복적인 연산이나 데이터베이스 쿼리를 줄입니다. 이는 CPU 부하를 현저히 감소시킬 수 있다.
- 동시성 및 멀티스레딩 개선
- 애플리케이션의 동시성 처리 능력을 분석하고, 필요한 경우 멀티스레딩을 통해 작업을 효율적으로 분산시킨다.
- 그러나, 스레드 관리에 대한 오버헤드가 증가할 수 있으므로 주의가 필요하다.
- 비동기 처리 사용
- 비동기 I/O 작업을 사용하여 I/O 작업이 CPU 리소스를 블로킹하지 않도록 한다.
- 네트워크 요청, 파일 시스템 작업 등을 비동기적으로 처리하여 CPU 사용률을 낮출 수 있다.
- 데이터베이스 쿼리 최적화
- 데이터베이스 쿼리의 성능을 분석하고, 쿼리 최적화를 통해 실행 시간을 단축한다.
- 인덱싱, 쿼리 리팩토링 등을 통해 데이터베이스의 부하를 줄일 수 있다.
- 서버 설정 조정
- 웹 서버나 애플리케이션 서버의 설정을 조정하여 리소스 사용을 최적화한다.
- 예를 들어, Tomcat의 경우
maxThreads
설정을 조정하여 스레드 풀의 크기를 최적화할 수 있다.
- 하드웨어 업그레이드 또는 스케일 아웃
- 모든 소프트웨어 최적화가 소진된 후에도 성능 문제가 지속되면, 하드웨어 업그레이드를 고려하거나 여러 서버에 부하를 분산하는 스케일 아웃을 고려할 수 있다.
Context Switching란?
- 스레드의 수가 CPU 코어의 수보다 많으면, 운영 체제는 컨텍스트 스위칭을 통해 여러 스레드가 CPU 시간을 공유하도록 한다.
- 컨텍스트 스위칭은 CPU가 현재 실행 중인 스레드에서 다른 스레드로 전환하는 과정이다.
- 이 과정에서 현재 스레드의 상태를 저장하고, 새로운 스레드의 상태를 불러오는 작업이 필요하다.
- 실생활 예시로, 요리사가 여러 요리를 동시에 준비하는 상황을 생각해볼 수 있다.
- 요리사는 한 번에 한 요리에만 집중할 수 있으며, 다른 요리로 전환할 때마다 현재 요리의 상태를 기억하고 새로운 요리의 상태로 마음을 전환해야 한다.
- 이는 컨텍스트 스위칭의 오버헤드와 유사하며, 시스템의 성능 저하를 가져올 수 있다.