네트워크 역사 — ARPANET에서 TCP/IP까지, 인터넷이 왜 이렇게 생겼는가

10년 넘게 TCP/IP 스택 위에서 서비스를 만들면서 “왜 이게 이렇게 동작하지?”라는 질문을 자주 했다.

왜 TCP는 연결을 맺는 데 3번 악수를 해야 하는가. 왜 IP와 TCP가 분리되어 있는가. 왜 인터넷은 중앙 서버가 없어도 돌아가는가.

이 질문들의 답이 역사에 있다. 설계자들이 어떤 문제를 풀려고 이 구조를 선택했는지를 알면 현재의 동작 방식이 이해된다.


인터넷이 처음에 어떻게 생겼나?

1969년 10월 29일.

UCLA의 컴퓨터에서 Stanford Research Institute(SRI)로 첫 메시지가 전송됐다. 메시지는 “LOGIN” — 그런데 시스템이 “LO”를 받고 나서 멈췄다.

역사상 첫 인터넷 메시지는 “LO”다.

ARPANET(Advanced Research Projects Agency Network) — 미국 국방부 고등연구소(DARPA)가 자금을 댔다. 목적은 분산된 연구 기관들 사이에 컴퓨팅 자원을 공유하는 것이었다. UCLA, UCSB, SRI, 유타 대학교 — 초기 4개 노드로 시작했다.

이 네트워크가 지금의 인터넷의 직접 조상이다. 하지만 둘은 같지 않다. ARPANET은 하나의 네트워크였고, 인터넷(Internet)은 네트워크들의 네트워크다. 이 차이가 나중에 TCP/IP의 계층 분리로 이어진다.

1971년 Ray Tomlinson이 ARPANET에서 최초의 이메일을 보냈다. @ 기호를 사용자 이름과 호스트를 구분하는 구분자로 처음 도입한 것도 그다.


당시 통신이 전화처럼 회선 교환이었다면 어떤 문제가 있었나?

전화망은 회선 교환(Circuit Switching) 방식이다.

서울에서 부산으로 전화를 걸면, 서울 교환기 → 대전 교환기 → 부산 교환기 → 수신자로 이어지는 전용 경로가 만들어진다. 통화 내내 이 경로는 나만의 것이다. 아무 말 안 해도, 침묵이 계속돼도 회선이 점유된다.

세 가지 문제:

첫째, 낭비. 전화 통화의 40%는 침묵이다. 그 시간 동안 회선은 다른 사람이 쓸 수 없다.

둘째, 취약성. 특정 교환기나 회선이 고장나거나 전쟁으로 파괴되면? 그 경로를 쓰던 통신이 전부 끊긴다. 우회 경로가 없다.

셋째, 독점. 한 연결이 회선 전체를 독점한다. 서울-부산 회선을 내가 쓰는 동안 다른 사람은 같은 회선을 못 쓴다.

ARPANET 설계자들은 처음부터 이 방식을 선택하지 않았다.


그래서 패킷 교환이 나온 거다

패킷 교환(Packet Switching) — 1960년대 폴 바란(RAND Corporation)과 도널드 데이비스(영국 NPL)가 독립적으로 개념을 발전시켰다.

핵심 아이디어: 데이터를 작은 패킷으로 나눠서 각각 독립적으로 보내라.

전송할 데이터: "안녕하세요. 오늘 날씨가 좋네요."

패킷으로 분할:
  패킷 1: [헤더: 출발지/목적지/순번] + "안녕하세요."
  패킷 2: [헤더: 출발지/목적지/순번] + " 오늘 날씨가"
  패킷 3: [헤더: 출발지/목적지/순번] + " 좋네요."

각 패킷이 독립적으로 네트워크를 통해 전송됨
→ 다른 경로를 통해 도착할 수도 있음
→ 수신측에서 순번 순서대로 재조립

전용 경로가 필요 없다. 패킷마다 다음 목적지가 있고, 중간 노드(라우터)가 받아서 목적지 방향으로 전달한다. 여러 통신이 같은 물리 링크를 공유한다.

고장 허용(Fault Tolerant) 특성:

회선 교환:
A ─── 교환기 ─── B
이 교환기가 고장나면? A와 B 통신 불가.

