프로세스 관리

Chooooo·2025년 2월 8일
0

리눅스 정리

목록 보기
6/10

컴퓨터의 작동 원리

CPU

CPU는 프로그램의 명령어를 해석해 산술, 논리 연산 등 모든 연산을 수행하는 컴퓨터의 두뇌. 초창기는 컴퓨터에 CPU 하나만 존재했으나 기술 발전 -> 여러 CPU가 하나의 칩에 장착된다. 여러 CPU로 된 하나의 칩을 프로세서(processor)라고 하며, 프로세서에 장착된 CPU를 코어(core)라고 함. 그리고 코어(CPU)가 여러 개면 멀티 코어 프로세서라고 한다.

레지스터

레지스터는 CPU 내부에 포함된 아주 작고 빠른 메모리. 레지스터는 CPU가 연산을 수행할 때 필요한 데이터를 임시로 저장한다.

메모리

RAM(통상 메모리라고 부름)은 프로그램 코드와 데이터를 저장하는 공간. 레지스터는 CPU 내부에 존재하는 반면, 메모리는 CPU와 물리적으로 떨어져 시스템 버스라는 통로로 연결되어 있다. 메모리는 레지스터보다 크기가 매우 크지만, 접근 속도는 훨씬 느리다. 디스크에 비해서는 크기가 매우 작고, 접근 속도가 매우 빠르다.

메모리에는 프로그램의 실행 코드와 데이터가 저장. 메모리에 저장된 데이터는 컴퓨터가 꺼지면 모두 없어짐 -> 그래서 메모리르 휘발성 메모리라고 한다.

캐시

캐시는 CPU와 메인 메모리 사이에 위치한 고속 메모리로, 자주 사용되는 데이터를 임시 저장하여 CPU의 성능을 향상시키는 중요한 역할을 한다.

저장 장치

저장 장치는 HDD(하드 디스크 드라이브), SSD(Solid State Drive), 플래시 메모리와 같은 저장소를 말한다. 흔히 디스크라고 통칭하기도 한다.

저장 장치에 저장된 데이터는 컴퓨터의 전원이 꺼져도 보존된다. 그래서 저장 장치를 비휘발성 메모리라고 한다. 저장 장치에는 운영체제, 프로그램, 일반 파일 등 컴퓨터가 꺼져도 보관해야 하는 데이터를 저장한다.
-> 저장 장치는 메모리에 비해 크기가 매우 크고, 접근 속도가 매우 느리다.

시스템 버스

시스템 버스는 컴퓨터 내부에서 데이터를 주고받는 통로이다. CPU, 메모리, 디스크 등 다양한 구성 요소가 데이터를 주고받을 때 버스를 사용한다.

주소 버스, 데이터 버스, 제어 버스 등 여러 종류가 있으며 각기 다른 역할을 수행한다.

프로그램을 작동시키면 디스크에 저장된 프로그램 실행 코드를 시스템 버스를 통해 메모리로 적재한다. 디스크에 저장된 프로그램 코드를 메모리에 복사한다고 볼 수 있다. CPU는 메모리에 적재한 프로그램 실행 코드의 명령을 순차적으로 실행한다.

CPU는 이 과정에서 메모리에 저장된 데이터를 사용한다. CPU는 버스를 통해 데이터를 메모리에서 레지스터로 읽어와 연산을 수행한다. 그리고 버스를 통해 연산 결과를 다시 메모리에 저장한다.

아까도 말했지만, CPU는 컴퓨터의 두뇌 역할 -> 모든 연산을 담당한다.
필요한 데이터는 메모리(RAM)에 저장되어 있고, CPU가 작업을 수행하려면 메모리에서 데이터를 가져와야 한다. 이 데이터는 버스라는 통로를 통해 메모리에서 CPU 내부의 레지스터로 전달된다. CPU는 레지스터에 있는 데이터로 연산을 수행한다. (레지스터는 CPU 내부에 있는 매우 빠른 임시 저장소니까.)

  • 연산이 끝나면 결과를 다시 버스를 통해 메모리에 저장한다.

프로세스란 ?

컴퓨터 시스템에서 프로세스는 메모리에서 실행 중인 프로그램을 뜻한다.
프로그램은 디스크에 저장된 실행 파일을 의미한다.

