DB나 API 서버에서 클라이언트 요청을 처리할 때는 보통 쓰레드나 프로세스를 활용하게 된다.
요청마다 새로운 쓰레드를 만들거나, 아예 프로세스를 생성해서 처리할 수도 있고,
혹은 하나의 쓰레드를 여러 작업이 나눠서 사용하는 구조도 있다.
요청 단위로 리소스를 할당하는 방식과 작업 단위로 재사용하는 방식은 동시성, 성능, 안정성 측면에서 각기 다른 장단점을 가지게 된다.
이번 포스팅에서는 각 방식의 메커니즘과 장단점을 비교해보자.
프로세스란
디스크에 저장되어있는 프로그램을 실행하여 메모리 위에 올려진 것을 프로세스라고 한다.
예시
프로그램: chrome.exe
프로세스 : 메모리에 올라와 실행중인 chrome
프로세스 2개: chrome을 두 개 띄움
쓰레드란
프로세스 내에서 실행되는 작업 단위를 쓰레드라고 한다.
한 프로세스 내에서 여러 쓰레드를 가질 수 있다.
크롬 내에서도 여러 쓰레드를 가질 수 있다.
예시
UI 쓰레드: 크롬 내에서 렌더를 담당하는 쓰레드
Network 쓰레드: HTTP 요청, 응답을 담당하는 쓰레드
Audio 쓰레드: 오디오를 담당하는 쓰레드
프로그램을 실행했을 때 흐름
디스크에 저장된 프로그램(게임, 브라우저 등)을 실행하면
운영체제가 해당 프로그램을 메모리에 적재하고 실행 상태로 만든다.
이 상태를 **프로세스**라고 한다.
프로세스는 메모리 내에서 다음과 같은 영역으로 구성된다:
- 코드(Code) 영역: 실제 실행되는 기계어 코드
- 데이터(Data) 영역: 전역 변수, static 변수 등
- 힙(Heap): 런타임 중 동적으로 할당되는 객체
- 스택(Stack): 함수 호출 정보와 지역 변수 저장
CPU는 코드 영역의 명령어를 읽어 실행하며,
이 과정에서 스택과 힙, 데이터 영역을 이용해 프로그램의 상태와 데이터를 관리한다.
운영체제는 각 프로세스에게 독립된 논리 메모리 공간을 할당해주며,
프로세스는 이 공간을 통해 다른 프로세스와 격리된 환경에서 실행된다.
하나의 프로세스는 내부에서 여러 쓰레드를 생성하여
병렬로 작업을 처리할 수 있고,
필요에 따라 새로운 프로세스를 생성(fork 등)하거나
외부 프로그램을 실행(exec 등)할 수도 있다.
프로세스 쓰레드 사용 이유
운영체제는 우리가 실행하는 모든 작업(프로세스와 쓰레드)을 스케줄링한다.
예를 들어, 내가 음악을 들으며 글을 작성한다고 하자.
음악이 재생되는 동안에도 글쓰기가 가능하고, 글을 쓴다고 음악이 멈추는 일도 없다.
이건 운영체제가 각 작업에 조금씩 CPU 사용 시간을 배분해서,
아주 빠르게 번갈아 실행하기 때문이다.
요즘 CPU는 여러 개의 코어를 가지고 있어 여러 작업을 진짜로 병렬 처리할 수 있다.
하지만 싱글 코어 CPU에서도 OS는 마치 모든 작업이 동시에 실행되는 것처럼
빠르게 전환하며(시분할 방식) 실행되기 때문에 우리는 동시에 되는 것처럼 느낀다.
결국 프로세스와 쓰레드는
운영체제가 스케줄링하는 작업 단위이며,
이들을 통해 다양한 프로그램들이 동시에 작동하는 것처럼 보이게 만드는 것이다.
프로세스와 쓰레드의 근본적인 차이
프로세스는 완전히 독립된 메모리 영역을 가지며,
쓰레드는 같은 프로세스 내에서 메모리를 공유한다.
이로 인해 프로세스는 다른 프로세스의 메모리에 접근하려면
시간과 비용이 더 들지만, 서로의 동작을 방해하기는 어렵다.
반면 쓰레드는 메모리를 공유하므로
다른 쓰레드와 데이터를 빠르게 주고받을 수 있지만,
잘못하면 서로의 동작에 간섭하거나 충돌(경쟁 상태, 데드락 등)을 일으키기 쉽다.
요청 처리에서의 프로세스와 쓰레드
DB나 API 서버에 요청이 들어왔을 때 각 요청(SQL, restAPI)에 대해 프로세스를 할당해서 처리를 할 것인지, 쓰레드를 할당해서 처리를 할 것인지 고민을 해보자.
프로세스의 경우 격리된 메모리 공간을 가지는 것이 특징이고 쓰레드의 경우 스택 영역만 분리하는 것이 특징이다.
장단점 비교
프로세스 기반 | 쓰레드 기반 | |
메모리 사용 | 높음 (각자 공간) | 낮음 (공유) |
생성 속도 | 느림 | 빠름 |
안정성 | 높음 (한 프로세스 죽어도 나머지 OK) | 낮음 (공유 메모리라 전체 영향 가능) |
병렬성 | OS가 병렬 실행 지원 | 병렬 처리에 유리 (I/O 중심) |
디버깅 | 상대적으로 쉬움 | 디버깅 어려움 (상태 공유 때문에) |
예시 | PostgreSQL, Oracle | Spring Boot, Node.js, MYSQL, MongoDB |
정리
여러 기술들은 각자 설계 방식에 따라 요청을 프로세스 혹은 쓰레드를 할당하여 처리한다.
상황에 따라 적절히 조합해서 사용하자.
관련 링크
https://linux-kernel-labs.github.io/refs/heads/master/lectures/processes.html