Juicycrunch Carrot Blog
목록으로
Engineering

Fallacies of Distributed Computing

분산 시스템을 설계할 때 주의해야 할 8가지 잘못된 가정을 정리합니다.

분산 컴퓨팅의 오류

분산 컴퓨팅의 오류(Fallacies of Distributed Computing)는 분산 시스템을 설계할 때 개발자들이 흔히 저지르는 8가지 잘못된 가정을 정리한 원칙입니다.

  1. 네트워크는 신뢰할 수 있다. (The network is reliable.)
  2. 지연 시간은 0이다. (Latency is zero.)
  3. 대역폭은 무한하다. (Bandwidth is infinite.)
  4. 네트워크는 안전하다. (The network is secure.)
  5. 네트워크 토폴로지는 변하지 않는다. (Topology doesn’t change.)
  6. 관리자는 한 명뿐이다. (There is one administrator.)
  7. 전송 비용은 0이다. (Transport cost is zero.)
  8. 네트워크 환경은 모두 동일하다. (The network is homogeneous.)

여기서 나열한 항목들은 지켜야 할 규칙이 아닙니다. 반대로 경계해야 할 가정 입니다.

L. Peter Deutsch

L. Peter Deutsch

이 원칙은 1994년경 L. Peter Deutsch 의 공로로 알려져있습니다.

L. Peter Deutsch 는 프로그래밍 언어 구현, 가상 머신, 인터프리터 등의 분야에서 중요한 업적을 남긴 미국의 컴퓨터 과학자입니다. 1946년생으로 10대 때부터 프로그래밍을 시작했습니다. UC 버클리에서 컴퓨터 과학 박사 학위를 취득했으며 Sun Microsystems에서 일했습니다.

여담으로 처음엔 7가지 였으나, Java 의 아버지로 유명한 James Gosling 이 8번째 항목을 추가하였습니다.

1. The network is reliable.

네트워크는 신뢰할 수 있다 → 네트워크 요청은 실패할 수 있다

네트워크가 정상적으로 동작할 것이라고 가정했을 때

네트워크 통신은 실패할 수 있습니다.

  • 네트워크 연결이 끊어지는 경우가 있을 수 있다
  • 요청이 유실될 수 있다.
  • 응답이 유실될 수 있다.

여기서 한 가지 오해를 주의해야 합니다. 네트워크가 항상 불안정하거나 통신이 자주 실패한다는 뜻은 아닙니다.

말하고자 하는 것은 ‘통신이 실패할 가능성을 배제하지 마라’ 라는 뜻 입니다.

서버 프로세스가 종료되거나, 네트워크 장비에 문제가 발생하거나, 소켓 연결이 계속 유지되어있다고 판단하거나, 요청이나 응답이 유실될 수 있습니다.

여러가지 기법이 있겠지만 Timeout, 재시도, 중복요청방지, heartbeat 등으로 핸들링 합니다.

2. Latency is zero

지연 시간은 0이다 → 네트워크 통신에는 시간이 걸린다.

통신이 정상적으로 성공하더라도 시간이 걸린다라는점을 기억해야 합니다.

요청의 성공 ⋅ 실패 유무도 중요하지만, 그 요청이 얼마나 빨리 처리되고 Latency 가 전체 시스템에 어떤 영향을 미치는지도 고려해봐야 합니다.

응답 시간 = 네트워크 전송 시간 + 서버 처리 시간 + 기타 시간

데이터는 빛의 속도에 가까운 속도로 이동하지만 중간에 네트워크 장비와 소프트웨어를 거쳐야 합니다. 따라서 소프트웨어를 아무리 최적화하더라도 물리적인 통신 지연 자체를 완전히 없앨 수는 없습니다.

이를 간과했을 경우 가장 대표적인 예시중 하나가 Chatty API 입니다.

Chatty API

예르들어 쇼핑몰에서 마이 페이지에 정보를 가져오기위해 서버에 API 요청을 여러번 한다고 가정해보겠습니다.

  • 내 정보 조회
  • 남은 포인트 조회
  • 내 장바구니 목록 조회
  • 최근 구매목록 정보 조회

각 API 는 독립적으로 보면 합리적입니다. 하지만 하나의 페이지를 표시하기 위해 여러 차례 네트워크 통신이 필요하다면, 그만큼 전체 응답 시간이 길어질 수 있습니다.

해결 방법중 하나는 해당 페이지에 필요한 데이터를 하나의 API에서 함께 반환하는 것입니다. (페이지 특화 API)

API 분리 vs 통합

당연하게도 페이지에 특화된 API가 늘어나면 재사용성이나 유지보수 측면에서 고려할 사항도 생깁니다. 그리고 불필요한 데이터까지 반환하거나 API의 책임이 지나치게 커질 수 있습니다.