패킷 교환:
A ─ 라우터1 ─ 라우터2 ─ B
      │                   │
    라우터3 ─ 라우터4 ─────┘

라우터1이 고장나면?
→ 패킷이 라우터3 경로로 자동 우회
→ A와 B는 계속 통신 가능

이 설계 철학이 지금의 인터넷에 그대로 살아있다. BGP(Border Gateway Protocol) 라우팅이 이 분산 경로 선택을 실현한다. 인터넷의 일부가 끊겨도 나머지 경로로 패킷이 흐른다.

“핵전쟁 대비 설계”라는 말은 절반만 맞다. 폴 바란이 1964년 RAND 보고서에서 분산 네트워크의 생존성을 핵전쟁 시나리오로 설명했지만, ARPANET의 직접 설계 동기는 아니었다. 하지만 결과적으로 그 특성을 갖게 됐다.


초기 프로토콜(NCP)의 문제가 뭐였나?

초기 ARPANET은 **NCP(Network Control Protocol)**를 사용했다. 1970년에 표준화됐다.

NCP로 이메일을 보내고, 파일을 전송하고, 원격으로 접속했다. 작동은 했다.

그런데 세 가지 한계가 있었다:

첫째 — ARPANET 전용

NCP는 ARPANET이라는 하나의 네트워크를 가정했다. 다른 종류의 네트워크(패킷 라디오 네트워크, 위성 네트워크)와 연결하는 방법이 없었다. ARPANET 노드끼리만 통신할 수 있었다.

둘째 — 호스트 번호 체계 고정

NCP의 주소는 ARPANET 노드 번호 기반이었다. 다른 네트워크에는 다른 번호 체계가 있었다. 서로 다른 네트워크를 연결할 방법이 없었다.

셋째 — 신뢰성을 네트워크에 의존

NCP에서 신뢰성(전송 보장, 오류 복구)은 네트워크 내부에서 처리했다. 이 가정은 네트워크가 하나일 때만 통했다. 여러 네트워크를 연결하면 네트워크 간 인터페이스에서 신뢰성이 깨졌다.

1974년 빈턴 서프(Vint Cerf)와 로버트 칸(Bob Kahn)이 논문을 발표했다. “A Protocol for Packet Network Intercommunication”. 여기서 완전히 새로운 접근법을 제시했다.


TCP와 IP가 왜 두 개로 나눠졌나?

처음에는 TCP와 IP가 하나의 프로토콜이었다.

빈턴 서프와 로버트 칸이 제안한 초기 TCP는 패킷 라우팅(IP 기능)과 신뢰성 전송(TCP 기능)을 모두 담고 있었다.

그런데 1978년 존 포스텔(Jon Postel)이 분리를 제안했다. 당시 패킷 라디오 실험에서 군사 통신 프로토콜이 필요했다. 신뢰성 오버헤드 없이 빠른 전송이 필요한 상황이었다. TCP의 재전송, 순서 보장을 다 해야 하는 건 아니었다.

분리 후:

IP (Internet Protocol):
→ 패킷을 어떻게 목적지까지 라우팅할 것인가
→ 신뢰성, 순서 보장 없음 (Best Effort)
→ 어떤 상위 프로토콜도 IP 위에서 동작 가능

TCP (Transmission Control Protocol):
→ IP 위에서 신뢰성 있는 연결 지향 통신
→ 재전송, 순서 보장, 흐름 제어, 혼잡 제어

UDP (User Datagram Protocol):
→ IP 위에서 비연결형 통신
→ 신뢰성 없음, 오버헤드 최소화
→ DNS, 실시간 스트리밍, 게임에 적합

이 계층화가 **엔드투엔드 원칙(End-to-End Principle)**의 핵심 구현이다.

“네트워크는 패킷만 전달하라. 지능은 양 끝단에 있어라.”

이 원칙 덕분에 Ethernet, WiFi, 4G, 광섬유 — 어떤 물리 네트워크 위에서도 TCP/IP가 동작한다. 물리 계층이 바뀌어도 IP는 그대로다. IP가 바뀌어도 TCP는 그대로다.


1983년 Flag Day — 하루아침에 모든 호스트가 프로토콜을 바꾼 게 어떻게 가능했나?

