빙응의 공부 블로그
[OSTEP 영속성(persistence)]분산 시스템 본문

📝서론
분산 시스템은 전세계의 구조를 바꿨습니다. 웹 브라우저가 지구 상 어딘가에 있는 웹 서버에 접속하면
클라이언트/서버 분산 시스템이라는 구조에 한 구성원이 되는 것이다.
분산 시스템을 개발할 때 몇 가지 새로운 도전거리가 생겨난다. 우리는 그 중 "실패"에 관해서 알아보자.
핵심 질문 : 구성 요소가 실패하더라도 동작하는 시스템을 어떻게 만들까?
- 분산 시스템의 핵심 사안은 여러 개가 존재한다.
- 실패와 고장의 극복
- 시스템 성능
- 보안
📝통신의 기본
최신 네트워킹의 핵심 가정은 통신은 신뢰할 수 없다는 것이다.
이것에는 여러개의 이유가 있다.
- 패킷 손실
- 네트워크는 패킷 단위로 데이터를 전송하는데, 중간 유실이 가능하다.
- 지연, 재정렬, 중복
- 패킷이 전송 순서와 다르게 도착하거나, 중복되거나, 지연될 수 있다.
- 중간 노드 장애/ 네트워크 분리
- 라우터나 중간 서버가 고장 나거나, 네트워크가 분리될 수 있다.
- 이로 인해 메시지 도달이 안될 수 있다.
- 전송 오류
- 보안 문제
- 데이터가 중간에 탈취되거나 변조될 수 있다.
이제 이러한 네트워킹의 근본적인 문제를 어떻게 해결하는지 알아보자
📝신뢰할 수 없는 통신 계층
가장 간단한 방법은 아무런 조치를 취하지 않는 것이다.
신뢰할 수 없는 계층에 대한 예는 거의 모든 현대 시스템에 존재하는 UDP/IP 네트워크 시스템이다.
만약 사용한다면 패킷을 잃어버리는 경우들을 만나게 되며 메시지는 도달하지 못한다.
발신 측은 그렇기 때문에 손실에 대해서 전혀 알 수 없다. 하지만 UDP가 모든 실패에 대비를 못하는 건 아니다. 예를 들어 UDP는 체크섬을 포함하기에 일부 패킷 손상을 검출 가능하다.
📝신뢰할 수 있는 통신 계층
핵심 질문 : 발신자가 수신자가 메시지를 수신했다는 것을 어떻게 알 수 있는가?
쉽게 생각해보면 물어보는 것이다. 우리는 이것을 Ack(acknowledgement)라고 부른다.
간단하게 발신자가 메시지를 수신자에게 보내면 수신자는 받았다는 확인 메시지를 보내는 것이다.
발신자가 Ack를 못 받았다면?
그래서 타임아웃이라는 추가적인 장치를 사용한다. 일정 시간이 지나면 다시 메시지를 전송하는 것이다.

이 과정에서 수신자는 똑같은 메시지를 두번 받는다. 그렇기에 신뢰성을 목표로하면 수신측도 각 메시지를 정확히 한번만 받는다는 보장이 필요하다.

