티스토리 뷰
*IPC란 프로세스 간 통신(Inter-Process Communication)을 뜻하는 용어이다.
*IPC에 대해서 설명을 하기 앞서, 프로세스가 무엇인지에 대해서 간략하게 설명을 해보려고 한다.
실행 파일을 실행시키는 과정을 설명해보면, 실행 파일은 DISK에 저장이 되어 있고 이를 실행시키면 특정 메모리에 올라가고 이 메모리가 CPU에 올려서 실행이 된다. 그 후 해당 실행 파일은 '프로세스'가 된다.
만약 A라는 실행 파일과, B라는 실행 파일을 실행하게 되면, 메모리의 특정 부분을 A 프로세스가 차지하고, 다른 특정 부분을 B 프로세스가 차지하게 된다.
이 때 프로세스는 독립적으로 움직이기에 프로세스끼리는 서로 영향을 주지 않는다. 즉, A 프로세스가 하는 일에 대해서 B 프로세스는 관여하지 않는다는 뜻이다.
하지만 이렇게 독립적인게 좋은 점도 있지만 단점도 존재한다. 그리고 때로는 프로세스끼리 서로 데이터를 주고 받아야 하는 순간들도 존재한다. 이 때 IPC를 통해 프로세스들 간에 서로의 자원을 공유할 수 있게 된다.
*IPC는 서로 다른 프로세스들이 데이터를 주고 받는 것을 뜻한다. 이 때 원칙적으로 '같은 컴퓨터' 내에서 실행되고 있는 프로세스들 간에 데이터 교환을 뜻한다. 즉, 다른 컴퓨터에 각각 존재하는 프로세스들 간의 데이터 교환은 원칙적으로 IPC의 범주에 들어가지 않는다.
하지만, 이는 컴퓨터 네트워크를 고려하면 확장될 수 있다. 일반적으로 IPC는 같은 시스템 내에서 동작하는 프로세스들 사이의 통신을 가리키지만, 분산 시스템이나 클라우드 컴퓨팅 환경과 같이 네트워크를 통해 연결된 여러 시스템에서 동작하는 프로세스들 간의 통신을 지칭할 때도 있다. 이러한 경우에는 프로세스가 같은 시스템에 있지 않아도 IPC를 통해 데이터를 교환할 수 있다.
즉, IPC는 주로 같은 시스템(컴퓨터) 내의 프로세스들 사이의 통신을 가리키지만, 확장된 개념으로는 네트워크를 통해 다른 시스템의 프로세스들과 통신하는 경우를 포함할 수 있다. 이러한 '확장된' IPC를 구현하는 기술에는 원격 프로시저 호출(Remote Procedure Call, RPC)과 소켓 통신(Socket Communication)이 포함된다.
*이 때 운영체제의 ‘커널’이 IPC를 사용해서 프로세스끼리 통신을 할 수 있게 된다.
(커널이란 운영체제의 핵심 중추 역할을 하는 애라고 생각하면 된다.)
*그렇다면 어떤 경우에 프로세스끼리 서로 데이터를 주고 받아야 하는 것일까? 대표적인 예시를 통해 이를 설명해 보려고 한다.
(1) 만약 A라는 실행 파일이 있다고 가정했을 때, 이 실행 파일을 실행한다면 보통은 프로세스 1개가 이를 담당해서 처리하게 된다. 하지만, 프로그램이 복잡한 경우에는 1개가 아닌 여러 프로세스를 사용하여 일을 분산시킴으로써 성능 향상에 도움이 되고 효율적인 작업을 수행할 수 있게 된다.
이렇게 1개가 아닌 여러 프로세스를 사용하게 된다면 이 프로세스들이 함께 작업을 하면서 어떤 부분이 이미 처리되었는지, 어떤 부분이 아직 처리 되지 않았는지 등에 대한 정보를 서로 교환해야 한다. 이런 상황에서 IPC가 필요하게 되는 것이다.
(2) 하나의 브라우저에서 여러 탭
⇒ 원래 이런 경우는 여러 탭을 ‘스레드’가 관리하게 되는데, 현대에는 이를 여러 개의 ‘프로세스’가 관리하도록 하기도 한다. 만약 네이버 탭을 2개 열어놨다고 가정해보자. 하나의 탭에서 네이버에 로그인을 했을 때, 다른 탭에 들어가보면 이 탭에도 로그인이 된걸 볼 수 있다. IPC 덕분에 가능한 일이다.
(3) 여러개의 프로그램을 사용
⇒ 음악 재생 프로그램을 실행해서 노래를 듣고 있다고 가정해보자. 이 때 볼륨을 조절하면 오디오 컨트롤러 프로세스에게 전달이 되면서 오디오 컨트롤러의 볼륨도 따라서 조절이 되게 된다.
즉, 음악 재생 프로그램(프로세스)와 오디오 컨트롤러 프로세스 두개가 원래는 별도의 프로세스이지만, 음악 재생 프로세스의 볼륨을 조절했을 때 오디오 컨트롤러 프로세스에게 영향을 주는것 자체가 IPC이다.
(4) 서버와 클라이언트 간의 통신
=> 이는 일반적으로 IPC(프로세스 간 통신)의 범주에는 포함되지 않는다. IPC는 원칙적으로 '하나의 시스템 내에서' 동작하는 프로세스들 간의 통신을 지칭하기 때문이다.
그러나 위에서 언급했듯이, '시스템'이라는 용어의 정의를 넓게 해석하면 서버와 클라이언트 간의 통신을 IPC의 한 종류로 볼 수 있다. 즉, 네트워크 시스템에서는 서버와 클라이언트가 각각 다른 '프로세스'로 취급될 수 있으며, 이 경우에는 그들 간의 통신을 IPC로 볼 수 있다.
이런 의미에서는 소켓 통신, 웹 서비스 API 호출, RPC(Remote Procedure Call) 등 서버와 클라이언트 간의 통신 방식을 IPC의 한 종류로 볼 수 있다. 이들 방식은 서로 다른 시스템에 위치한 프로세스들이 데이터를 주고받을 수 있게 해주는 통신 매커니즘이지만, 기본적인 개념은 프로세스 간의 데이터 교환, 즉 IPC와 동일하다.
IPC의 종류
IPC는 크게 '공유 메모리' 방식과 '메시지 전달' 방식 2가지로 나눌 수 있다.
(1) 공유 메모리(Shared Memory)
-이 방식에서는 두 개 이상의 프로세스가 특정 메모리 영역을 공유하게 된다. 이 공유된 메모리를 통해 데이터를 읽고 쓰며 서로 정보를 교환한다.
-공유 메모리는 커널 의존도가 낮기에 빠른 데이터 교환을 가능하게 하지만, 동시에 여러 프로세스가 메모리에 접근할 때 발생할 수 있는 동기화 문제를 해결해야 한다.
=> 빠르지만, 동기화 이슈가 존재한다.
*공유 메모리 방식의 종류
- 공유 메모리 세그먼트(Shared Memory Segments): 이는 가장 기본적인 형태의 공유 메모리 메커니즘이다. 두 개 이상의 프로세스가 공동으로 사용할 수 있는 메모리 공간을 생성한다. 이 공간에 쓰여진 데이터는 다른 프로세스에서 읽을 수 있으므로 정보 교환이 가능해진다.
- 메모리 맵 파일(Memory Mapped Files): 이는 파일을 메모리에 매핑하여 프로세스가 직접 메모리에 접근하듯이 파일에 접근할 수 있게 해주는 메커니즘이다. 이 방식을 통해 여러 프로세스가 같은 파일에 대해 데이터를 공유할 수 있다.
*공유 메모리의 동기화 문제 해결 방법
- 세마포어(Semaphores): 세마포어는 공유 메모리의 동기화 문제를 해결하는 메커니즘이며, 여러 프로세스가 동시에 공유 메모리에 접근하는 것을 제어한다.
- 조건 변수(Condition Variables): 조건 변수는 특정 조건이 만족될 때까지 프로세스의 실행을 대기시키는 데 사용된다.
*세마포어란?
-깃발이라는 뜻으로 옛날 기찻길에서 깃발 표식으로 파란색이 걸려 있으면 지나가도 되고, 빨간색이 걸려있으면 섰다가 다른 기차가 지나가고나면 지나가게끔 하는 용도로 사용되던 깃발을 의미한다.
이를 컴퓨터 프로그래밍에 적용하여 여러 개의 프로세스가 특정 메모리의 자원을 공유하는데 있어서 무작위로 공유를 하도록 하는 것이 아닌, 허용된 순간에만 접근을 하도록 설정하여 동기화 문제를 해결할 수 있게 된다. 마치 파란색 깃발이 걸려 있을 때만 프로세스는 공유 메모리에 접근이 가능하고, 빨간 깃발이 걸려 있을 때는 일단 대기를 하게 되는 것과 같다.
-세마포어의 값에 따라 공유 메모리에 접근할 수 있는 프로세스의 개수가 정해진다. 즉 '공유 자원의 개수'를 나타내는 일종의 값이다. 아래에 프린터의 예시를 통해 이 말의 의미를 자세하게 알아보자.
서버에 프린터가 5대 연결 되어 있다고 가정해보자. 그럼 '공유 자원'은 5개가 된다. 즉 세마포어가 5로 설정이 된다는 의미이다. 이 때 특정 사용자가 프린터를 사용하기 위해 서버에 요청 하게 되면 공유 자원의 수는 1개가 줄어들면서 4가 된다. 그 이후 사용자가 프린터를 하나씩 사용할 때마다 공유자원의 개수가 하나씩 감소하고, 그러다 사용할 프린터가 더이상 남아있지 않으면 세마포어는 0이 된다. 이 때 또 다른 누군가가 프린트를 사용하고 싶어도 세마포어는 0이기 때문에 대기를 해야 한다. 그 후 누군가 프린터를 다 쓰고 반환하면 다시 1이 증가하게 되는데 이 때 대기하던 사용자는 비로소 사용할 수 있게 된다.
이 때 세마포어의 값이 프린터의 개수만큼 설정이 되어 있었는데, 이 세마포어의 값은 개발자가 따로 상황에 맞춰서 설정을 해둘 수 있게 된다.
-그리고 세마포어는 '교착상태(Deadlock)'를 예방 하는데 중요한 역할을 한다. 교착상태에 대해서는 아래에 설명할 것이다.
=> 한 마디로 세마포어란 공유 가능 자원의 개수를 의미하게 되고, 이 세마포어의 개수 만큼 프로세스는 특정 메모리에 동시 접근이 가능하게 된다. 만약 세마포어 값 이상의 프로세스가 접근하려고 한다면 이 프로세스는 대기를 해야 하고, 이미 공유 자원을 사용 중인 프로세스 중 하나가 작업을 끝내고 나왔을 때, 즉 세마포어의 값이 0에서 1이 됐을 때 비로소 대기 하던 프로세스는 이 공유 메모리에 접근이 가능하게 된다. 이렇게 접근 가능한 프로세스의 개수를 제한함으로써 동기화 문제를 해결할 수 있게 된다.
(2) 메시지 전달(Message Passing)
-이 방식에서는 프로세스들이 메시지를 보내고 받아 데이터를 교환한다. 메시지는 데이터와 제어 정보를 포함할 수 있으며, 이를 통해 프로세스는 서로 독립적으로 동작할 수 있다.
-메시지 전달은 동기화 문제를 비교적 쉽게 관리할 수 있지만, 메시지를 보내고 받는 과정에서 발생하는 오버헤드가 공유 메모리 방식보다는 크다는 단점이 있다.
-커널 의존도가 메모리 공유 방식에 비해 높기 때문에 속도가 더 느리다.
*메시지 전달 방식의 종류
- 파이프(Pipes): 한 프로세스는 하나의 파이프를 기준으로 파이프의 한쪽 끝에서 데이터를 쓰고, 다른 프로세스는 반대쪽 끝에서 데이터를 읽는다. 파이프는 주로 단방향 통신에 사용되지만, 양방향 통신이 필요한 경우에는 두 개의 파이프를 사용할 수 있다.
파이프는 '이름이 없는 파이프'와 '이름이 있는 파이프' 두가지로 나눌 수 있는데, 이름이 없는 파이프의 경우에는 일반적으로 부모 프로세스와 자식 프로세스 사이와 같이 '서로 관련이 있는 프로세스' 간에 데이터를 전송하는 데 사용된다. 그리고 통신이 끝나면 이 파이프는 사라지기에 주로 일회성의 통신을 할 때 자주 사용된다.
그에 비해 이름이 있는 파이프의 경우에는 '서로 관련이 없는 프로세스' 간에도 통신이 가능하다. 그리고 통신이 끝나도 사라지지 않기에 주로 일회성 보다는 지속적인 통신을 할 때 자주 사용된다. - 소켓(Sockets): 소켓은 네트워크를 통해 데이터를 전달하는 기능을 제공한다. 고로 소켓을 통해 '같은 시스템(컴퓨터)의 다른 프로세스' 또는 '다른 시스템(컴퓨터)의 프로세스'와 통신할 수 있다.
한 마디로 로컬에서 프로세스끼리 통신을 할 때도 이 소켓을 사용할 수 있지만, 원격으로 서로 다른 컴퓨터에 존재하는 프로세스끼리도 소켓을 통해 통신을 할 수 있다. 이 때 TCP 또는 UDP와 같은 프로토콜 또는 IP, 포트 번호와 같은 수단을 통해 특정 프로세스에게 데이터를 전달해준다. - 메시지 큐(Message Queues): 메시지 큐는 프로세스 간에 데이터를 전달하는 방식으로, 메시지는 큐라는 자료구조에 저장되어 전달된다. 큐는 FIFO (First In, First Out) 원칙에 따라 먼저 들어온 메시지가 먼저 나가게 된다. 메시지 큐를 통한 통신은 메시지 단위로 이루어지며, 각 큐는 고유의 ID를 가진다. 이를 통해 특정 프로세스가 특정 메시지 큐에 접근하여 메시지를 읽거나 쓸 수 있다.
메시지 큐의 한 가지 중요한 특성은 프로세스가 메시지를 전달할 때, 메시지는 커널에 의해 관리되는 큐에 먼저 저장되고, 그 후에 수신 프로세스가 해당 메시지를 받게 된다. 이런 방식은 프로세스들이 동시에 메시지를 전송하더라도 데이터가 손실되지 않도록 보장해준다.
메시지 큐는 메시지를 통한 비동기 통신에 특히 유용하며, 프로세스 간에 복잡한 데이터를 안전하게 전달하거나, 다수의 프로세스 간에 데이터를 교환하는 등의 상황에서 적합하다. 하지만 큐에 저장된 메시지들이 많아지면 추가적인 메모리를 필요로 하므로, 이를 관리하는 데 주의가 필요하다. - 시그널(Signals): 프로세스에게 일종의 "알림"을 보내는 방법이다. 프로세스가 특정 이벤트를 알려주기 위해 다른 프로세스에게 시그널을 보낼 수 있다. 예를 들어, 우리가 휴대폰에 '알람'을 설정하면, 설정한 시간이 되면 휴대폰은 우리에게 알람을 울려서 시간을 알려준다. 이런 상황에서 휴대폰이 우리에게 '알람 시그널'을 보낸 것과 같다. 그런데 이렇게 보낸 시그널이 어떤 동작을 취하게 할지는 프로세스가 정할 수 있다. 휴대폰의 '알람' 예시로 돌아가서 보면, 우리는 알람이 울리면 어떤 동작을 취할지 선택할 수 있다. 예를 들어, '다시 알림'을 누르면 알람은 일시적으로 멈추고, '정지'를 누르면 알람은 완전히 멈춘다.
이처럼 시그널을 받은 프로세스도 자신이 취할 동작을 선택할 수 있다. 시그널은 강력한 통신 수단이지만, 복잡한 데이터를 전송하기 위한 수단은 아니다. 시그널은 단지 특정 이벤트가 발생했음을 알리는 역할을 하며, 이를 통해 프로세스는 그에 따른 적절한 행동을 취할 수 있게 된다.
추가적인 내용
*교착 상태(Deadlock)란
-두 개 이상의 프로세스들이 있을 때, 서로가 각자에게 가진 자원이 필요해서 접근했을 때 프로세스 각자가 서로 상대방의 자원을 점유하고 있어, 모두가 진행할 수 없는 상태를 뜻한다.
즉, 각각의 프로세스는 서로 상대방이 가지고 있는 자원을 기다리며 무한정 대기하다가 결국 아무 일도 일어나지 않는 상태에 빠지는 것을 뜻한다.
-교착 상태를 해결하기 위한 대표적인 방법으로는 은행원 알고리즘이 있다.
*프로세스와 스레드의 차이
-프로세스는 특정 메모리 부분을 공유하는 반면 ‘스레드’는 애초에 메모리 자체를 공유하기 때문에 더 빠르지만 그에 따른 단점도 존재한다.
'기술 노트' 카테고리의 다른 글
서버 트래픽 과부하에 대한 예방과 대처 방법 (0) | 2023.05.07 |
---|---|
쿠키와 세션, OAuth, JWT에 대하여 (0) | 2023.04.29 |
Node.js의 '특징'과 '동작원리' 그리고 JS의 '동작원리' (0) | 2023.04.08 |
DB Index란? (0) | 2023.03.28 |
컴퓨터의 구조와 OS의 관계 (0) | 2023.03.21 |