캐싱도 응답 시간을 줄이는 방법입니다. 다만 캐시를 사용하면 데이터가 변경되었을 때 기존 캐시를 어떻게 무효화할 것인지도 함께 고민해야 합니다.

핵심은 단순히 API 호출 횟수를 최소화하는 것이 아닙니다. 필요한 데이터를 적절한 크기로, 적절한 횟수만큼 요청하는 것이 중요합니다. 문제는 적절한 수준을 판단하기 어렵다는 것입니다. 부하 테스트, 모니터링을 통해 응답 시간, 처리량, 자원 사용량 등의 지표를 수집하고 병목이 발생하는 지점을 찾아 개선하는 것이 합리적입니다.

3. Bandwidth is infinite.

대역폭은 무한하다 → 전송할 수 있는 데이터의 양에는 한계가 있다

실무에서도 자주 마주치는 문제입니다. 대표적인 사례로 페이지네이션과 이미지 최적화를 들 수 있습니다.

수백만 건의 게시글이 있는데 모든 데이터를 한 번에 반환한다고 가정해 보겠습니다.

데이터를 조회하고 처리하는 데 필요한 메모리뿐만 아니라, 네트워크를 통해 전송하는 데에도 상당한 자원이 필요합니다. 응답 데이터가 커질수록 전송 시간이 길어지고 서버와 클라이언트의 자원 사용량도 증가할 수 있습니다.

이때 페이지네이션을 적용하면 필요한 데이터만 나누어 조회할 수 있습니다.

이미지 최적화도 마찬가지입니다.

예를 들어 목록에서 썸네일만 보여주면 되는 상황인데 원본 이미지의 크기가 5~10MB라면, 원본을 그대로 전송하는 것은 비효율적일 수 있습니다.

이 경우 이미지 업로드 시점에 썸네일을 미리 생성해 두거나, 요청한 크기에 맞는 이미지를 제공하는 방식으로 전송량을 줄일 수 있습니다.

핵심은 모든 데이터를 한 번에 전송하는 것이 아니라 필요한 시점에 필요한 양의 데이터만 전송하는 것입니다.

4. The network is secure.

네트워크는 안전하다 → 네트워크와 통신 상대를 무조건 신뢰해서는 안된다

오픈 인터넷에 배포되는 서비스를 개발할 때 모든 개발자는 TLS, 인증, 인가 등 기본적인 보안 요소를 고려합니다. 하지만 사설망이나 폐쇄망에 서비스를 구축할 때는 상대적으로 보안에 소홀해지기 쉽습니다. 저 역시 망분리가 되어 있는 폐쇄망에서 서비스를 구축하면서 보안을 가볍게 생각했던 경험이 있습니다.

flowchart TD
    Internet[요청]
    Gateway[API Gateway]
    Backend[Backend API<br/>Public]

    subgraph VPC["Private VPC"]
        Order[Order Service]
        Payment[Payment Service]

        Order --> Payment
    end

    Internet --> Gateway
    Gateway --> Backend
    Backend --> Order

위와 같은 구조에서 “어차피 내부 서비스는 검증된 요청만 받을텐데 보안은 생략해도 되는건 아닐까?” 이렇게 생각하기 쉽지만 내부 네트워크에 있다는 사실만으로 통신 상대를 신뢰할 수는 없습니다.

다른 서비스의 보안 취약점이나 설정 오류로 인해 의도하지 않은 요청이 전달될 수도 있습니다.

중요한 것은 각 서비스가 자신이 수행하는 작업을 보호할 책임 이 있다는 점입니다.

5.The network topology doesn’t change

네트워크 토폴로지는 변하지 않는다 → 네트워크 구성, 주소, 연결관계는 변할 수 있다

다음과 같은 코드가 있다고 가정하겠습니다.

String userServiceUrl = "http://192.168.0.10:8080";

특정 서비스의 주소를 코드에 직접 작성했습니다. 물론 고정 IP 를 사용하는 것 자체가 잘못된 것은 아닙니다. 폐쇄망처럼 네트워크 구성이 비교적 고정된 환경에서는 고정 IP를 사용하고 별도의 목록으로 관리하기도 합니다.

문제는 서비스의 위치가 변경되었을 때입니다.

서버가 이전되거나 IP 주소가 변경되면 해당 주소를 참조하는 모든 곳을 찾아 수정해야 할 수 있습니다. 서비스가 많아질수록 이러한 변경을 관리하기가 어려워집니다.

따라서 환경 설정, DNS, 서비스 디스커버리 등을 활용해 서비스의 위치와 애플리케이션의 로직을 분리하는 방법을 고려할 수 있습니다.

