Butler Lampson의 Xerox PARC 아이디어—네트워킹, OS 구조, 네이밍, 캐싱, RPC—에 대한 실용적 가이드와 이것들이 오늘날 대규모 시스템에 왜 여전히 영향력을 미치는지 설명합니다.

Butler Lampson은 지난 반세기 동안 가장 영향력 있는 컴퓨터 시스템 설계자 중 한 명이었다. 1970~80년대 Xerox PARC에서 그는 네트워크화된 컴퓨터가 고립된 기계가 아니라 프로그램, 파일, 프린터, 사람 등과 신뢰성 있게 상호작용하는 공유 환경의 일부로 동작해야 한다는 관점을 형성하는 데 기여했다.
Lampson 작업이 오래가는 이유는 근본에 집중했기 때문이다: 확장되는 인터페이스, 합성 가능한 메커니즘, 현실 세계의 실패를 예외가 아니라 전제로 삼는 시스템 설계.
“스케일”은 단순히 거대한 데이터센터를 의미하진 않는다. 이는 시스템에 많은 사용자, 많은 머신, 그리고 현실 세계의 혼란이 동시에 존재할 때 벌어지는 일이다. 예: 수백 대의 노트북과 서비스가 로그인과 파일을 공유하는 사무실; 동시에 수천 명의 고객이 쓰는 제품; 서버 하나가 다운되거나 네트워크가 느리거나 업데이트가 완벽하게 롤아웃되지 않아도 동작해야 하는 사내 앱.
이 시점에서 어려운 문제들이 바뀐다. "내 컴퓨터에서 동작하나?"가 아니라 다음을 묻는다:
이 글은 단순한 기념관 투어나 향수 여행이 아니다. Lampson의 작업은 지속된 설계 아이디어를 남겼기 때문에 유용하다: 명료한 인터페이스, 단순한 빌딩 블록, 실패를 전제로 한 시스템.
우리는 네트워킹, RPC, 네이밍, 캐싱, 실용적 보안 같은 개념에 초점을 맞춰 현대 운영체제와 분산 컴퓨팅에 어떻게 이어졌는지 살펴본다. 이를 통해 오늘날 아키텍처에서 이러한 패턴을 인식하고 당신의 서비스에 적용할 수 있을 것이다.
각 사람의 책상에 강력한 개인용 컴퓨터가 있고, 그 컴퓨터들이 전체 작업장을 하나의 일관된 시스템처럼 느끼게 하는 공유 서비스에 연결되어 있다고 상상해 보라. 그게 Xerox PARC의 가정이었다: 단순히 “컴퓨터 한 대”가 아니라 컴퓨팅, 문서, 통신이 사람과 기계 사이에서 자연스럽게 흐르는 네트워크화된 환경.
PARC의 목표는 개인용 컴퓨팅을 일상 업무(글쓰기, 설계, 파일 공유, 인쇄 초안, 협업)에 실용적으로 만드는 것이었다—메인프레임 운영자나 특별한 의식이 필요하지 않게. 목표는 단일 혁신 장치가 아니라 하루 종일 생활할 수 있는 작동 가능한 환경을 만드는 것이었다.
Alto는 “개인” 부분이었다: 상호작용 작업을 위해 설계된 컴퓨터. Ethernet은 “작업 공간” 부분이었다: Altos가 서로와 공유 리소스와 빠르게 대화하게 한 로컬 네트워크.
이 공유 리소스들은 옵션이 아니라 필수였다:
이 조합은 새로운 사고방식을 촉발했다: 당신의 컴퓨터는 혼자서도 강력하지만, 네트워크 서비스를 안정적으로 이용할 수 있을 때 훨씬 더 유용해진다.
PARC는 프로토타입이나 분리된 데모에 그치지 않았다. 하드웨어, 운영체제, 네트워킹, 애플리케이션을 포함한 완전한 시스템을 조립하고 사람들이 실제로 어떻게 일하는지에서 배웠다.
그 피드백 루프는 실제로만 드러나는 어려운 문제들을 보여주었다: 이름 붙이기, 과부하 처리, 실패 대응, 예측 가능한 성능 유지, 그리고 공유 리소스가 원격이라기보다 “가까운” 것처럼 느껴지게 만드는 방법.
많은 PARC 시스템은 알아볼 만한 접근을 반영한다: 간단한 원시 기능과 강한 엔지니어링 규율의 결합. 인터페이스는 작고 이해하기 쉽게 유지하고, 서비스는 깔끔하게 합성되도록 설계하며, 아이디어를 실제 배포에서 시험한다. 이 스타일 덕분에 교훈은 현대 팀이 대규모 시스템을 구축할 때도 여전히 적용된다.
Xerox Alto는 단순히 "책상 위의 컴퓨터"가 아니었다. 개인 기기, 고품질 그래픽 인터페이스, 그리고 당신을 공유 리소스에 연결하는 빠른 로컬 네트워크라는 세 가지 아이디어를 하나의 일상적 경험으로 묶었다는 점에서 전환점이었다.
그 조합은 기대치를 조용히 재배선했다. 당신의 컴퓨터는 반응성 있고 상호작용 가능하며 항상 이용 가능한 느낌을 주면서도, 동시에 공유 파일 서버, 프린터, 협업 도구 같은 더 큰 시스템으로 들어가는 관문처럼 느껴졌다. 이것이 클라이언트/서버 사고방식의 씨앗이다.
Alto 스타일 이전에는 컴퓨팅이 종종 기계(또는 터미널)를 직접 사용하는 형태였다. Alto는 이를 뒤집었다: “클라이언트”가 사용자 곁에 살았고 네트워크는 공유 기능을 가깝게 느끼게 했다.
실제로 “클라이언트/서버”는 다이어그램이 아니라 워크플로였다. 즉각적인 피드백이 필요한 작업(텍스트 편집, 드로잉, 창과 상호작용)은 로컬에서, 공유되거나 모든 책상에 복제하기엔 비용이 큰 작업(권위 있는 문서 저장, 프린터 관리, 접근 조정, 이후의 공유 서비스 실행)은 원격에서 처리되었다.
“Alto”를 “노트북”으로, “파일/프린트 서버”를 “클라우드 서비스”로 바꾸면 친숙한 정신 모델이 된다. 당신의 장치는 여전히 클라이언트이다: UI를 렌더링하고, 데이터를 캐시하며, 짧은 지연의 상호작용을 처리한다. 클라우드는 여전히 서버 측이다: 공유 상태, 협업, 중앙화된 정책, 탄력적 컴퓨트를 제공한다.
좋은 시스템은 이 분할을 거부하지 않고 받아들인다. 사용자는 로컬 반응성과 오프라인 관용을 원하고, 조직은 공유된 진실과 조정된 접근을 원한다.
이 분할은 운영체제 및 시스템 설계자에게 지속적인 긴장을 만든다:
PARC 시대의 작업은 이 긴장을 일찍 가시화했다. 네트워크를 컴퓨터의 일부로 간주하면, 로컬과 원격이 하나의 시스템처럼 느껴지도록 인터페이스, 캐싱, 실패 동작을 설계해야 한다—그러나 둘이 동일하다고 속이진 말아야 한다.
Ethernet은 단순히 “그저 네트워킹”처럼 보이기 쉬우나, Xerox PARC에서는 방 안의 개인용 기계들이 공유 시스템처럼 동작하게 만든 실용적 돌파구였다.
Ethernet 이전에는 컴퓨터 연결이 종종 비싸고 특수한 링크를 의미했다. Ethernet은 경제성을 바꿨다: 비교적 저렴한 공유 매체에 많은 머신이 동시에 붙을 수 있게 한 것.
이는 기본 가정을 “하나의 큰 컴퓨터”에서 “여러 작은 컴퓨터의 협력”으로 바꿨다. 협업이 영웅적 인프라를 필요로 하지 않게 된 것이다.
동일하게 중요한 점은 Ethernet의 공유적 성격이 새로운 시스템 설계를 권장했다는 것이다: 서비스는 다른 머신에 살 수 있고, 프린터와 파일 서버는 네트워크에 연결될 수 있으며, 팀은 연결성이 드문 자원이 아니므로 빠르게 반복할 수 있었다.
오늘날 우리는 네트워크를 운영체제가 메모리나 저장소를 다루듯이 취급한다: 추가 요소가 아니라 플랫폼의 일부다. 앱의 “로컬” 동작은 종종 원격 호출, 원격 데이터, 원격 신원, 원격 구성에 의존한다.
이 사실을 수용하면 네트워크가 정중히 방해하지 않을 것이라고 설계하지 않게 된다.
공유 네트워크는 경쟁을 의미한다. 패킷은 지연되거나 버려지거나 순서가 바뀔 수 있다. 피어는 재부팅한다. 스위치는 과부하된다. 아무것도 “고장” 나지 않은 것처럼 보여도 시스템은 망가진 것처럼 느껴질 수 있다.
따라서 올바른 자세는 불완전한 조건에서의 정상 동작을 위해 구축하는 것이다:
Ethernet은 분산 컴퓨팅을 가능하게 했고, 분산 컴퓨팅이 요구하는 규율도 강제했다.
PARC에서는 “서비스”가 네트워크상에서 다른 것들을 위해 한 가지 일을 하는 프로그램이었다.
파일 서비스는 문서를 저장하고 반환했다. 인쇄 서비스는 문서를 받아 종이에 출력했다. 디렉터리(또는 네이밍) 서비스는 기계 세부 정보를 외우지 않고도 올바른 파일 서버, 프린터, 사람을 찾도록 도왔다. 각 서비스는 분명한 목적, 정의된 인터페이스, 그리고 그에 의존하는 사용자를 가졌다.
큰 시스템을 작은 서비스로 쪼개면 변경이 더 안전하고 빨라진다. 인쇄 시스템에 새 기능이 필요하면 파일 저장소 전체를 다시 설계할 필요가 없다. 경계는 책임을 명확히 한다: “파일은 여기 저장된다” vs “인쇄는 여기서 처리된다.”
또한 서비스는 인터페이스를 먼저 설계하는 습관을 장려한다. 프로그램이 다른 머신과 이야기해야 하면 입력·출력·오류를 명시해야 하는데, 모놀리스 내부에서는 종종 모호하게 남는 세부사항들이다.
서비스가 많아지면 네트워크 요청도 많아진다. 이는 지연을 추가하고 부하를 증가시키며 새로운 실패 모드를 만든다: 파일 서비스는 살아있지만 인쇄 서비스는 다운됐거나, 디렉터리 서비스가 느릴 수도 있다.
모놀리스는 “한꺼번에” 실패하지만, 분산 서비스는 부분적이고 혼란스러운 방식으로 실패한다. 해결책은 서비스를 피하는 것이 아니라 부분적 실패를 명시적으로 설계하는 것이다.
많은 클라우드 앱이 내부 서비스로 운영된다: 사용자 계정, 결제, 검색, 알림 등. PARC의 교훈은 여전히 적용된다: 명확성과 독립적 진화를 위해 분할하되, 첫날부터 네트워크 지연과 부분적 장애를 계획하라.
실무적으로 팀은 서비스 경계에 기본 타임아웃, 재시도, 명확한 오류 메시지를 결합한다(참조: /blog/failure-is-normal).
원격 프로시저 호출(RPC)은 단순한 아이디어지만 큰 효과가 있다: 다른 머신의 함수를 마치 로컬 함수 호출처럼 호출하는 것. 요청을 수작업으로 포장하고 네트워크로 보내고 응답을 풀어내는 대신, RPC는 프로그램이 “getUser(42) 실행해”라고 말하면 시스템이 메시지 전달을 뒤에서 처리하게 한다.
이 “로컬처럼 느끼게” 하는 목표는 Xerox PARC의 분산 컴퓨팅 작업의 중심이었고, 오늘날 팀들이 여전히 원하는 것이다: 명확한 인터페이스, 예측 가능한 동작, 애플리케이션 코드에 노출된 복잡성의 축소.
위험은 RPC가 일반 함수 호출처럼 너무 보일 수 있다는 점이다. 로컬 호출은 실행되거나 프로세스를 크래시시키지만, 네트워크 호출은 느려지거나 사라지거나 부분적으로 완료되거나 응답 없이 성공할 수 있다. 좋은 RPC 설계는 이런 현실을 내재화한다:
타임아웃과 응답 손실은 재시도를 불가피하게 만든다. 그래서 멱등성이 중요하다: 한 번 하든 여러 번 하든 효과가 같은 연산.
간단한 예: chargeCreditCard(orderId, amount)은 기본적으로 멱등적이지 않다—타임아웃 후 재시도하면 중복 결제가 발생할 수 있다. 더 안전한 설계는 chargeCreditCard(orderId)처럼 orderId가 고유한 청구를 식별하고 서버가 반복을 “이미 처리됨”으로 취급하도록 하는 것이다. 이렇게 서버가 중복을 제거하면 재시도가 안전해진다.
현대 API는 RPC 사고방식의 직계 후손이다. gRPC는 정의된 인터페이스와 타입화된 메시지로 “원격 메서드 호출” 모델을 명시적으로 만든다. REST는 보통 메서드 지향보다 자원 지향으로 보이지만 목표는 유사하다: 서비스 간 통신 방식 표준화, 계약 정의, 실패 관리.
어떤 스타일이든 PARC의 교훈은 동일하다: 네트워크는 도구이지 무시할 세부사항이 아니다. 좋은 RPC는 분산을 편리하게 만들되 그것이 무료인 척하지 않는다.
분산 시스템은 깨질 때 진정으로 ‘분산’처럼 느껴진다. 많은 날들이 무언가를 찾을 수 없기 때문에 망가진 것처럼 느껴진다.
네이밍은 어렵다. 현실 세계는 가만히 있지 않는다: 머신은 교체되고, 서비스는 새 호스트로 옮겨지고, 네트워크는 재번호 매겨지며, 사람들은 여전히 “파일 서버”나 “LaserWriter로 인쇄” 같은 안정적이고 기억하기 쉬운 경로를 기대한다. 만약 당신이 입력하는 이름이 동시에 위치라면, 모든 변경이 사용자에게 보이는 중단으로 이어진다.
PARC 시대의 핵심 아이디어는 *원하는 것(이름)*과 *현재 어디에 있는지(위치)*를 분리하는 것이다. 이름은 안정적이고 의미 있어야 하고, 위치는 변경 가능한 구현 세부사항이다.
이 둘이 결합되면 시스템은 취약해진다: 지름길, 하드코딩된 IP, 설정 부패가 발생한다.
디렉터리 서비스는 “지금 X는 어디에 있나?”라는 질문에 이름을 위치로 매핑해 답한다(종종 타입·소유자·접근 규칙 같은 메타데이터도 포함). 최고의 디렉터리는 단순 조회를 저장하는 것을 넘어서 조직이 작동하는 방식을 인코딩한다.
좋은 네이밍과 디렉터리 설계는 몇 가지 실용적 특성을 공유한다:
DNS는 고전적 예다: 사람 친화적 이름은 변하는 IP 집합으로 매핑되고, 캐싱은 TTL로 제어된다.
기업 내부의 서비스 디스커버리 시스템도 같은 패턴을 반복한다: 안정적인 서비스 이름, 바뀌는 인스턴스, 캐시 성능과 업데이트 속도 사이의 긴장.
교훈은 단순하다: 시스템을 확장 가능하고 이해하기 쉽게 유지하려면 네이밍을 사후 고려 사항이 아니라 일급 설계 문제로 다뤄라.
캐싱은 단순하다: 이미 가져온 것을 가까이에 보관해 다음 요청을 더 빠르게 처리한다. 네트워크를 건너지 않거나 느린 디스크나 바쁜 서버에 다시 접근하지 않도록 로컬 복사본을 재사용한다.
PARC에서는 네트워크화된 워크스테이션과 공유 서비스 때문에 “서버에 다시 물어보기”가 비싼 습관이었다. 캐싱은 대부분의 경우 원격 리소스를 빠르게 느끼게 만들었다.
단점은 신선도다. 캐시는 틀릴 수 있다.
공유 문서가 서버에 저장되어 있다고 상상하자. 워크스테이션은 파일을 캐시해 즉시 연다. 동료가 같은 문서를 편집해 새 버전을 저장하면, 캐시가 이를 인지하지 못하면 오래된 내용을 계속 보거나 오래된 복사본을 편집해 최신 작업을 덮어쓸 수 있다.
그래서 모든 캐싱 설계는 다음 사이의 균형이다:
팀은 보통 몇 가지 도구로 이 균형을 관리한다:
현대 시스템은 이 패턴을 어디서나 쓴다: CDN은 웹 콘텐츠를 사용자 근처에 캐시하고, 브라우저와 모바일 앱은 자산과 API 응답을 캐시하며, 데이터베이스 캐싱 레이어(Redis, Memcached 등)는 기본 저장소의 부하를 줄인다.
여전히 남는 교훈: 캐싱은 가장 저렴한 성능 승리이지만, 제품에서 “충분히 신선함”이 무엇인지 명확히 정의해야만 안전하게 사용할 수 있다.
대규모 보안은 단지 “당신은 누구인가?”만이 아니라 “지금 특정 리소스에 대해 무엇을 할 수 있는가?”도 포함한다. Lampson과 Xerox PARC 전통은 매우 실용적인 아이디어를 밀어붙였다: 케이퍼빌리티(권한 토큰).
케이퍼빌리티는 파일, 프린터, 메일박스, 서비스 연산 같은 것에 대한 접근을 허용하는 위조 불가능한 토큰이다. 토큰을 소유하면 허용된 행동을 수행할 수 있고, 없으면 수행할 수 없다.
핵심은 위조 불가능성: 시스템은 추측으로 유효한 토큰을 만들어내는 것을 계산적으로나 구조적으로 불가능하게 만든다.
호텔 키 카드가 당신 방(그리고 당신의 체류 기간)에만 열리는 식으로 생각하면 된다. 수기로 쓴 “들어와도 된다” 메모와는 다르다.
많은 시스템은 신원 기반 보안에 의존한다: 사용자를 인증한 다음, 자원마다 어떤 사용자/그룹이 무엇을 할 수 있는지 쓰인 **ACL(접근 제어 목록)**을 확인한다.
ACL은 직관적이지만 분산 시스템에서 번거로워질 수 있다:
케이퍼빌리티는 기본을 뒤집는다. 중앙 권한을 반복해서 묻는 대신, 이미 권리를 인코딩한 토큰을 제시한다.
분산 시스템은 작업을 머신 간에 계속 전달한다: 프론트엔드가 백엔드를 호출하고, 스케줄러가 작업을 워커에게 주고, 한 서비스가 다른 서비스를 트리거한다. 각 홉은 딱 필요한 만큼의 권한을 안전하게 전달하는 방법이 필요하다.
케이퍼빌리티는 이를 자연스럽게 만든다: 요청과 함께 토큰을 전달하면 수신 머신은 매번 신뢰를 재발명하지 않고 이를 검증할 수 있다.
잘 설계하면 우발적 과도 권한을 줄이고 문제가 생겼을 때 영향 범위를 제한한다.
케이퍼빌리티는 오늘날 다음 형태로 자주 나타난다:
교훈은 단순하다: 접근 설계는 위임·범위·만료를 중심으로 하고, 장기 신원만으로 설계하지 마라.
분산 시스템은 하나의 깔끔한 방식으로 “망가지지” 않는다. 기계가 작업 중간에 크래시하고, 스위치가 재부팅되고, 네트워크 경로가 패킷을 차단하거나 지연시키고, 전력 장애가 일부 랙만 먹어버리는 식으로 지저분하고 부분적인 실패가 발생한다.
사용자 관점에서는 서비스가 “업” 상태지만 일부는 접근할 수 없을 수 있다.
실용적 실패 모델은 직설적이다:
이걸 수용하면 오류를 “예외적 가장자리 케이스”로 보지 않고 정상 제어 흐름의 일부로 다루게 된다.
대부분 시스템은 소수의 수법에 의존한다.
타임아웃은 호출자가 영원히 기다리지 않게 한다. 핵심은 추측이 아니라 실제 지연 데이터에 기반해 타임아웃을 설정하는 것이다.
재시도는 일시적 결함에서 회복할 수 있지만, 장애 동안 부하를 증폭시킬 수도 있다. 그래서 지수 백오프(재시도할 때마다 더 길게 기다림)와 지터(무작위성)는 동기화된 재시도 폭탄을 방지한다.
페일오버(스탠바이 인스턴스나 복제본으로 전환)는 구성 요소가 정말로 다운됐을 때 도움이 되지만, 나머지 시스템이 실패를 안전하고 빠르게 감지할 수 있을 때만 유효하다.
재시도하면 작업이 한 번 이상 실행될 수 있다. 이것이 at-least-once 전달이다: 작업을 잃지 않으려 노력하지만 중복이 생길 수 있다.
Exactly-once는 동작이 정확히 한 번 일어난다는 보장이다. 네트워크 분할을 건너면 얻기 어렵다.
많은 팀은 대신 연산을 멱등적으로 설계해 at-least-once가 수용 가능하도록 한다.
가장 신뢰할 수 있는 팀은 스테이징(때론 프로덕션)에서 적극적으로 실패를 주입하고 결과를 관찰한다: 인스턴스를 죽이고, 네트워크 경로를 차단하고, 종속성을 느리게 하며 알람·재시도·사용자 영향이 어떻게 동작하는지 검증한다.
중단을 놀라운 사건이 아니라 설계를 개선하는 실험으로 다뤄라.
운영체제는 개의 해로 늙는다: 새 기능이 늘어날수록 상호작용 방식이 기하급수적으로 증가하고 그 안에 버그가 숨어든다.
Lampson 학파는 OS 구조를 확장 전략으로 본다. 핵심이 지저분하면 위에 쌓인 모든 것이 그 지저분함을 물려받는다.
반복되는 PARC 시대의 교훈은 커널(또는 “신뢰된 코어”)을 좁고 단순한 합성 가능한 원시 기능들로 유지하라는 것이다. 수십 가지 특수 케이스를 집어넣는 대신 설명하기 쉽고 오용하기 어려운 몇 가지 메커니즘을 정의하라.
명확한 인터페이스는 메커니즘만큼 중요하다. 경계가 명시적일 때(구성 요소가 무엇을 약속하고 무엇을 가정하는지), 구현을 교체하고 부분을 격리해 테스트하며 우발적 결합을 피할 수 있다.
격리는 영향 범위를 제한한다. 메모리 보호, 프로세스 분리, 최소 권한 자원 접근 등은 “어디서든 버그가 모든 것을 망친다”를 “버그는 격리된다”로 바꾼다.
이 사고방식은 케이퍼빌리티와 유사한 설계로 이끈다: 코드에 필요한 권한만 부여하고 접근을 명시적으로 하라.
실용주의는 성능에서도 드러난다: 흔한 연산을 위한 빠른 경로를 만들고 안전성이나 명확성을 사지 않는 오버헤드는 피하라.
목표는 모든 것을 미세 최적화하는 게 아니라 평상시 사용이 즉각적으로 느껴지게 하면서 정합성을 유지하는 것이다.
오늘날 커널, 언어 런타임, 컨테이너화 플랫폼에서 같은 아이디어를 볼 수 있다: 작고 신뢰된 기반, 잘 정의된 API, 팀이 빠르게 출시하되 실패 모드를 공유하지 않게 하는 격리 경계(프로세스·샌드박스·네임스페이스).
세부는 바뀌었지만 설계 습관은 여전히 유효하다.
PARC의 큰 승리는 단일 발명품이 아니라 사람들이 실제로 쓸 수 있는 네트워크 시스템을 만들던 일관된 방법론이었다. 이름은 바뀌었지만 핵심 문제들(지연, 실패, 신뢰, 소유권)은 변하지 않았다.
설계 검토할 때 도움이 되는 “정신적 사전”:
시스템을 평가할 때 사용하라:
한 현대적 변화는 팀이 분산 아키텍처를 빠르게 프로토타입할 수 있다는 점이다. Koder.ai 같은 도구(채팅으로 웹·백엔드·모바일 앱을 빌드하는 바이브-코딩 플랫폼)는 “첫 동작 시스템” 단계를 가속화할 수 있다—프런트엔드는 React, 백엔드는 Go+PostgreSQL, 모바일은 Flutter로 시작해 소스 코드를 추출하고 나중에 진지한 프로덕션 코드베이스처럼 발전시킬 수 있다.
그러나 Lampson 시대의 교훈은 여전히 적용된다: 속도가 이익이 되려면 인터페이스를 명확히 하고 실패 동작(타임아웃·재시도·멱등성)을 명시하며 네이밍, 캐싱, 권한을 일급 설계 결정으로 다뤄야 한다.
따라할 것: 규율—간단한 인터페이스, 명시적 계약, 부분적 장애를 전제로 한 설계.
적응할 것: 오늘은 매니지드 디스커버리, API 게이트웨이, 클라우드 IAM을 쓴다—직접 만든 디렉터리와 수동 인증 대신.
피할 것: 과도한 중앙집중화(모두가 의존하는 하나의 ‘신 서비스’)와 불명확한 소유권(책임자가 없는 공유 컴포넌트).
도구는 계속 바뀔 것이다—새 런타임, 새 클라우드, 새 프로토콜—그러나 제약은 남는다: 네트워크는 실패하고 지연은 존재하며 사람으로 운영할 수 있을 때 시스템만이 확장한다.
이 문맥에서 “스케일”은 많은 사용자, 많은 머신, 그리고 지속적인 현실 세계의 혼잡이 존재하는 상태를 뜻합니다. 문제는 여러 서비스에 걸친 요청들이 생기고 실패가 부분적으로 발생할 때 드러납니다: 어떤 것은 동작하고, 어떤 것은 타임아웃되고, 그럼에도 시스템은 예측 가능한 방식으로 동작해야 합니다.
PARC는 개인용 컴퓨터(Alto)들이 Ethernet으로 연결되어 파일 서버나 프린터 같은 공유 서비스와 결합된 완전한 네트워크화된 작업 공간을 만들었습니다. 핵심 교훈은 사람들이 실제로 종일 쓰는 종단간 시스템을 만들고 관찰할 때만 진짜 문제가 보인다는 점입니다—이름 붙이기, 과부하, 캐싱, 실패, 보안 등이 피할 수 없는 현실로 드러납니다.
클라이언트/서버 사고방식은 여전히 유효한 실용적 분할을 촉진했습니다: 지연에 민감한 상호작용은 로컬에서(UI, 편집, 렌더링 등) 처리하고, 공유되거나 권위가 필요한 상태(파일, 신원, 협업, 정책)는 서비스 쪽에 둡니다. 설계 목표는 로컬에서 빠른 반응성과 네트워크가 느리거나 불안정할 때의 일관된 전역 동작을 동시에 만족시키는 것입니다.
네트워크가 더 이상 배경 요소가 아니라 일급 의존성이 되기 때문입니다. 많은 머신이 공유 매체를 쓰고 서비스들이 빈번히 통신하면 다음을 가정해야 합니다:
실용적 기본값은: 초기에 계측(로그·기본 메트릭·트레이싱), 타임아웃 기본 사용, 백오프를 동반한 신중한 재시도입니다.
서비스로 쪼개면 명확성과 독립적 진화가 쉬워집니다: 각 서비스는 집중된 목적과 정의된 인터페이스를 갖습니다. 비용은 네트워크 홉 증가와 부분적 장애 모드의 도입입니다. 따라서 계약과 신뢰성(타임아웃, 재시도, 사용자에게 보이는 오류 동작)에 대한 규율이 필요합니다.
RPC는 원격 연산을 마치 로컬 함수 호출처럼 보이게 하지만, 좋은 RPC는 네트워크 현실을 명시적으로 반영합니다. 실무적으로 필요한 것:
이런 요소가 없으면 RPC는 ‘로컬처럼 보이니 원격임을 잊게 만드는’ 취약한 설계를 유도합니다.
타임아웃과 응답 손실 때문에 재시도는 불가피하고, 재시도는 작업을 중복시킬 수 있습니다. 그래서 멱등성이 중요합니다:
orderId) 중심으로 설계결제, 프로비저닝, 알림 전송 같은 동작에서 특히 중요합니다.
이름이 위치와 결합되어 있으면(예: 하드코딩된 IP/호스트/경로) 마이그레이션과 장애가 사용자에게 즉시 노출됩니다. 안정적인 이름을 변하는 위치와 분리하고, 디렉터리나 디스커버리 시스템을 사용해 “지금 X는 어디에 있나?”를 묻도록 하세요. 응답은 TTL 같은 명확한 신선도 규칙으로 클라이언트가 캐시하도록 합니다.
캐싱은 가장 쉬운 성능 향상 수단이지만, 오래된 캐시로 인한 일관성 문제가 생깁니다. 일반적 통제 수단:
핵심은 각 데이터에 대해 “충분히 신선한” 것이 무엇인지 문서화해 두는 것입니다.
케이퍼빌리티(권한 토큰)는 특정 리소스나 연산에 대한 위조 불가능한 토큰입니다. 신원+ACL 방식과 달리, 분산 시스템에서 위임과 최소 권한을 자연스럽게 구현하기 쉽습니다:
현대적 유사물로는 OAuth 액세스 토큰, 범위가 제한된 클라우드 자격 증명, 서명된 URL/JWT 등이 있습니다(주의해서 사용).