프로세스와 스레드의 개념
프로세스는 쉽게 말해, 우리가 작업 관리자를 열었을 때 보이는 프로그램 하나하나를 의미한다. 프로세스는 운영체제가 관리하는 하나의 독립적인 실행 단위로, 고유한 메모리 공간을 가지며 CPU, 메모리, 파일 핸들 등의 자원을 할당받아 독립적으로 실행된다. 멀티코어 CPU 환경에서는 여러 프로세스가 동시에 실행될 수 있어, 여러 작업을 병렬로 처리하는 것이 가능하다. 이는 멀티태스킹 환경에서 중요한 역할을 한다.
스레드는 한 프로세스 내에서 실행되는 가벼운 실행 단위다. 프로세스는 생성 및 관리 비용이 높은 반면, 스레드는 상대적으로 비용이 낮다. 스레드는 같은 프로세스 내에서 메모리와 자원을 공유하여 효율적인 실행이 가능하다. 예를 들어, 웹 브라우저의 각 탭이 별도의 스레드로 실행되며, 동시에 여러 작업을 처리할 수 있다.
스레드의 효율성과 한계
스레드의 비용이 낮기 때문에 많은 스레드를 생성하면 좋지 않을까 생각할 수 있다. 하지만 스레드가 많아질수록 컨텍스트 스위칭 비용이 증가하여 오히려 성능이 저하될 수 있다. 따라서 스레드의 적절한 개수를 찾는 것이 중요하다.
스프링 프레임워크에서는 기본적으로 쓰레드 풀을 사용하여 스레드의 생성과 관리를 효율적으로 처리한다. 기본 설정에서는 대개 몇십 개 정도의 스레드를 생성할 수 있지만, 무작정 많은 스레드를 생성하는 것은 바람직하지 않다.
CPU Bound와 IO Bound
서버의 작업이 IO Bound인지 CPU Bound인지에 따라 적절한 스레드 개수가 달라진다.
- IO Bound 작업은 디스크나 네트워크 I/O처럼 CPU 외의 자원을 많이 사용하는 작업을 말한다. 이 경우, 스레드가 많을수록 대기 시간을 줄일 수 있어 효율적이다. 예를 들어, 웹 서버나 스프링 서버는 IO Bound 작업의 대표적인 예다. 하지만 최적의 스레드 개수를 찾기 위해서는 실제 성능 테스트를 통해 조정하는 것이 좋다.
- CPU Bound 작업은 주로 CPU를 많이 사용하는 작업이다. 이 경우, 일반적으로 CPU 코어 수 + 1 개의 스레드를 사용하는 것이 적당하다. 이는 CPU의 효율적인 사용을 보장하면서 컨텍스트 스위칭 비용을 최소화하기 위함이다. 예를 들어, 영상 처리나 과학 계산 프로그램이 CPU Bound 작업의 대표적인 예다.
프로세스의 적절한 개수
프로세스의 개수는 시스템의 리소스와 애플리케이션의 요구사항에 따라 달라진다. 일반적으로 CPU 코어 수와 메모리 크기가 결정적인 요소다.
- CPU 코어 수와 프로세스 개수: 멀티코어 시스템에서는 각 코어가 하나의 프로세스를 효율적으로 처리할 수 있다. 따라서 CPU 코어 수와 동일하거나 약간 많은 프로세스 개수를 사용하는 것이 일반적이다.
- 메모리 제한: 각 프로세스는 독립적인 메모리 공간을 사용하므로, 메모리 용량도 중요한 고려사항이다. 너무 많은 프로세스를 생성하면 메모리 부족 문제가 발생할 수 있다.
결론적으로, 프로세스의 적절한 개수는 시스템의 CPU 코어 수와 메모리 용량에 따라 조정해야 한다. 일반적으로 CPU 코어 수에 1~2개의 프로세스를 추가하는 것이 좋은 전략이다.
스레드 간 통신
스레드는 같은 프로세스 내에서 실행되므로, 메모리와 자원을 공유할 수 있다. 이를 통해 스레드 간 통신이 매우 효율적으로 이루어진다.
- 공유 메모리: 스레드들은 같은 프로세스 내의 메모리를 공유하기 때문에, 변수를 통해 데이터를 주고받을 수 있다.
- 락과 동기화: 동시에 접근하는 데이터의 일관성을 유지하기 위해 락, 세마포어 등의 동기화 기법을 사용한다.
프로세스 간 통신 (IPC)
프로세스 간 통신은 서로 독립된 메모리 공간을 사용하기 때문에, 별도의 IPC(Inter-Process Communication) 기법이 필요하다. 주요 IPC 기법은 다음과 같다.
1) 파이프 (Pipe)
- 설명: 한 프로세스가 데이터를 쓰면 다른 프로세스가 읽을 수 있는 일방향 통신 채널이다.
- 특징: 간단하고 빠르지만, 단방향 통신만 가능하다.
2) 소켓 (Socket)
- 설명: 네트워크를 통해 프로세스 간에 데이터를 주고받는 방법이다.
- 특징: 로컬 및 원격 프로세스 간의 양방향 통신이 가능하다.
3) 메시지 큐 (Message Queue)
- 설명: 프로세스 간에 메시지를 보내고 받을 수 있는 큐를 사용한다.
- 특징: 데이터의 순서를 보장하고, 동기화 문제가 적다.
4) 공유 메모리 (Shared Memory)
- 설명: 두 프로세스가 같은 메모리 영역을 공유하여 데이터를 주고받는다.
- 특징: 매우 빠르지만, 동기화 문제를 처리해야 한다.
5) 신호 (Signal)
- 설명: 프로세스에 특정 이벤트가 발생했음을 알리는 신호를 보낸다.
- 특징: 단순한 이벤트 알림에 적합하다.
결론적으로, 프로세스와 스레드의 적절한 개수를 설정하고, 각각의 통신 방법을 이해하는 것은 시스템 성능 최적화와 안정성 확보에 매우 중요하다. 각 기법의 특성을 잘 이해하고, 상황에 맞게 적용하는 것이 중요하다.