물론 DNS 역시 만능은 아닙니다. 주소가 변경되더라도 DNS 캐시, TTL 등에 따라 변경 사항이 즉시 반영되지 않을 수 있습니다.

핵심은 서비스의 위치와 네트워크 구성이 언제나 고정되어 있다고 가정하지 않는 것입니다.

6. There is one administrator

관리자는 한 명 이다 → 시스템마다 관리 주체와 정책이 다를 수 있다

분산 시스템에 참여하는 모든 시스템이 동일한 조직의 관리 정책과 보안 정책을 따른다고 가정해서는 안 됩니다.

예를 들어 우리 서비스가 외부 결제 서비스나 제3자 API와 연동한다고 생각해 보겠습니다. 우리 서비스의 운영 정책과 배포 주기를 자유롭게 조정할 수 있더라도 외부 서비스의 운영 정책이나 변경 일정까지 강제할 수는 없습니다.

  • 배포 및 변경 일정
  • 장애 대응 절차
  • 보안 정책과 접근 권한
  • API 버전 및 하위 호환성 정책
  • 운영 시간과 지원 범위

이러한 차이는 서비스 간 연동 과정에서 예상하지 못한 문제를 일으킬 수 있습니다.

따라서 외부 시스템의 변경이나 장애가 발생하더라도 전체 시스템에 미치는 영향을 최소화할 수 있도록 에러 핸들링, 의존성 관리, 장애 격리 등을 고려해야 합니다.

핵심은 내가 컨트롤 할 수 없는 시스템과 협력해야 한다는 사실을 설계에 반영하는 것입니다.

7. Transport cost is zero

네트워크 전송 비용은 0 이다 → 데이터를 주고받는 데에는 다양한 비용이 발생한다

대표적으로 다음과 같은 비용이 발생합니다.

  • 요청과 응답 데이터를 전송하는 네트워크 비용
  • 객체를 JSON 등의 형식으로 변환하고 다시 객체로 복원하는 데 필요한 CPU 자원
  • 요청과 응답 데이터, 객체 등을 보관하는 데 필요한 메모리
  • 요청을 처리하는 스레드, 연결, 버퍼 등의 자원
  • 서비스 간 통신 규약을 설계하고 모니터링 및 장애 대응 체계를 유지하는 데 드는 비용

이러한 비용은 일반적인 메서드 호출과 네트워크를 통한 원격 호출의 중요한 차이점이기도 합니다.

예를 들어 하나의 애플리케이션 내부에서 메서드를 호출하는 것과 별도의 서비스에 HTTP 요청을 보내 결과를 받는 것은 같은 방식으로 생각하기 어렵습니다.

서비스를 분리하면 독립적인 배포와 확장이라는 장점을 얻을 수 있지만, 그 과정에서 통신과 운영에 필요한 비용도 추가됩니다.

따라서 단순히 서비스를 분리하는 것만으로 설계가 개선된다고 볼 수는 없습니다. 서비스 분리로 얻는 이점과 추가되는 통신 비용을 함께 고려해야 합니다.

8. The network is homogeneous

네트워크 환경은 모두 동일하다 → 시스템마다 실행 환경과 데이터 처리 방식이 다를 수 있다

분산 시스템에서는 서로 다른 운영체제, 하드웨어, 프로그래밍 언어, 라이브러리, 버전 등이 함께 사용될 수 있습니다.

이러한 차이는 데이터 표현이나 처리 방식의 차이로 이어질 수 있습니다.

예를 들어 A 시스템은 Java로, B 시스템은 C#으로 개발했다고 가정해 보겠습니다.

두 언어는 숫자를 반올림하는 기본 메서드의 동작이 서로 다릅니다.

둘의 기본 반올림 방식은 다릅니다. Java 는 사사오입, C# 은 Banker’s Rounding 기법이 기본 속성입니다.

단순 반올림뿐만이 아니라, 날짜, 소수점 정밀도 등 에서도 시스템마다 다를 수 있습니다.

분산 시스템을 설계할 때는 각 서비스의 실행 환경이 동일하다고 가정하지 말아야 합니다. 서로 다른 시스템이 동일한 데이터를 동일한 의미로 처리하는지 확인하는 것이 중요합니다.

마치며

분산 컴퓨팅의 8가지 오류는 특별히 복잡한 기술을 설명하는 원칙이 아닙니다.

사실 너무나도 당연한 이야기처럼 들리기도 합니다.

하지만 시스템을 설계하다 보면 이러한 사실을 잠시 놓치기도 하고 마치 모든 것이 정상적으로 동작할 것처럼 코드를 작성하기도 합니다.

분산 시스템을 설계하거나 외부 서비스와 연동할 일이 있다면 이 8가지 가정을 한 번쯤 리마인드 삼아 생각해보는것도 좋을 것 같습니다.