가장 흔히 사용되는 신뢰할 수 있는 통신 계층은 TCP/IP 또는 TCP라고 부른다.
TCP는 위에서 설명한 방법에 더해 더 정교한 기법을 사용한다.
📝통신의 추상화
기본 메시징 계층을 다루었으니 이제 분산 시스템 구현에 필요한 통신 개념을 알아보자.
통신의 추상화란?
- 분산시스템을 쉽게 만들기 위해 통신을 더 높은 수준으로 추상화하려는 시도이다.
- 복잡한 메시지 전송을 마치 로컬 메모리 접근처럼 보이게 하는 방식들이 존재한다.(예. DSM)
예시 DSM(Distributed Shared Memory)
"분산된 여러 컴퓨터가 하나의 가상 메모리 공간을 공유하는 것처럼 보이게 하는 것"
- 각각의 컴퓨터가 하나의 가상 주소 공간을 공유하는 구조
- 마치 멀티스레드 프로그램처럼 코딩할 수 있다.
- 실제로는 메모리 접근 시 다른 기계에 페이지 요청 -> 페이지 폴트 + 통신 발생
문제점
- 실패 처리가 매우 어려움
- 성능 저하
- 실제로 많이 쓰이지 않음
📝 Remote Procedure Call(RPC)
앞서 소개한 DSM로는 현재 시점에서 신뢰할 수 있는 통신 계층을 만들지 않는다.
대신 프로그래밍 언어 차원의 개념을 사용해서 만들게 되었다.
RPC
- 원격 프로시스 호출기
- 네트워크 상에 있는 다른 컴퓨터의 함수를, 마치 로컬 함수 호출하듯이 호출할 수 있게 해주는 프로그래밍 모델
- 분산 시스템 개발에서 운영체제 레벨보다 프로그래밍 언어 차원의 추상화가 더 자연스럽고 효율적이라 인식해서 출발
RPC 구성
| 스텁 생성기 (Stub Generator) | 인터페이스 정의를 받아 클라이언트/서버 스텁 코드를 자동 생성 (인자들을 직렬화/역직렬화하는 코드 포함) 즉, 어뎁터 역할 |
| 런타임 라이브러리 | 메시지 전송, 연결 관리, 동기/비동기 호출, 오류 처리 등 실행 시간 동작 담당 |
RPC 동작 방식
클라이언트 측
- 클라이언트 코드는 마치 로컬 함수 호출하듯 func1(arg) 호출
- 클라이언트 스텁은
- 호출 정보를 메시지 버퍼에 직렬화(marshaling)
- 함수 식별자와 인자 포함
- 메시지를 서버로 전송
- 응답을 기다림 (대부분 동기 호출)
- 응답 메시지에서 결과 역직렬화(unmarshaling) 후 클라이언트에 반환
서버 측
- 서버 스텁이 도착한 메시지에서 호출 정보 추출 (역직렬화)
- 실제 프로시저(함수) 호출
- 결과를 메시지 버퍼에 직렬화해 클라이언트에 응답 전송
📌 고려사항
RPC에서는 고려해야할 몇 가지 중요한 문제들이 있다.
스텝 컴파일러
- 복잡한 구조의 인자나 다수의 인자 전달 문제
- 즉, 복잡한 자료 구조를 어떻게 패키지화해서 전송하는가?
- 병행성을 고려하여 서버를 구성하는 것
- 흔한 구성 방식은 쓰레드 풀을 사용하는 것이다.
런타임 라이브러리
- 서비스 위치 찾기 (Naming)
- 분산 시스템에서 원격 서비스가 어디에 있는지 알아내는 문제
- 가장 기본적으로는 IP 주소 + 포트 번호를 사용한다.
- 더 발전된 시스템은 DNS, 분산 네임 서비스 등 사용
- 전송 프로토콜 선택
- RPC를 TCP 위에서 구현하면 데이터 전달은 확실하나
- 확인 메시지, 타임아웃, 재전송 때문에 성능 저하 발생
- RPC를 UDP 위에 구현하는 경우
- RPC 계층이 타임아웃, 재시도, ACK 같은 신뢰성 메커니즘 직접 처리
- RPC를 TCP 위에서 구현하면 데이터 전달은 확실하나
🔥이렇게만 보면 TCP 위에 RPC를 구현할 이유가 없지 않을까?
결론만 말하면 전혀 그렇지 않다. 여기서는 구분이 필요하다.
- TCP는 비유하자면 네트워크에서 ‘길’(데이터 전송 경로)을 신뢰성 있게 보장하는 전송 계층 프로토콜이다..
- RPC는 분산 시스템에서 원격 함수 호출을 가능하게 하여 분산 자원을 마치 로컬처럼 쓸 수 있게 하는 ‘가상화’ 기술 이다.
즉 TCP가 데이터를 제대로 보내고 받는 통신이라면 RPC는 복잡한 네트워크를 추상화하는 프로그래밍 모델이다.
둘은 서로 보완하는 관계이지만 TCP에서는 중복되는 기능이 많기에 오버헤드도 증가하는 현상이 있어 UDP에서 자주 사용된다.
'CS > 운영체제' 카테고리의 다른 글
| [OSTEP 영속성(persistence)]로그 기반 파일 시스템(LFS) (3) | 2025.07.17 |
|---|---|
| [OSTEP 영속성(persistence)]크래시 일관성: FSCK와 저널링 (0) | 2025.07.15 |
| [OSTEP 영속성(persistence)]파일과 디렉터리 (0) | 2025.06.04 |
| [OSTEP 영속성(persistence)]하드 디스크 드라이브(HDD) (0) | 2025.06.02 |
| [OSTEP 영속성(persistence)]I/O 장치 (1) | 2025.05.27 |