스터디/TCP 와 IP

8. 멀티프로세스 기반의 서버구현

DDD Developer 2024. 9. 3. 17:27
728x90
반응형

프로세스 이해와 활용

 

지금까지 공부하고 실습했던 코드들은 모두 서버와 클라이언트가 1대1의 관계를 가진다.
즉, 연결요청의 순서를 따라서 첫 번째 클라이언트부터 100번째 클라이언트까지 순차적으로 연결을 허용해서 서비스를 제공하는 서버였다.
하지만 이러한 서버는 실제로는 쓰이질 못한다.
예를 들어 설명해보겠다. 1초만에 서비스를 제공하는 서버가 있다.
순위권에 든 클라이언트는 만족할 수도 있다. 하지만 100번째 1000번째 클라이언트라면 ?
아무리 서비스 시간이 빠르다고 해도 대기시간이 길어지면 메리트가 없을 것이다.
반면에 3초만에 서비스를 제공하는 서버가 있다.
하지만 모든 클라이언트는 접속대기시간이 1초를 넘지 않는다.
당연히 후자의 서버를 고르지 않겠는가 ?


이번 챕터에서 모든 클라이언트의 만족도를 올릴 수 있는 다중 서버에 대해서 배워보자.

 

네트워크 프로그래밍은 CPU의 연산을 필요치 않는 데이터의 송수신 시간이 큰 비중을 차지한다.
그렇기 때문에 둘 이상의 클라이언트에게 동시에 서비스를 제공하는 것이 CPU를 보다 효율적이게 사용하는 것이라고 보면 된다.

 

다중접속 서버의 구현방법들

 

- 멀티프로세스 기반 서버 : 다수의 프로세스를 생성하는 방식으로 서비스 제공
- 멀티플렉싱 기반 서버 : 입출력 대상을 묶어서 관리하는 방식으로 서비스 제공
- 멀티쓰레딩 기반 서버 : 클라이언트의 수만큼 쓰레드를 생성하는 방식으로 서비스 제공

 

 

프로세스(Process)의 이해

 

멀티프로세스 기반 서버의 서비스 주체가 되는 프로세스를 먼저 이해해 봐야한다.

프로세스는 간단하게 다음과 같이 정의 할 수있다.

" 메모리 공간을 차지한 상태에서 실행중인 프로그램"

 

예를 들어 벽돌깨기 게임을 하나 다운 받아서 하드 디스크에 저장해 놓았다고 가정해 보자.

그렇다면 이는 프로세스가 아닌 프로그램이다.

왜냐하면 이는 실행중인 상태가 아니기 때문이다.

그러면 게임을 실행해 봤을때 벽돌깨기 프로그램은 메인 메모리(Main Memory)라는 곳으로 이동해서 실행을 위한 준비를 마치게 된다. 만약 벽돌깨기 프로그램을 둘 이상 실행하게 되면 실행하는 수만큼 프로세스는 생성된다.

이렇듯 프로세스는 운영체제의 관점에서 프로그램 흐름의 기본 단위가 된다.

 

CPU의 코어 수와 프로세스 수


두 개의 연산장치가 존재하는 CPU를 가리켜 Dual 코어 CPU라고 하고, 4개는 Quad라고 한다.
이렇듯 CPU는 실제 연산장치에 해당하는 코어가 둘 이상 존재할 수 있으며, 코어의 수만큼 프로세스는 동시 실행이 가능하다.
반면 코어의 수를 넘어서는 개수의 프로세스가 생성되면, 프로세스 별로 코어에 할당되는 시간을 나눠서 가진다.
하지만 CPU가 워낙 고속으로 프로세스를 실행하기 때문에 프로세스가 동시에 실행되는 것처럼 느끼게 된다.
물론 코어의 수가 많을수록 그 느낌을 더 크게 받을 수 있다.
그래서 코어가 많이 달린 CPU가 비싼 것이다.

 

프로세스 & 좀비(Zombie)프로세스

 

파일은 여는 것 못지않게 닫는 것이 중요하다. 마찬가지로 프로세스도 생성 못지않게 소멸이 중요하다.

만약에 우리가 프로세스를 대충(?)만 소멸해 놓는다면 이들이 좀비처럼 우리를 괴롭힐지도 모른다!

 

좀비 프로세스

 