1983년 1월 1일, Flag Day.

역사상 가장 과감한 네트워크 전환이다.

ARPANET에 연결된 모든 호스트가 NCP에서 TCP/IP로 전환했다. 이 날을 기점으로 NCP 패킷은 더 이상 처리되지 않았다. 하룻밤 사이에 프로토콜 스택을 완전히 교체했다.

가능했던 이유:

첫째, 규모가 작았다. 당시 ARPANET 노드는 400개 미만이었다. 지금 같은 수십억 기기였다면 불가능했다.

둘째, 중앙 관리 구조. ARPANET은 DARPA가 관리하는 단일 조직의 네트워크였다. 참여 기관에 전환 명령을 내릴 수 있었다.

셋째, 긴 준비 기간. TCP/IP 개발은 1970년대부터였다. 1980년부터 NCP와 TCP/IP를 병행 운영하며 준비했다. Flag Day는 마지막 커트라인이었다.

넷째, 4.2 BSD의 TCP/IP 내장. 1983년 릴리즈된 4.2 BSD Unix에 TCP/IP 스택이 내장됐다. Unix 워크스테이션 교체만으로 전환이 됐다.

현대에는 절대 불가능하다.

IPv6 전환이 1990년대부터 진행 중인데 아직도 IPv4가 더 많이 쓰이는 이유가 여기에 있다. 수십억 기기가 연결된 네트워크에서 “내일부터 프로토콜 바꿔”는 불가능하다. Flag Day는 다시 없다.


DNS가 왜 나왔나? hosts.txt 파일로 관리하다 어떤 혼란이 생겼나?

초기 ARPANET에서 호스트 이름은 HOSTS.TXT 파일 하나로 관리했다.

Stanford Research Institute(SRI)가 이 파일을 중앙에서 관리했다. 모든 기관이 FTP로 최신 버전을 받아 썼다.

호스트가 수백 개일 때는 괜찮았다.

1980년대 초, 호스트가 수천 개로 늘어나자 동시에 여러 문제가 터졌다.

  • HOSTS.TXT 파일이 수 메가바이트가 됐다. 매일 받아도 이미 낡은 정보였다
  • SRI 서버 하나에 수천 기관이 FTP 요청을 보냈다. 서버가 병목이었다
  • 기관마다 맘대로 이름을 짓다 보니 같은 이름이 여러 곳에 생겼다
  • 새 호스트가 추가되면 전파에 며칠이 걸렸다

그래서 1983년 DNS가 나왔다.

Paul Mockapetris가 RFC 882/883으로 설계했다. 핵심은 두 가지다.

분산 데이터베이스 — 계층적으로 나눠서 각 부분을 해당 조직이 관리한다. naver.com의 IP는 Naver가 직접 관리한다. 중앙 서버가 모든 걸 들고 있지 않는다.

캐싱 — TTL로 유효 기간을 제어하고, 자주 조회되는 결과를 가까운 서버에 캐시한다. 모든 쿼리가 권위 서버까지 갈 필요가 없다.

/etc/hosts는 지금도 모든 OS에 살아있다. DNS보다 먼저 확인된다. hosts.txt의 흔적이 50년 뒤에도 남아있는 것이다. 로컬 개발에서 127.0.0.1 my-service.local을 쓰는 것도 같은 원리다.


WWW가 인터넷이랑 다른 건가?

이 혼동이 엄청나게 흔하다.

인터넷(Internet) — 전 세계 컴퓨터들을 연결하는 네트워크 인프라다. TCP/IP 프로토콜로 통신한다.

WWW(World Wide Web) — 인터넷 위에서 동작하는 하나의 서비스다. HTTP 프로토콜로 하이퍼텍스트 문서를 주고받는다.

인터넷 (1969~)
├── 이메일 (SMTP, 1971~)
├── FTP (1971~)
├── Telnet (1969~)
├── Usenet (1980~)
├── IRC (1988~)
└── WWW (1989~) ← 인터넷의 부분집합, 인터넷이 아님

인터넷이 없으면 WWW는 없다. 하지만 인터넷은 WWW 없이도 존재한다.