프로그램이 시스템에 설치되면 프로그램을 구성하는 여러 파일이 디스크에 저장된다. 그래서 시스템에 무거운 프로그램을 설치하거나 많은 프로그램을 설치하면 남은 디스크 용량이 줄어들게 된다.

프로세스는 실행 중인 프로그램이다. 시스템에 설치하고 실행하지 않은 프로그램은 그저 디스크에 저장된 파일일 뿐이다. 디스크의 자리만 차지하며 아무런 동작을 하지 않는다.

프로세스는 메모리에서 실행중인 프로그램이다. 왜 메모리일까 ? 디스크에 저장된 상태 그대로 프로그램을 실행할 수는 없는가 ? -> 불가능하다. CPU는 실행할 명령을 메모리로부터 읽어들이도록 설계됐다.

프로그램이 CPU에서 실행되려면 프로그램의 코드가 반드시 메모리에 적재돼야 한다. 코드가 실행되면 CPU는 실행 결과를 메모리에 저장하거나 메모리로부터 다음 실행 코드를 읽어들인다. 프로그램의 동작에 필요한 여러 정보를 메모리에 저장하거나 메모리에서 가져오는 것이다.

프로그램을 실행하기 위한 코드를 메모리에 적재하기도 하고, 프로그램이 작동하면서 사용하는 정보를 메모리에 저장하기도 한다. 프로세스는 이런 정보를 모아 관리하는 객체이다.

리눅스 주요 프로세스 관리 명령어

ps(Process Status) 명렁어

기본 형식 : ps [옵션]

ps 명령어는 현재 실행 중인 프로세스의 상태를 보여준다. 시스템에서 실행 중인 프로세스의 목록와 함께 프로세스ID, 실행 시간, 메모리 사용량, 사용자 이름 등 다양한 정보를 제공한다. 이 정보들을 활용해 시스템의 현재 상태를 모니터링하고, 문제 있는 프로세스를 식별하거나 시스템 자원 현황을 파악할 수 있음

주요 옵션으로는

  • -e : 모든 프로세스 출력
  • -f : 프로세스의 자세한 정보 출력
  • -l : 프로세스의 상세 정보 출력

ps 명령어의 출력 결과에서 각 필드가 갖는 의미

