업데이트됨 1개월 전
당신의 스마트폰은 기본적으로 창문 같은 존재입니다. 그 창문을 통해 보이는 것들—이메일, 피드, 지도—은 전혀 다른 어딘가에 있습니다. 새로 고침을 눌렀을 때, 당신은 기기에서 데이터를 꺼내는 게 아닙니다. 수천 킬로미터 떨어진 데이터 센터의 컴퓨터에게 필요한 것을 보내달라고 요청하는 겁니다.
이것이 바로 클라이언트-서버 아키텍처입니다. 당신이 사용하는 거의 모든 네트워크 애플리케이션의 기반이 되는 패턴이죠. 이를 이해하면 앱이 왜 그런 방식으로 작동하는지, 왜 어떤 것들은 인터넷 연결이 필요하고 어떤 것들은 필요하지 않은지, 그리고 인터넷이 실제로 어떻게 돌아가는지 알 수 있습니다.
모든 것을 바꾼 분리
이 아키텍처가 주류가 되기 전, 조직들은 "더미 터미널"과 함께 메인프레임 컴퓨터를 사용했습니다. 터미널은 본질적으로 처리 능력이 없는 모니터와 키보드에 불과했죠. 모든 연산은 중앙 메인프레임에서 이루어졌습니다. 터미널은 다른 누군가의 컴퓨터를 들여다보는 창에 불과했습니다.
이 방식은 작동했지만, 치명적인 약점이 있었습니다. 메인프레임이 단일 장애점이었던 것입니다. 메인프레임이 다운되면 모두가 다운됐습니다. 업그레이드는 엄청나게 비싼 기계 하나를 교체하는 것을 의미했습니다. 사용자가 늘어날수록 그 기계는 더 많은 일을 해야 했습니다.
개인용 컴퓨터가 이 방정식을 바꿨습니다. 갑자기 사용자들은 책상 위에 진짜 컴퓨팅 파워를 갖게 됐습니다. 클라이언트-서버 아키텍처는 이 둘을 모두 활용하는 방식으로 등장했습니다. 로컬에서 처리하는 것이 합리적인 작업은 로컬에서, 공유가 필요한 것은 중앙에서.
클라이언트와 서버: 각자의 역할
클라이언트는 당신의 기기에서 실행되는 애플리케이션입니다. 웹 브라우저, 이메일 앱, 스마트폰의 앱들이 모두 클라이언트입니다. 이들은 당신이 보는 것과 어떻게 상호작용하는지를 담당합니다. 인터페이스를 렌더링하고, 입력을 받아들이고, 결과를 보여주죠. 검색어를 입력하거나 버튼을 탭할 때, 당신은 클라이언트와 상호작용하는 겁니다.
서버는 무대 뒤에서 무거운 작업을 처리하는 기계입니다. 요청을 처리하고, 데이터를 관리하고, 규칙을 적용하며, 사용자 간의 조율을 담당합니다. 검색 결과가 돌아오거나 메시지가 전달될 때, 그 일을 한 것은 서버입니다.
둘 사이의 약속은 단순합니다. 클라이언트가 묻고, 서버가 답합니다. 클라이언트는 서버가 어떻게 작업을 수행하는지 알 필요가 없습니다. 서버는 클라이언트가 어떻게 생겼는지 신경 쓰지 않습니다. 이 깔끔한 분리 덕분에 단일 서버가 웹 브라우저, 모바일 앱, 다른 서비스에서 오는 요청을 동시에 처리할 수 있습니다. 모두가 요청과 응답이라는 같은 언어로 대화하니까요.
요청의 여정
이메일을 확인할 때, 정교하게 조율된 대화가 펼쳐집니다.
- 이메일 클라이언트가 메일 서버에 요청을 보냅니다. "이 계정의 새 메시지를 주세요"
- 서버는 신원을 확인하고, 데이터베이스를 조회하며, 응답을 조합합니다
- 서버는 네트워크를 통해 메시지를 전송합니다
- 클라이언트가 메시지를 받아 화면을 갱신합니다
이 왕복 과정은 네트워크 상태에 따라 밀리초에서 몇 초가 걸릴 수 있지만, 패턴은 변하지 않습니다. 요청, 처리, 응답.
이 대화는 표준화된 프로토콜을 사용합니다. 웹 브라우저는 웹 서버와 HTTP로 대화합니다. 이메일 클라이언트는 메일 서버와 IMAP 또는 SMTP를 사용합니다. 이 프로토콜들은 어떤 클라이언트든 호환되는 서버와 대화할 수 있게 해주는 공용 언어입니다.
이 패턴이 승리한 이유
클라이언트-서버 아키텍처가 주류가 된 것은 실제 문제들을 우아하게 해결하기 때문입니다.
중앙화된 업데이트는 서버에서 버그를 고치거나 기능을 추가하면 모든 클라이언트가 즉시 혜택을 받는다는 뜻입니다. 수천 대의 기기에 소프트웨어를 업데이트할 필요가 없습니다.
데이터 일관성은 데이터가 주로 서버에 있을 때 관리하기 훨씬 쉬워집니다. 같은 문서를 보는 10명은 같은 버전을 봅니다. 서로의 변경사항이 조용히 덮어쓰이지 않습니다.
보안이 향상됩니다. 민감한 데이터가 통제된 환경에 있기 때문입니다. 데이터 센터의 서버는 카페의 노트북보다 훨씬 탈취하기 어렵습니다.
확장성이 단순해집니다. 더 많은 사용자를 처리해야 한다면? 서버를 추가하면 됩니다. 클라이언트는 전혀 바꿀 필요가 없습니다.
씬 클라이언트와 팻 클라이언트: 로컬에서 얼마나 처리할까
모든 클라이언트가 같은 방식으로 작동하지는 않습니다. 클라이언트와 서버 사이의 분업은 달라질 수 있습니다.
씬 클라이언트는 로컬에서 최소한의 작업만 합니다. 기본적인 웹 페이지는 씬 클라이언트입니다. 브라우저는 서버가 보내는 것을 렌더링할 뿐, 실제 로직은 모두 원격에서 실행됩니다. 업데이트가 쉬워지지만 항상 연결이 필요합니다.
팻 클라이언트는 기기에서 상당한 처리를 담당합니다. 많은 모바일 앱들은 데이터를 로컬에 저장하고, 오프라인에서도 작동하며, 주기적으로만 서버와 동기화합니다. 응답성이 좋고 오프라인 사용이 가능하지만, 동기화가 더 복잡해집니다.
대부분의 현대 애플리케이션은 그 사이 어딘가에 있으며, 각 기능에 맞는 적절한 분업을 선택합니다.
서버는 하나의 기계가 아니다
실제 애플리케이션은 단일 서버에서 실행되지 않습니다. 클라이언트 입장에서 "서버"처럼 보이는 것은 실제로 함께 작동하는 여러 특화된 기계들입니다.
- 로드 밸런서가 여러 서버에 요청을 분산합니다
- 웹 서버가 HTTP를 처리하고 정적 파일을 제공합니다
- 애플리케이션 서버가 비즈니스 로직을 실행합니다
- 데이터베이스 서버가 데이터를 저장하고 조회합니다
- 캐시 서버가 반복 요청의 속도를 높입니다
클라이언트는 이 복잡함을 보지 못합니다. 요청을 보내고 응답을 받을 뿐입니다. 하지만 그 단순한 인터페이스 뒤에서, 조율된 시스템이 작업을 처리하고 있습니다.
단순한 요청-응답을 넘어서
기본 패턴—클라이언트가 묻고, 서버가 답한다—은 대부분의 상호작용에 적합합니다. 하지만 어떤 애플리케이션은 더 많은 것을 필요로 합니다.
폴링은 클라이언트가 "새로운 게 있나요?"를 반복적으로 묻는 방식입니다. 단순하지만 변경사항이 없을 때는 낭비적입니다.
롱 폴링은 서버가 보낼 것이 생길 때까지 연결을 열어두어 불필요한 요청을 줄입니다.
WebSocket은 지속적인 양방향 연결을 만듭니다. 서버는 요청을 기다리지 않고 즉시 클라이언트에 업데이트를 푸시할 수 있습니다. 채팅이나 실시간 협업 같은 기능을 가능하게 하는 것이 바로 이것입니다.
이러한 변형들은 기본적인 클라이언트-서버 관계를 유지하면서 통신 방식을 적절히 조정한 것입니다.
상태 문제
웹의 기반 프로토콜인 HTTP는 무상태(stateless)입니다. 각 요청은 독립적이며, 이전 요청에 대한 기억이 없습니다. 이는 서버를 단순하고 확장 가능하게 만들지만, 애플리케이션은 연속성이 필요합니다. 로그인 상태가 유지되길 기대합니다. 장바구니가 남아있길 기대합니다.
해결책은 이렇습니다. 서버는 근본적으로 무상태를 유지하지만, 토큰, 쿠키, 세션 저장소를 사용해 기억이 있는 것처럼 보이게 합니다. 클라이언트는 각 요청과 함께 토큰을 보냅니다. 서버는 그 토큰으로 세션을 조회합니다. 내부는 무상태, 겉으로는 유상태입니다.
앞으로의 방향
클라이언트-서버 아키텍처는 계속 유지되지만, 구현 방식은 계속 진화하고 있습니다.
마이크로서비스는 서버 측을 서로 통신하는 작은 서비스들로 분해합니다. 클라이언트 입장에서는 변화가 없지만, "서버"는 이제 분산 시스템이 됩니다.
엣지 컴퓨팅은 서버 로직을 사용자에 더 가깝게 가져옵니다. 하나의 중앙 위치가 아니라 세계 각지의 데이터 센터에서 코드를 실행합니다.
서버리스는 서버 관리를 완전히 추상화합니다. 개발자는 아래의 기계에 대해 신경 쓰지 않고 클라우드에서 실행되는 함수를 작성합니다.
패턴은 그대로입니다. 클라이언트가 요청하고, 서버가 응답합니다. 하지만 서버는 점점 더 정교해지고, 더 분산되며, 더 보이지 않게 됩니다.
클라이언트-서버 아키텍처에 관한 자주 묻는 질문
클라이언트-서버와 P2P(피어-투-피어)의 차이점은 무엇인가요?
클라이언트-서버에서는 역할이 고정됩니다. 클라이언트가 요청하고 서버가 제공합니다. P2P에서는 모든 참여자가 클라이언트이자 서버가 될 수 있으며, 서로 직접 자원을 공유합니다. BitTorrent는 P2P, Netflix는 클라이언트-서버입니다. 대부분의 애플리케이션이 클라이언트-서버를 사용하는 것은 관리, 보안, 확장이 더 쉽기 때문입니다.
왜 어떤 앱은 오프라인에서도 작동하고 어떤 앱은 그렇지 않나요?
클라이언트 측에서 얼마나 많은 처리를 담당하느냐에 달려있습니다. 데이터를 로컬에 저장하고 기기에서 로직을 처리하는 앱은 오프라인에서도 작동하며, 연결이 되면 동기화합니다. 서버 측 처리에 전적으로 의존하는 앱은 모든 작업에 연결이 필요합니다. 설계자들은 어떤 트레이드오프를 감수할지에 따라 선택합니다.
클라우드는 그냥 클라이언트-서버 아키텍처인가요?
본질적으로, 그렇습니다. "클라우드"는 직접 운영하는 대신 인터넷을 통해 접근하는 서버를 가리키는 마케팅 용어입니다. 기본 패턴—기기가 클라이언트, 원격 기계가 서버—은 동일합니다. 바뀐 것은 누가 그 서버들을 소유하고 운영하는지입니다.
왜 모든 것을 그냥 내 기기에서 실행할 수 없나요?
어떤 것들은 가능하지만, 중앙화는 로컬만으로는 해결할 수 없는 문제들을 해결합니다. 공유 데이터는 하나의 일관된 원본이 필요합니다. 보안에 민감한 작업들은 통제된 환경이 필요합니다. 연산 집약적 작업들은 스마트폰이 갖추지 못한 처리 능력이 필요합니다. 그리고 업데이트는 한 곳만 변경하면 되니 훨씬 쉬워집니다.
이 페이지가 도움이 되었나요?