1989년 팀 버너스-리(Tim Berners-Lee)가 CERN에서 WWW를 제안했다. 제목은 “Information Management: A Proposal”이었다. 상사 Mike Sendall은 제안서에 “Vague but exciting”이라고 메모를 남겼다.

1991년 8월 6일, 첫 웹 서버(NeXT 컴퓨터)와 첫 웹 사이트(http://info.cern.ch)가 공개됐다.

1993년 모자이크(Mosaic) 브라우저가 이미지를 텍스트와 함께 표시하면서 웹이 폭발적으로 성장했다. 이때부터 일반인들이 “인터넷을 쓴다”고 하면 사실상 “WWW를 쓴다”를 의미하게 됐다. 혼동의 시작이다.


HTTP가 0.9에서 3까지 어떻게 진화했나?

HTTP는 실제 사용 중에 발생한 불편함을 해결하며 진화했다. 각 버전이 해결한 실제 문제가 핵심이다.

HTTP/0.9 (1991) — 단순함의 극치:

요청: GET /page.html

응답: <html>...</html>
     (연결 종료)

GET 메서드만. 응답은 HTML만. 상태 코드, 헤더 없음. 요청마다 TCP 연결을 새로 맺고 끊었다.

HTTP/1.0 (1996) — 헤더와 상태 코드:

요청: GET /image.jpg HTTP/1.0
      User-Agent: Mozilla/1.0

응답: HTTP/1.0 200 OK
      Content-Type: image/jpeg
      Content-Length: 12345
      [이미지 바이너리]

헤더, 상태 코드, 다양한 Content-Type 지원. 하지만 여전히 요청마다 TCP 연결을 새로 맺었다. 페이지 하나에 리소스가 수십 개면 수십 번의 TCP handshake가 발생했다.

HTTP/1.1 (1997) — 연결 재사용:

해결한 문제: 요청마다 TCP 연결을 새로 맺는 오버헤드. Connection: keep-alive로 연결을 재사용했다. Host 헤더가 필수가 됐다 — 하나의 서버에 여러 도메인을 운영할 수 있게 됐다(가상 호스팅).

남은 문제: Head-of-Line Blocking. 요청이 직렬이라 앞 요청이 느리면 뒤가 기다렸다. 브라우저가 같은 도메인에 6개 병렬 연결을 여는 편법이 생겼다.

HTTP/2 (2015) — 멀티플렉싱:

해결한 문제: HTTP/1.1의 HoL Blocking. 하나의 TCP 연결 위에 여러 스트림을 멀티플렉싱. HPACK으로 헤더 압축. 바이너리 프로토콜.

남은 문제: TCP 레벨 HoL Blocking. 패킷 하나가 유실되면 그 뒤 모든 스트림이 기다린다.

HTTP/3 (2022) — QUIC 기반:

해결한 문제: TCP의 HoL Blocking. UDP 기반 QUIC 프로토콜은 스트림별로 독립 재전송을 구현했다. QUIC은 TLS 1.3을 내장해서 연결 수립 오버헤드도 줄었다.

HTTP 버전별 특성 비교 (RTT 100ms, 리소스 100개 환경):

HTTP/1.1 (6 병렬 연결):
  6개 TCP 연결 수립 × 1 RTT + 순차 요청 → 수 초

HTTP/2 (1 연결, 멀티플렉싱):
  TCP 연결 수립 1 RTT + 병렬 요청 → 수백 ms

HTTP/3 (QUIC):
  0-RTT (재방문 시) + 병렬 요청
  패킷 손실 환경에서 특히 유리

이 역사를 이해하면 현재 기술이 어떻게 다르게 보이나?

1970~80년대에 만들어진 설계 원칙들이 2026년에도 그대로 유효하다.

엔드투엔드 원칙이 만들어주는 자유:

지금 내가 Spring Boot로 새 API를 만들 때 ISP에 “HTTP/2 써도 되나요?”라고 물을 필요가 없다. 응용 계층이 변해도 네트워크 계층은 그대로다. WWW를 만들 때 라우터 소프트웨어를 업데이트할 필요가 없었다. 비디오 스트리밍을 만들 때 네트워크 인프라를 바꿀 필요가 없었다.

계층화가 가능하게 하는 것:

Application (HTTP, gRPC, SMTP)
Transport   (TCP, UDP, QUIC)
Network     (IP, ICMP)
Data Link   (Ethernet, WiFi, 5G)
Physical    (광섬유, 구리선, 전파)

광섬유에서 5G로 바뀌어도 IP는 그대로다. IP에서 IPv6로 바뀌어도 TCP는 그대로다. TCP 위에서 HTTP/3으로 바뀌어도 애플리케이션은 거의 그대로다. QUIC도 UDP 위에서 신뢰성을 구현했다 — TCP를 바꾸지 않고.

TCP 3-way Handshake를 왜 없앨 수 없는가:

엔드투엔드 신뢰성 원칙의 귀결이다. 네트워크가 보장해주지 않으니 양 끝단이 서로 확인해야 한다. QUIC은 1-RTT 또는 0-RTT로 줄였지만 완전히 없앨 수는 없다.

왜 HTTP가 Stateless인가:

서버가 클라이언트 상태를 기억하면 서버가 중앙화되고 엔드투엔드 원칙이 깨진다. Stateless가 더 많은 서버로 수평 확장을 가능하게 한다. JWT, 세션 토큰이 Stateless HTTP 위에서 상태를 구현하는 방법이다.

DNS의 분산 설계:

“왜 하나의 중앙 서버로 통합하지 않나요?”라는 질문을 받기도 한다. 1970년대 HOSTS.TXT의 실패가 그 답이다. 중앙 집중은 단일 장애점이고 확장이 불가능하다.

50년 전 설계자들이 이 원칙들을 명확하게 정리하지 않았다면, 지금 우리가 쓰는 인터넷은 훨씬 복잡하고 경직된 구조였을 것이다. 역사를 이해하면 현재 시스템이 왜 이렇게 생겼는지가 보인다. 그리고 시스템을 이해하면 더 나은 서비스를 만들 수 있다.


최적화

역사적 관점에서 본 현재 스택 선택:

프로토콜탄생 이유현재 상황
TCP신뢰성 있는 데이터 전송HTTP/1.1, HTTP/2의 기반
UDP오버헤드 없는 빠른 전송DNS, QUIC(HTTP/3)의 기반
HTTP/1.1연결 재사용, 가상 호스팅레거시 시스템, 구형 클라이언트
HTTP/2멀티플렉싱, HPACK현재 주류
HTTP/3TCP HoL Blocking 해소채택 중 (CloudFront, Google 지원)

지금 당장 HTTP/3을 써야 하나?

Spring Boot 입장에서 HTTP/3은 로드 밸런서(ALB, CloudFront)가 처리한다. Spring Boot 자체는 HTTP/1.1이나 HTTP/2로 LB와 통신한다. 클라이언트-LB 구간 프로토콜은 AWS가 관리한다. Spring Boot 코드에서 할 일이 없다.


운영상 주의사항

프로토콜 호환성 문제

HTTP/2는 모든 클라이언트가 지원하지 않는다. 구형 안드로이드 앱, 내부 레거시 시스템, 일부 방화벽이 HTTP/2 트래픽을 차단한다. ALPN 협상으로 HTTP/1.1로 fallback되지만, 명시적으로 HTTP/1.1을 요구하는 클라이언트가 있을 수 있다.

DNS TTL과 배포

HOSTS.TXT 시대의 교훈이 지금도 유효하다. 분산 DNS 캐시 때문에 TTL 이내에 변경이 완전히 전파되지 않는다. 배포 전 TTL 단축 → 배포 → TTL 복구 사이클을 운영 절차에 넣어야 한다.

레이어별 장애 분리

장애가 발생했을 때 어느 계층인지 확인하는 것이 첫 번째 단계다.

  • DNS 조회 실패 → L7 이전 문제
  • TCP 연결 실패 → L4 문제
  • TLS 핸드쉐이크 실패 → TLS 레이어 문제
  • HTTP 5xx → L7 애플리케이션 문제

계층 모델을 이해하면 장애 원인 분리가 빨라진다.

# 단계별 연결 디버깅
dig www.example.com           # DNS 조회
curl -v telnet://example.com:443  # TCP 연결
openssl s_client -connect example.com:443  # TLS 핸드쉐이크
curl -v https://example.com   # HTTP 요청 전체