필드필드 코드의미
PID(ProcessD)pid각 프로세스를 구별하는 고유 번호
PPID(Parent Pricess IDppid해당 프로세스를 생성한 부모 프로세스의 ID
C(CPU Usage)c프로세스의 CPU 사용량
STIME(start time)stime프로세스가 시작된 시각
TTY(Terminal Type)tty프로세스가 실행되는 터미널의 종류나 번호
TIME(CPU Time)time프로세스가 실행되면서 소비한 총 CPU 시간
CMD(Command)cmd프로세스를 시작한 명령 또는 실행 파일 이름
STAT(Status)stat프로세스의 현재 상태로, R은 실행 상태, S는 대기 상태, Z는 좀비 상태를 의미
%MEM(Memory Usage)%mem전체 시스템 메모리 대비 프로세스가 사용하는 메모리 비율
VSZ(Virtual Memory Size)vsz프로세스에 할당된 전체 가상 메모리의 양
RSS(Resident Set Size)rss프로세스가 실제로 사용하는 메모리의 양

kill 명령어

기본 형식 : kill [옵션] PID
특정 프로세스를 종료하는 명령어

주요 시그널 옵션:

  • -9 : 강제 종료(SIGKILL)
  • -15 : 정상 종료 (SIGTERM, 기본값)
  • -l : 재시작(SIGHUP)

top 명령어

기본 형식 : top [옵션]
시스템의 프로세스를 실시간으로 모니터링한다. CPU 사용률, 메모리 사용량 등을 확인할 수 있다.

주요 옵션:

  • -d 초 : 화면 갱신 주기 설정
  • -p PID : 특정 프로세스만 모니터링
  • -u 사용자명 : 특정 사용자의 프로세스만 모니터링

nohup 명령어

기본 형식 : nohup 명령어 &
터미널 세션이 종료되어도 프로세스가 계속 실행되도록 한다. 백그라운드 작업에 주로 사용

jobs 명령어

현재 쉘에서 실행 중인 작업 목록을 보여준다. 백그라운드 프로세스 관리에 유용하다.

fg와 bg 명령어

각각 백그라운드 프로세스를 포그라운드로 가져오거나(fg), 포그라운드 프로세스를 백그라운드로 보내는(bg) 데 사용

프로세스 작동

프로세스의 개념만으로는 프로세스가 어떻게 작동하는지 이해하기 어렵다. 지금부터 프로세스의 생애주기를 알아보고, 운영체제 내에서 여러 프로세스가 어떻게 조화롭게 동작할 수 있는지 살펴보자.

프로세스의 생애 주기

프로세스는 생성되고 종료될 때까지 여러 상태를 거치게 된다.

				생성(Created)
                    ↓
            [메모리/자원 할당 완료]
              		↓		
   ┌──────→ 실행 대기(Ready) ←────────┐
   │               ↓                │
   │         [CPU 할당]              │
   │               ↓                │
   │         실행(Running)           │
   │           ↙         ↘          │
   │ [I/O 또는 이벤트 대기]  [실행 완료]  │
   │         ↙                 ↘    │
   │     대기(Blocked)            종료│
   │         ↓                      │
   └─── [I/O 또는 이벤트 완료] ─────────
  1. 생성(Created) : 프로세스가 처음 만들어진 상태. 프로그램이 실행되면 운영체제는 새로운 프로세스를 생성한다.

    • PCB(Process Control Block)생성
    • 메모리 공간 할당
    • 필요한 자원 할당
  2. 실행 대기(Ready) : CPU 할당받을 준비. 여러 프로세스들이 CPU 스케줄러에 의해 관리되는 실행 대기열에서 자신의 차례를 기다린다. (메모리는 할당 받았지만, CPU는 아직 못받았음)

  3. 실행(Running) : CPU를 할당받아 실제로 명령어들이 실행되는 상태. 스케줄러가 실행 대기열에서 다음에 실행할 프로세스를 선택하면 해당 프로세스는 CPU를 할당받고 실행 상태가 된다. 프로세스는 이 상태에서 :

    • 시간 할당량을 모두 사용하면 다시 Ready로
    • I/O 작업(프로세스가 외부와 데이터를 주고받는 모든 작업)이 필요하면 Blocked 상태로
    • 작업을 모두 마치면 Terminated 상태로 전환한다.
  4. 대기(Blocked) : 입출력 작업이나 다른 이벤트를 기다리는 상태 (디스크 읽기/쓰기 작업, 네트워크 통신, 사용자 입력 대기 등)

  5. 종료(Terminated) : 프로세스가 모든 작업을 마치고 종료되는 단계

    • 할당받은 자원 반환
    • PCB 제거
    • 메모리 공간 해제가 이루어진다.

상태 전이는 운영체제의 프로세스 스케줄러에 의해 관리된다.

멀티 태스킹을 위한 여러 기법

윈도우나 리눅스 같은 운영체제는 여러 프로그램을 동시에 실행할 수 있게 설계되어 있다. 한 번에 여러 일을 동시에 처리하는 것을 멀티 태스킹이라고 하는데, 멀티 태스킹은 운영체제의 역할 중 하나. 멀티 태스킹을 지원하는 데 필요한 기능과 기법을 알아보자.

아래 세 가지 핵심 요소를 이해하는 것이 중요. 이것들이 어떻게 함께 작동하여 멀티 태스킹을 가능하게 하는지.

먼저 멀티 태스킹의 기본 개념을 이해해보면, 실제로 CPU는 한 번에 하나의 프로세스만 실행할 수 있다. 하지만 우리가 여러 프로그램이 동시에 실행되는 것처럼 느끼는 것은 운영체제가 CPU 시간을 매우 빠르게 여러 프로세스에 나누어 주기 때문.

프로세스 스케줄링

프로세스 스케줄링은 전체적인 관리자 역할을 한다. 어떤 프로세스가 CPU를 사용할 차례인지, 얼마나 오래 사용할 수 있는지를 결정한다. 프로세스 스케줄링은 운영체제에서 작동하는 모든 프로세스에 적용돼야 함
-> 그래서 프로세스 스케줄러는 커널 영역에서 작동한다.

스케줄링 알고리즘

스케줄링 알고리즘은 구체적인 의사결정 방법을 제공한다. 예를 들어, 먼저 온 손님을 먼저 서비스할지(FCFS), 짧은 주문부터 처리할지(SJF), 또는 모든 테이블을 돌아가며 일정 시간씩 서비스할지(Round Robin) 결정하는 규칙과 같다.

컨텍스트 스위칭

컨텍스트 스위칭은 실제로 한 프로세스에서 다른 프로세스로 전환하는 기술적인 과정이다.
이때 CPU가 처리하던 프로세스는 실행이 끝나지 않은 상태로 중단된다. 언젠가 중단된 프로세스가 다시 CPU에서 처리할 차례가 되면(스케줄링되면) 중단된 상태를 그대로 복원하고 실행을 재개해야 매끄럽게 처리된다.
-> 이처럼 프로세스 스케줄링에 따라 처리되는 프로세스가 변경되는 일련의 과정을 컨텍스트 스위칭이라고 한다.

컨텍스트 스위칭 과정
1. 현재 프로세스 상태 저장 : 현재 실행 중인 프로세스의 모든 상태 정보를 PCB에 저장한다.

  • CPU 레지스터 값들
  • 프로그램 카운터(다음에 실행할 명령어 위치)
  • 메모리 관리 정보
  • 입출력 상태 정보 등
  1. 다음 프로세스 선택과 실행 : 스케줄러가 다음에 실행할 프로세스를 선택하고 해당 프로세스의 PCB에서 상태 정보를 불러와 CPU 레지스터에 복원한다.

스레드

프로세스와 프로세스 스케줄러를 적용함으로써 운영체제는 멀티 태스킹을 지원할 수 있었다. 하지만 프로세스의 동작 방식에서 여러 아쉬운 점이 있었음. 프로세스 간에 데이터를 교환하거나 공유하려면 IPC, 프로세스 간 통신 도구를 이용해야 한다.

그런데 IPC를 이용한 데이터 교환과 공유가 성능에 병목 현상(전체 시스템의 성능이나 용량이 하나의 구성 요소로 인해 제한을 받는 현상)을 일으킨다. 또한 컨텍스트 스위칭으로 인한 오버헤드가 커서 시스템 효율이 낮았다. -> 프로세스를 전환할 때마다 메모리 컨텍스트를 교체해야 하기 때문.

이런 문제를 해결하기 위해 스레드라는 개념이 등장.
스레드는 프로세스의 가장 작은 실행 단위로 한 프로세스에는 여러 프로세스가 존재 가능하다.
스레드 1개 -> 싱글 스레드 프로세스 여러 개 -> 멀티 스레드 프로세스

스레드 특성

메모리 공유

  • 코드 영역 : 프로그램의 실행 코드
  • 데이터 영역 : 전역 변수
  • 힙 영역 : 동적으로 할당된 메모리

독립적으로 가지는 영역

  • 스택 영역 : 지역 변수, 매개변수, 리턴값
  • 레지스터 : 스레드 실행 상태 정보

멀티 스레드 프로세스

장점

  • 응답성 향상: 하나의 스레드가 블록되어도 다른 스레드는 계속 실행될 수 있다.
  • 자원 공유: 같은 프로세스 내의 스레드들은 자원을 자연스럽게 공유할 수 있다.
  • 경제성: 프로세스를 생성하는 것보다 스레드를 생성하는 것이 시스템 자원을 덜 사용한다.
  • 확장성: 멀티프로세서 시스템에서 각 스레드를 다른 프로세서에서 병렬로 실행할 수 있다.

단점

  • 동기화 문제: 여러 스레드가 같은 자원에 동시에 접근할 때 발생할 수 있는 race condition(경쟁상태)
  • 데드락 가능성: 여러 스레드가 서로가 가진 자원을 기다리며 영원히 블록되는 상황
  • 디버깅의 어려움: 멀티스레드 프로그램은 실행 순서가 예측하기 어려워 버그를 찾기 어려움

포어그라운드 프로세스 & 백그라운드 프로세스

포어그라운드 프로세스는 터미널에서 직접 실행하고 사용자와 상호작용하는 프로세스.
백그라운드 프로세스는 사용자의 직접적인 제어없이 뒤에서 실행되는 프로세스

둘을 나누는 가장 큰 기준은 프로그램과 사용자 간 인터페이스이다. 프로그램에 따라 사용자 입력이 가능한, 보이는 곳에서 사용자와 상호작용하며 작동하는 프로세스도 있고, 사용자의 입력과 관계없이 보이지 않는 곳에서 묵묵히 일을 하는 프로세스도 있다.

하나의 쉘에서 실행할 수 있는 포어그라운드 프로세스의 수는 1개.

ping 명령어

ping 명령어는 네트워크 연결 상태를 확인하는데 사용한다.
ping은 ICMP 프로토콜로 에코 요청 패킷을 대상 호스트한테 보냄. 에코 응답을 받아 해당 호스트가 네트워크에서 접근 가능한지 확인한다.

ICMP(인터넷 제어 메시지 프로토콜)는 네트워크 장치에서 네트워크 통신 문제를 진단하는 데 사용하는 프로토콜.

  • 에코 요청(echo request) : 대상이 메시지를 받으면 응답을 달라는 요청
  • 에코 응답(echo reply) : 에코 요청을 받은 대상이 보내는 응답 메시지

실행

쉘에서 실행하는 프로그램은 기본으로 포어그라운드 프로세스로 실행된다.
-> ping 프로그램도 포어그라운드 프로세스로 실행되므로 쉘은 프로세스가 종료될 때까지 기다린다.

포어그라운드 프로세스 실행
command    # 일반적인 명령어 실행

백그라운드 프로세스 실행
command &  # 명령어 뒤에 & 붙이기

예를 들어, 긴 시간이 걸리는 압축 명령을 백그라운드로 실행하고 싶다면:
tar -czf backup.tar.gz /home/user &

프로세스 간 전환 방법

포어그라운드에서 백그라운드로 전환
1. CTRL + Z를 눌러 프로세스 일시 중지
2. bg 명령어로 백그라운드에서 실행 재개

백그라운드에서 포어그라운드로 전환
1. jobs 명령어로 백그라운드 작업 목록 확인
2. fg %작업번호 명령어로 원하는 작업을 포어그라운드로 가져오기

# vim으로 파일 편집 중
vim document.txt
# Ctrl + Z로 일시 중지
[1]+ Stopped vim document.txt

$ jobs
[1]  Stopped  vim document.txt
[2]- Running  tar -czf backup.tar.gz /home/user &
[3]+ Running  find / -name "*.log" &
# bg 명령어로 백그라운드 실행
bg
# 나중에 다시 포어그라운드로 가져오기
fg %1

jobs 명령어를 실행하면 현재 쉘에서 실행 중인 작업 목록이 표시된다.
각 작업에는 번호가 할당되어 있음

즉, fg %1은 작업 번호 1번(이 경우 vim document.txt)를 포어그라운드로 가져오라는 의미

  • 물론 가장 최근에 중지된 작업은 fg만 입력해도 포어그라운드로 가져올 수 있다.

IPC(프로세스 간 통신)

프로세스는 기본적으로 서로 독립된 메모리 공간을 가지고 있어서 직접적인 데이터 교환이 불가능하다. 이들이 협력하기 위해서는 특별한 통신 방법이 필요한데, 이것이 바로 IPC

파이프(Pipe)

가장 간단한 형태의 IPC. 한 프로세스의 출력이 다른 프로세스의 입력으로 직접 전달된다. 수도관처럼 한 방향으로만 데이터가 흐른다.
즉, 한 프로세스가 데이터를 파이프에 쓰면 다른 프로세스가 파이프에서 데이터를 읽어갈 수 있다.

ls | grep ".txt"  # ls의 출력이 grep의 입력으로 전달됨

메시지 큐(Message Queue)

메시지 큐프로세스 간 통신을 위한 중간 저장소 역할을 하는 IPC 메커니즘이다. 이는 마치 우체통이나 택배 물류센터와 같은 방식으로 작동한다. 송신 프로세스가 메시지를 큐에 넣으면, 수신 프로세스는 자신이 처리할 준비가 되었을 때 해당 메시지를 큐에서 가져와 처리할 수 있다.
메시지 큐의 특징은 메시지가 구조화된 형태를 가진다는 점. 각 메시지는 유형과 우선순위를 가질 수 있어서, 수신 프로세스는 자신이 처리해야 할 특정 유형의 메시지만 선택적으로 가져올 수 있다. 마치 우체국에서 일반 우편, 등기 우편, 긴급 우편 등을 분류하여 처리하는 것과 유사하다.
여러 프로세스가 하나의 메시지 큐를 공유할 수 있다는 점도 중요한 특징이다. 한 프로세스가 메시지 큐를 독점하지 않기 때문에, 여러 송신 프로세스가 메시지를 보내고 여러 수신 프로세스가 이를 처리할 수 있음. 이러한 특성 덕분에 메시지 큐는 복잡한 시스템에서 작업을 효율적으로 분배하고 처리하는 데 매우 유용하다.
또한, 메시지 큐는 비동기 통신을 가능하게 한다. 송신 프로세스는 메시지를 큐에 넣은 후 즉시 다른 작업을 수행할 수 있으며, 수신 프로세스는 자신의 처리 속도에 맞춰 메시지를 가져와 처리할 수 있다. 이러한 비동기 처리 방식은 시스템의 전반적인 효율성을 높이는 데 기여한다.

소켓(socket)

네트워크 통신에서 착안한 통신 방식. 같은 컴퓨터 내의 프로세스들 뿐만 아니라, 네트워크로 연결된 다른 컴퓨터의 프로세스와도 통신할 수 있다. -> 양방향 통신

소켓은 TCP(통신 제어 프로토콜)를 기반으로 하는 연결형 통신과 UDP(사용자 데이터그램 프로토콜)를 기반으로 하는 데이터그램 통신이 모두 가능하다.

소켓은 네트워크 통신의 끝점(endpoint)로, 전화기와 같은 역할을 함. 통신하고자 하는 두 프로세스는 각각 자신의 소켓을 가지고 있으며, 이 소켓들을 통해 데이터를 주고 받는다.

프로세스 A의 소켓 <-----> 네트워크 <-----> 프로세스 B의 소켓
  1. 서버 프로세스는 특정 포트 번호(전화번호와 같은)로 소켓을 열고 클라이언트의 연결 요청을 기다린다.
  2. 클라이언트 프로세스는 서버의 IP 주소와 포트 번호를 사용해 연결을 요청한다.
  3. 연결이 수립되면 양방향으로 데이터 통신이 가능하다.

소켓의 특별한 점은 같은 컴퓨터 내의 프로세스 간 통신 뿐만 아니라, 인터넷을 통해 다른 컴퓨터의 프로세스와도 통신이 가능하다는 것이다.

TCP 소켓 : 신뢰성 있는 연결 지향적 통신 제공.
UDP 소켓 : 비연결형 통신. 마치 편지처럼 각 메시지가 독립적으로 전송된다.

공유 메모리

여러 프로세스가 동일한 메모리 영역을 공유하는 방식. 이는 가장 빠른 IPC 방식인데, 동시에 여러 프로세스가 같은 메모리에 접근할 때 발생할 수 있는 문제를 방지하기 위한 동기화 메커니즘이 필요하다.

세마포어와 뮤텍스

이들은 실제로 통신 방식이라기 보다는 동기화를 위한 도구.
-> 여러 프로세스가 공유 자원에 접근할 때 발생할 수 있는 충돌을 방지하기 위한 동기화 도구. (동시성 제어를 위한 동기화 도구)

일단 결론적으로 세마포어는 지정된 개수만큼의 프로세스가 공유 자원에 접근할 수 있다.

  • 예를 들어 세마포어 값이 3이라면, 최대 3개의 프로세스가 동시에 자원을 사용할 수 있다. 4번째 프로세스가 기존 프로세스 중 하나가 자원 사용을 마치고 나갈 때까지 기다려야 한다.

뮤텍스는 정확히 하나의 프로세스만 자원에 접근할 수 있다. 다른 점은 소유권개념이다. 뮤텍스는 잠금을 획득한 바로 그 프로세스만이 잠금을 해제할 수 있다.

먼저 왜 이러한 도구들이 필요한지를 이해해야 한다.
-> 여러 프로세스가 동시에 같은 자원(ex. 공유 메모리, 파일 등)에 접근하려고 할 때 문제가 발생할 수 있기 때문.

세마포어는 정수 값을 가지는 카운터를 사용하여 동시에 자원에 접근할 수 있는 프로세스의 수를 제어. 프로세스가 자원을 사용하려고 할 때마다 카운터가 감소하고, 자원 사용을 마치면 카운터가 증가. 카운터가 0이 되면 다른 프로세스들은 카운터가 다시 증가할 때까지 대기해야 한다.

세마포어는 여러 개의 동일한 자원을 관리할 때 유용하다. 예를 들어 데이터베이스 연결 풀에서 동시에 허용할 수 있는 연결의 수를 제한하는 데 사용될 수 있다.

반면 뮤텍스는 단 하나의 프로세스만 자원에 접근할 수 있도록 하는 잠금 메커니즘이다. 프로세스가 뮤텍스를 획득하면 해당 자원을 독점적으로 사용할 수 있으며, 다른 프로세스들은 뮤텍스가 해제될 때까지 대기해야 한다. 중요한 점은 뮤텍스를 획득한 프로세스만이 그것을 해제할 수 있다는 것이다.

세마포어와 뮤텍스의 가장 큰 차이점은 접근 제어의 범위! 세마포어는 여러 프로세스의 동시 접근을 허용할 수 있지만, 뮤텍스는 항상 하나의 프로세스만 허용한다. 또한 뮤텍스는 소유권이라는 개념이 있어서, 잠금을 획득한 프로세스만이 그것을 해제할 수 있다.

일단 지금 설명한 것은 프로세스 간 세마포어와 뮤텍스.

기본적으로 세마포어, 뮤텍스는 스레드 단위로 설명하고, 스레드 단위의 동기화 메커니즘으로 설명한다. (면접)

  • 물론 프로세스 간 통신(IPC)에서도 동기화 메커니즘으로 사용될 수 있지만, 면접에서 뮤텍스와 세마포어를 설명할 때는 스레드 단위의 동기화 도구로 설명하는 것이 일반적임.

IPC 메커니즘들의 best practice

대규모 시스템에서는 보통 여러 IPC 메커니즘을 함께 사용. 각각의 장점을 활용하여 시스템의 다양한 요구사항을 충족시키기 때문이다.

메시지 큐는 마이크로서비스 아키텍처에서 특히 강점을 발휘한다. 대규모 트래픽이 발생하는 상황에서 시스템의 부하를 분산시키고 각 서비스 간의 느슨한 결합을 유지할 수 있기 때문.
예를 들어 주문 처리 시스템에서는 결제, 재고 관리, 배송 처리 등의 서비스들이 메시지 큐를 통해 비동기적으로 통신하다.

소켓은 네트워크를 통한 실시간 통신이 필요한 경우에 주로 사용됩니다. 채팅 애플리케이션, 실시간 게임 서버, 웹소켓을 사용하는 실시간 대시보드 등이 대표적인 예시이다.

공유 메모리는 대용량 데이터를 빠르게 주고받아야 하는 경우에 적합하다. 예를 들어 이미지나 비디오 처리 애플리케이션에서 여러 프로세스가 같은 데이터를 처리해야 할 때 사용된다. -> 여러 프로세스가 직접 접근할 수 있는 물리적 RAM의 한 영역.

  • 여러 프로세스가 실시간으로 같은 데이터를 읽고 쓸 필요가 있을 때도 사용

세마포어는 제한된 수의 리소스를 관리해야 할 때 사용된다. 데이터베이스 연결 풀이나 스레드 풀 관리가 대표적. 특히 클라우드 환경에서 리소스 사용량을 제어할 때 유용하다.

뮤텍스는 한 번에 하나의 프로세스만 접근해야 하는 중요한 자원을 보호할 때 사용한다. 파일 시스템의 중요한 데이터를 수정하거나, 데이터베이스의 트랜잭션을 처리할 때 주로 사용

현대의 대규모 시스템에서는 이러한 IPC 메커니즘들을 계층화하여 사용하는 것이 일반적이다.
예를 들어 마이크로서비스 간의 통신은 메시지 큐로 처리하고, 각 서비스 내부에서는 세마포어나 뮤텍스를 사용하여 리소스 접근을 제어하는 방식으로 진행.

profile
back-end, 지속 성장 가능한 개발자를 향하여

0개의 댓글