흔히 아는 좀비와 똑같다.
프로세스를 분명 종료되었는데 죽지 않고 살아있어서 리소스가 메모리 공간을 차지하고 있는 상태를 의미한다.
프로세스는 실행되고 나서 할 일을 다 하면 사라져야 하는데 사라지지 않고 좀비가 되어 시스템의 중요한 리소스를 차지하기도 한다.
이 상태에 있는 프로세스를 가리켜 '좀비 프로세스'라고 부르며 이는 시스템에 부담을 주는 원인이다. 그렇기 때문에 우리는 좀비 프로세스를 소멸시켜야 한다.

 

생성 원인

 

1. 좀비 프로세스란 무엇인가?

  • 자식 프로세스의 잔재: 부모 프로세스가 종료된 자식 프로세스의 상태 정보를 회수하지 않았을 때 발생한다.
  • 프로세스 ID만 남은 상태: 좀비 프로세스는 실제로 실행 중인 코드나 데이터를 가지고 있지 않고, 프로세스 ID(PID)만 남아 프로세스 테이블에 존재한다.
  • 자원 낭비: 좀비 프로세스는 시스템 자원(특히 프로세스 테이블 항목)을 차지하고, 새로운 프로세스 생성을 제한할 수 있다.

2. 좀비 프로세스는 왜 발생하나?

  • 부모 프로세스의 wait() 호출 누락: 자식 프로세스가 종료될 때 부모 프로세스는 wait() 시스템 호출을 통해 자식 프로세스의 종료 상태를 확인하고 자원을 정리해야 합니다. wait() 호출을 하지 않으면 좀비 프로세스가 발생합니다.
  • 부모 프로세스의 무한 루프: 부모 프로세스가 무한 루프에 빠져 wait() 호출을 할 수 없는 경우에도 좀비 프로세스가 발생할 수 있습니다.
  • 부모 프로세스의 종료: 자식 프로세스보다 부모 프로세스가 먼저 종료될 경우, 자식 프로세스는 'init' 프로세스(PID 1)의 자식 프로세스가 되고, init 프로세스는 주기적으로 wait() 호출을 통해 좀비 프로세스를 처리합니다. 하지만 이 과정에서 좀비 프로세스가 일시적으로 발생할 수 있습니다.

3. 좀비 프로세스는 어떻게 확인하나?

  • ps 명령: ps aux 또는 ps -el 명령을 사용하여 프로세스 목록을 확인하고, 상태가 'Z'인 프로세스가 좀비 프로세스입니다.
  • top 명령: top 명령을 실행하고 상태 필터를 'Z'로 설정하면 좀비 프로세스만 확인할 수 있습니다.

4. 좀비 프로세스는 어떻게 처리하나?

  • 부모 프로세스에 wait() 호출 추가: 부모 프로세스 코드에 wait() 또는 waitpid() 시스템 호출을 추가하여 자식 프로세스의 종료 상태를 확인하고 자원을 정리합니다.
  • 부모 프로세스 종료: 부모 프로세스를 종료하면 좀비 프로세스는 init 프로세스의 자식 프로세스가 되고, init 프로세스가 좀비 프로세스를 처리합니다.
  • SIGCHLD 시그널 핸들러 사용: SIGCHLD 시그널 핸들러를 등록하여 자식 프로세스가 종료될 때마다 자동으로 wait() 호출을 수행하도록 할 수 있습니다.
  • 좀비 프로세스 강제 종료 (권장하지 않음): kill -9 명령으로 좀비 프로세스를 강제 종료할 수 있지만, 이는 시스템 불안정을 초래할 수 있으므로 권장하지 않습니다.

5. 좀비 프로세스 예방 팁

  • 자식 프로세스 종료 후 항상 wait() 호출: 자식 프로세스를 생성하고 종료하는 코드에서 항상 wait() 또는 waitpid() 시스템 호출을 사용하여 좀비 프로세스 발생을 방지합니다.
  • SIGCHLD 시그널 핸들러 활용: SIGCHLD 시그널 핸들러를 등록하여 자식 프로세스 종료 시 자동으로 wait() 호출을 수행하도록 합니다.
  • 좀비 프로세스 정기 점검: ps 또는 top 명령을 사용하여 좀비 프로세스 발생 여부를 정기적으로 확인하고, 필요한 경우 처리합니다.

 

좀비 프로세스는 시스템 자원을 낭비하고 새로운 프로세스 생성을 제한하는 문제를 일으킬 수 있습니다. 하지만 올바른 wait() 호출과 SIGCHLD 시그널 핸들러를 사용하면 효과적으로 예방하고 처리할 수 있습니다.

728x90
반응형