High Performance Browser Networking

high-performance-browser-networking-cover.png

High Performance Browser Networking Korean book cover

Ilya Grigorik의 _High Performance Browser Networking_을 네트워크 기초, 무선 네트워크, HTTP, 브라우저 API 흐름으로 한 페이지에 정리한 문서입니다.

한눈에 보는 전체 구조

  • Part 1: 레이턴시, 대역폭, TCP, UDP, TLS처럼 웹 성능의 하위 기반을 정리합니다.
  • Part 2: 와이파이와 모바일 네트워크의 물리적 한계, 배터리 비용, 최적화 패턴을 다룹니다.
  • Part 3: HTTP의 진화, 웹 성능 지표, HTTP 1.x의 한계, HTTP 2.0의 개선점을 정리합니다.
  • Part 4: 브라우저가 제공하는 네트워킹 API인 XHR, SSE, WebSocket, WebRTC를 비교합니다.

목차

  • Part 1. Networking Primer
    • 1부 1장. 레이턴시와 대역폭
    • 1부 2장. TCP의 구성요소
    • 1부 3장. UDP의 구성요소
    • 1부 4장. 전송 계층 보안 TLS
  • Part 2. Wireless Networks
    • 2부 1장. 무선 네트워크 소개
    • 2부 2장. WiFi
    • 2부 3장. 모바일 네트워크
    • 2부 4장. 모바일 네트워크 최적화
  • Part 3. HTTP
    • 3부 1장. HTTP의 역사
    • 3부 2장. 웹 성능 이해의 첫걸음
    • 3부 3장. HTTP 1.x
    • 3부 4장. HTTP 2.0
    • 3부 5장. 애플리케이션 전송 최적화
  • Part 4. Browser APIs
    • 4부 1장. 브라우저 네트워킹의 첫걸음
    • 4부 2장. XMLHttpRequest
    • 4부 3장. Server-Sent Events
    • 4부 4장. WebSocket
    • 4부 5장. WebRTC

Part 1. Networking Primer

1부 1장. 레이턴시와 대역폭

웹 성능 최적화의 출발점은 네트워크 트래픽을 좌우하는 두 축인 레이턴시와 대역폭을 이해하는 것이다. 대역폭은 더 많은 링크와 장비 투자로 확장할 수 있지만, 레이턴시는 물리적 거리와 빛의 속도라는 한계에 강하게 묶여 있다.

핵심 개념

레이턴시의 구성요소

메시지가 클라이언트와 서버 사이를 이동할 때의 총 지연은 여러 요소의 합이다.

  • 전파 지연: 신호가 송신지에서 수신지까지 이동하는 데 걸리는 시간이다. 거리와 매체의 물리적 특성에 의해 결정된다.
  • 전송 지연: 패킷의 모든 비트를 링크 위로 내보내는 데 걸리는 시간이다. 링크의 데이터 전송률, 즉 대역폭의 영향을 받는다.
  • 프로세싱 지연: 라우터나 장비가 패킷 헤더를 읽고 목적지를 판단하고 오류를 확인하는 데 걸리는 시간이다.
  • 큐잉 지연: 패킷이 라우터의 버퍼에서 처리 순서를 기다리는 시간이다. 혼잡할수록 커진다.

빛의 속도와 최종 마일

전파 지연은 빛의 속도라는 물리적 한계에 종속된다. 광섬유 안의 신호도 진공 속 빛보다 느리며, 거리가 멀어질수록 전파 지연과 라우팅 과정의 지연이 누적된다.

웹 성능에서 자주 문제가 되는 구간은 사용자의 집이나 사무실에서 ISP 라우터까지 이어지는 최종 마일이다. 이 짧아 보이는 구간에서 높은 레이턴시, 혼잡, 장비 품질 차이가 크게 드러난다.

대역폭과 레이턴시의 차이

대역폭은 광섬유 증설, 파장 분할 다중화 같은 방식으로 늘릴 수 있다. 반면 레이턴시는 물리적 거리와 매체의 한계를 넘어 획기적으로 줄이기 어렵다.

따라서 고성능 웹 애플리케이션은 레이턴시를 없애려 하기보다 감추고 줄이는 방식으로 설계해야 한다.

최적화 방향

  • 사용자의 물리적 위치와 가까운 곳에 콘텐츠를 배치한다.
  • CDN을 사용해 왕복 거리를 줄인다.
  • 캐싱으로 반복 요청을 제거한다.
  • 프리페칭으로 사용자가 필요로 하기 전에 데이터를 준비한다.
  • 요청 수와 왕복 횟수를 줄이는 방향으로 애플리케이션을 설계한다.

복습 질문

  • 최종 마일 레이턴시는 왜 발생하는가?
  • CDN은 전파 지연 시간을 어떻게 줄이는가?
  • 라우터의 큐잉 지연은 어떤 상황에서 커지는가?

1부 2장. TCP의 구성요소

TCP는 신뢰할 수 없는 IP 네트워크 위에서 데이터의 순서, 무결성, 전달 신뢰성을 제공한다. 그러나 이 신뢰성을 얻기 위해 핸드셰이크, 흐름 제어, 혼잡 제어 같은 절차가 필요하며, 이 절차들이 웹 성능에 직접적인 영향을 준다.

핵심 개념

3-Way 핸드셰이크

모든 TCP 연결은 데이터를 보내기 전에 SYN, SYN ACK, ACK 과정을 거친다. 이 과정은 시퀀스 번호와 연결 상태를 동기화하기 위한 필수 절차다.

새 TCP 연결을 만들 때마다 애플리케이션 데이터 전송 전 최소 1 RTT가 추가된다. 그래서 웹 성능에서는 새 연결을 계속 만드는 것보다 기존 TCP 커넥션을 재사용하는 것이 중요하다.

흐름 제어

흐름 제어는 송신자가 수신자의 처리 능력을 넘어서 데이터를 보내지 않도록 막는다. 수신자는 리시브 윈도(rwnd)를 통해 자신이 받을 수 있는 버퍼 크기를 송신자에게 알린다.

초기 TCP 스펙은 윈도 크기를 64KB로 제한했지만, 고속 네트워크에서는 윈도 스케일링 옵션으로 더 큰 윈도를 사용할 수 있다.

느린 시작과 혼잡 회피

TCP는 네트워크 혼잡을 피하기 위해 처음부터 최대 속도로 전송하지 않는다. 새 연결이 만들어지면 작은 혼잡 윈도(cwnd)로 시작하고, ACK를 받을 때마다 전송량을 지수적으로 늘린다.

짧은 HTTP 요청이 많은 환경에서는 네트워크의 최대 대역폭에 도달하기 전에 전송이 끝날 수 있다. 이 때문에 느린 시작은 짧고 잦은 연결에서 성능 병목이 된다.

패킷 손실이 발생하면 TCP는 혼잡으로 판단하고 혼잡 윈도 크기를 줄인다. 이후 다시 천천히 전송량을 늘리며 네트워크 상태를 탐색한다.

대역폭 지연 곱

대역폭 지연 곱(BDP)은 링크의 대역폭과 RTT를 곱한 값이다. 한 번에 보낼 수 있는 데이터양이 BDP보다 작으면, 링크의 대역폭이 충분해도 최대 처리량에 도달하지 못한다.

실제 전송량은 rwnd와 cwnd 중 더 작은 값에 의해 제한된다.

Head-of-Line 블로킹

TCP는 순서를 보장하기 때문에 중간 패킷 하나가 손실되면, 그 뒤에 도착한 패킷들도 애플리케이션에 전달되지 못하고 대기한다. 이 현상이 TCP 계층의 Head-of-Line 블로킹이다.

순서가 중요하지 않은 실시간 오디오나 비디오에서는 이 특성이 지터와 레이턴시를 늘릴 수 있다.

최적화 방향

  • 기존 TCP 커넥션을 재사용한다.
  • 사용자와 서버 사이의 물리적 거리를 줄인다.
  • CDN을 활용해 RTT를 낮춘다.
  • 전송해야 할 데이터 크기를 줄인다.
  • 서버의 TCP 설정을 최신 상태로 유지하고 초기 cwnd를 적절히 조정한다.

복습 질문

  • TCP의 Head-of-Line 블로킹은 어떤 순서 보장 특성 때문에 발생하는가?
  • 3-Way 핸드셰이크의 비용을 줄이려면 애플리케이션에서 무엇을 해야 하는가?
  • 초기 cwnd가 짧은 웹 요청의 성능에 중요한 이유는 무엇인가?

1부 3장. UDP의 구성요소

UDP는 TCP와 달리 연결 상태, 재전송, 순서 보장, 혼잡 제어를 제공하지 않는 단순한 전송 프로토콜이다. 그 대신 가볍고 빠르며, 실시간 통신과 P2P 통신의 기반으로 자주 사용된다.

핵심 개념

널 프로토콜에 가까운 서비스

UDP는 IP 계층 위에 포트 번호와 체크섬을 더해 애플리케이션으로 데이터그램을 라우팅한다.

UDP가 제공하지 않는 기능은 다음과 같다.

  • 메시지 전달 보장
  • 순서 보장
  • 연결 상태 추적
  • 흐름 제어
  • 혼잡 제어
  • 자동 재전송

이 단순함 덕분에 UDP는 WebRTC 기반 음성, 화상, 게임, P2P 통신처럼 지연 시간이 중요한 환경에서 유리하다.

NAT와 타임아웃

NAT는 내부 사설 IP와 외부 공인 IP 사이의 변환 테이블을 유지한다. TCP는 연결 시작과 종료 절차가 있어 상태 추적이 비교적 쉽지만, UDP에는 그런 신호가 없다.

그래서 NAT 장비는 일정 시간이 지나면 UDP 변환 레코드를 삭제한다. UDP 애플리케이션은 연결을 유지하기 위해 주기적인 킵얼라이브 패킷을 보내야 할 수 있다.

NAT 통과 기술

P2P 통신에서는 NAT 뒤에 있는 피어들이 서로의 공인 주소와 포트를 알아야 한다.

  • STUN: 외부 서버를 통해 자신의 공인 IP와 포트를 알아내고 직접 연결을 시도한다.
  • TURN: 직접 연결이 불가능할 때 중계 서버가 데이터를 대신 전달한다.
  • ICE: STUN과 TURN 후보를 조합해 가장 효율적인 통신 경로를 찾는다.

최적화 방향

UDP는 단순하지만, 그만큼 애플리케이션이 책임져야 하는 것이 많다. 흐름 제어, 혼잡 회피, 순서 정렬, 재전송을 직접 설계해야 하며, 잘못 구현하면 네트워크 혼잡을 키울 수 있다.

따라서 새로운 전송 프로토콜을 직접 만드는 것보다 WebRTC처럼 이미 검증된 프레임워크를 활용하는 것이 안전하다.

복습 질문

  • STUN과 TURN의 차이는 무엇인가?
  • WebRTC가 TCP 대신 UDP를 사용하는 이유는 무엇인가?
  • UDP 애플리케이션에서 킵얼라이브가 필요한 이유는 무엇인가?

1부 4장. 전송 계층 보안 TLS

TLS는 인터넷 통신에 암호화, 인증, 무결성을 제공한다. 보안에는 필연적으로 핸드셰이크와 암호화 비용이 따르며, 성능 최적화의 핵심은 이 비용, 특히 레이턴시를 줄이는 것이다.

핵심 개념

TLS의 세 가지 서비스

  • 암호화: 제3자가 데이터를 읽지 못하도록 보호한다.
  • 인증: 통신 상대가 주장하는 신원의 실제 소유자인지 검증한다.
  • 무결성: 데이터가 전송 중 변경되거나 위조되지 않았음을 확인한다.

TLS 핸드셰이크

TLS 터널을 만들기 위해 클라이언트와 서버는 암호화 방식, 인증서, 키 교환 정보를 합의한다. 이 과정은 TCP 핸드셰이크 위에 추가 RTT를 만든다.

ALPN은 추가 왕복 없이 HTTP/2 같은 애플리케이션 프로토콜을 협상하게 해주고, SNI는 하나의 IP에서 여러 도메인의 인증서를 제공할 수 있게 한다.

세션 재개

TLS 세션 재개는 전체 핸드셰이크 비용을 줄이기 위한 메커니즘이다.

  • 세션 식별자: 서버가 세션 상태를 저장하고 클라이언트가 식별자를 제시해 재개한다.
  • 세션 티켓: 서버가 암호화된 세션 정보를 클라이언트에게 맡기고, 서버는 상태를 저장하지 않아도 된다.

신뢰 사슬과 인증서 폐기

브라우저는 루트 CA에서 중간 CA, 사이트 인증서로 이어지는 신뢰 사슬을 검증한다. 인증서가 폐기되었는지 확인하기 위해 CRL이나 OCSP를 사용할 수 있지만, 이 과정은 추가 네트워크 요청과 레이턴시를 만들 수 있다.

OCSP 스테이플링은 서버가 OCSP 응답을 미리 받아 클라이언트에게 함께 전달하게 하여 이 비용을 줄인다.

TLS 레코드

TLS 데이터는 레코드 단위로 나뉘어 전송된다. 레코드는 복호화와 무결성 확인이 끝나야 애플리케이션으로 전달된다. 레코드 크기가 너무 크면 모든 조각이 도착할 때까지 대기해야 하므로 지연이 생길 수 있다.

최적화 방향

  • 세션 캐싱과 세션 티켓을 활성화한다.
  • CDN이나 엣지 서버에서 TLS를 조기 종료해 RTT를 줄인다.
  • 초기 혼잡 윈도에 맞춰 TLS 레코드 크기를 조정한다.
  • OCSP 스테이플링을 적용한다.
  • HSTS를 사용해 HTTP에서 HTTPS로 가는 리다이렉트를 제거한다.
  • TLS 압축은 보안 취약점 때문에 비활성화한다.

복습 질문

  • HSTS는 HTTPS 리다이렉트 지연을 어떻게 줄이는가?
  • OCSP 스테이플링은 어떤 네트워크 요청을 줄이는가?
  • 세션 티켓과 세션 식별자는 서버 상태 관리 측면에서 어떻게 다른가?

Part 2. Wireless Networks

2부 1장. 무선 네트워크 소개

무선 네트워크는 와이파이, 블루투스, 셀룰러처럼 다양한 형태를 갖지만, 모두 전파라는 공유 매체와 물리적 한계의 영향을 받는다.

핵심 개념

무선 네트워크의 범위

  • PAN: 개인 영역 네트워크다. 블루투스와 NFC가 대표적이다.
  • LAN: 건물이나 구역 안의 네트워크다. 와이파이가 대표적이다.
  • MAN: 도시 단위 네트워크다. WiMAX 같은 기술이 여기에 속한다.
  • WAN: 넓은 지역 또는 전 세계 단위 네트워크다. 3G, LTE 같은 셀룰러 망이 대표적이다.

채널 용량

무선 통신의 최대 전송률은 채널 용량 공식의 제약을 받는다. 핵심 변수는 대역폭과 신호 대 잡음비(SNR)다.

대역폭이 늘면 전송률도 늘 수 있지만, 무선 주파수는 정부 규제를 받는 제한된 자원이다. 따라서 무한정 늘릴 수 없다.

신호 강도와 잡음

무선 성능은 신호 강도와 잡음의 영향을 크게 받는다.

  • 패스 로스: 거리가 멀어질수록 신호 강도가 감소한다.
  • 근거리/원거리 문제: 가까운 강한 신호가 먼 약한 신호를 방해한다.
  • 셀 호흡: 잡음과 사용자 수가 늘어날수록 커버리지가 줄어든다.

변조

변조는 디지털 데이터를 아날로그 전파 신호에 싣는 과정이다. 고차 변조는 한 번의 신호에 더 많은 비트를 담을 수 있지만, 높은 SNR이 필요하다.

실전 관점

기술 스펙의 최대 전송률은 이상적인 환경에서의 값이다. 실제 환경에서는 거리, 장애물, 간섭, 사용자 수, 장비 상태 때문에 체감 처리량이 크게 낮아진다.

복습 질문

  • 무선 통신의 물리적 한계 요인은 무엇인가?
  • 신호 대 잡음비가 높아야 고차 변조를 사용할 수 있는 이유는 무엇인가?
  • 기술 스펙의 최대 속도와 실제 속도는 왜 다른가?

2부 2장. WiFi

와이파이는 전파를 여러 기기가 공유하는 반이중 네트워크다. 유선 이더넷과 달리 충돌 감지가 어렵기 때문에 충돌 회피와 링크 계층 재전송이 성능에 큰 영향을 준다.

핵심 개념

반이중 공유 채널

와이파이는 한 번에 한 기기만 데이터를 전송할 수 있다. 여러 기기가 같은 채널을 공유하기 때문에 접속 기기가 많을수록 대기 시간이 늘고 처리량은 낮아진다.

CSMA/CA는 송신 전 채널이 비어 있는지 확인하고, 임의의 대기 시간을 둔 뒤 전송하는 충돌 회피 방식이다.

2.4GHz와 5GHz

2.4GHz 대역은 도달 거리가 길고 장애물 통과에 유리하지만, 겹치지 않는 채널이 적고 간섭이 많다. 일반적으로 1, 6, 11번 채널만 독립적으로 사용하기 좋다.

5GHz 대역은 더 넓은 대역폭과 더 많은 비중첩 채널을 제공해 간섭이 적고 빠르다. 대신 도달 거리가 짧고 장애물 통과 성능이 낮다.

링크 계층 재전송

무선 환경은 신호 약화와 간섭으로 패킷 손실이 자주 발생한다. TCP는 손실을 혼잡으로 해석해 전송률을 줄이므로, 와이파이는 링크 계층에서 프레임 ACK와 재전송으로 손실을 흡수한다.

이 덕분에 애플리케이션은 손실을 덜 느끼지만, 재전송이 발생할 때 첫 홉 레이턴시와 지터가 증가한다.

최적화 방향

  • 대용량 다운로드와 백업은 가능하면 와이파이에서 수행한다.
  • 고정 품질을 고집하지 말고 네트워크 상태에 따라 적응형 비트레이트를 사용한다.
  • 5GHz 사용, 채널 조정, AP 위치 조정으로 간섭과 패스 로스를 줄인다.
  • 와이파이 환경의 처리량과 레이턴시는 계속 변한다고 가정하고 애플리케이션을 설계한다.

복습 질문

  • 와이파이가 반이중 링크로 동작하는 이유는 무엇인가?
  • 2.4GHz와 5GHz는 어떤 장단점이 있는가?
  • 링크 계층 재전송은 왜 TCP 성능 보호에 도움이 되는가?

2부 3장. 모바일 네트워크

모바일 네트워크는 와이파이나 유선망보다 구조가 복잡하고, 배터리 절약을 위한 상태 전환 메커니즘이 성능에 큰 영향을 준다.

핵심 개념

세대별 진화

1G와 2G를 거쳐 3G에서 본격적인 데이터 통신이 가능해졌고, LTE는 All IP 네트워크 구조를 통해 더 높은 처리량과 낮은 제어영역 레이턴시를 목표로 발전했다.

RRC 상태 기계

RRC는 모바일 기기와 기지국 사이의 무선 자원과 배터리 사용을 제어한다.

  • Idle: 기기가 저전력 상태에 있고 라디오 전력 소모가 낮다.
  • Connected: 기기가 고전력 상태에서 데이터를 송수신할 수 있다.

데이터를 보내려면 Idle에서 Connected로 전환해야 하며, 이 협상 과정이 초기 지연을 만든다.

상태 전환 레이턴시와 에너지 테일

상태 전환에는 제어영역 레이턴시가 발생한다. LTE에서는 보통 100ms 이하를 목표로 하지만, 3G에서는 수백 밀리초에서 수 초까지 걸릴 수 있다.

데이터 전송이 끝나도 기기는 즉시 저전력 상태로 돌아가지 않는다. 추가 데이터가 올 가능성에 대비해 일정 시간 고전력 상태로 머무르는데, 이를 에너지 테일이라고 한다.

복잡한 코어 네트워크

모바일 데이터는 기기에서 곧바로 인터넷으로 나가지 않는다. 무선 접속망, 통신사 코어 네트워크, 게이트웨이를 거쳐 외부 인터넷으로 향한다. 이 경로의 복잡성이 기본 레이턴시와 지터를 높인다.

최적화 방향

작은 데이터를 자주 보내는 패턴은 모바일에서 성능과 배터리에 모두 나쁘다. 매번 RRC 상태 전환과 에너지 테일을 유발하기 때문이다.

데이터는 가능하면 모아서 버스트 형태로 빠르게 전송하고, 이후 기기가 저전력 상태로 돌아갈 수 있게 해야 한다.

복습 질문

  • 모바일 배터리를 아끼는 전송 방식은 무엇인가?
  • RRC 상태 전환은 왜 초기 지연을 만드는가?
  • 모바일 코어 네트워크 구조는 왜 레이턴시를 높이는가?

2부 4장. 모바일 네트워크 최적화

모바일 최적화에서는 속도뿐 아니라 배터리 소모가 중요한 성능 지표다. 무선 전파를 활성화하는 일이 배터리 소모에 큰 영향을 주므로, 요청 패턴 자체를 신중히 설계해야 한다.

핵심 개념

폴링 줄이기

작은 요청을 주기적으로 보내는 폴링은 모바일 네트워크에서 매우 비효율적이다. 데이터가 없어도 라디오를 깨우고, 에너지 테일을 연장해 배터리를 낭비한다.

가능하면 클라이언트가 계속 묻는 방식보다 서버가 필요할 때 알려주는 푸시 방식이 낫다. SSE, WebSocket, 모바일 푸시 인프라 등을 상황에 맞게 사용할 수 있다.

버스트 전송

요청을 여러 번 나누어 보내면 매번 상태 전환과 대기 비용이 발생한다. 데이터를 모아 한 번에 빠르게 전송하면 라디오가 더 빨리 저전력 상태로 돌아갈 수 있다.

프리페칭도 라디오가 이미 켜져 있는 동안 필요한 리소스를 미리 받아둘 수 있어 효과적이다. 단, 사용 가능성이 낮거나 큰 리소스를 무분별하게 받으면 비용과 배터리를 낭비한다.

와이파이 오프로딩

모바일 데이터는 비용이 들고 RRC 전환 비용이 크다. 대용량 다운로드, 백업, 큰 미디어 프리페치는 가능하면 와이파이에 연결될 때까지 미루는 것이 좋다.

기본 프로토콜 최적화 병행

모바일 특화 최적화와 함께 기본 네트워크 최적화도 중요하다.

  • TCP 커넥션 재사용
  • TLS 세션 재개
  • DNS 룩업 최소화
  • HTTP 리다이렉션 제거
  • 전송 데이터 압축
  • CDN 활용

복습 질문

  • 모바일에서 폴링이 배터리에 나쁜 이유는 무엇인가?
  • 에너지 테일을 줄이기 위해 서버는 어떤 전송 패턴을 유도해야 하는가?
  • 와이파이 오프로딩이 적합한 작업은 무엇인가?

Part 3. HTTP

3부 1장. HTTP의 역사

HTTP는 단순한 하이퍼텍스트 전송 프로토콜에서 시작해, 현대 웹 애플리케이션을 위한 복잡하고 성능 중심적인 프로토콜로 발전했다.

핵심 개념

HTTP 0.9

HTTP 0.9는 HTML 문서를 전송하기 위한 매우 단순한 프로토콜이었다. 클라이언트가 한 줄짜리 GET 요청을 보내면 서버는 HTML 문서를 돌려주고 연결을 닫았다.

헤더, 상태 코드, 미디어 타입 같은 현대 HTTP 기능은 없었다.

HTTP 1.0

웹이 빠르게 성장하면서 HTML 외의 리소스, 상태 정보, 메타데이터가 필요해졌다. HTTP 1.0은 요청과 응답 헤더, 상태 코드, Content-Type을 도입했다.

이로써 이미지, 스크립트, 비디오 같은 다양한 리소스를 식별하고 전송할 수 있게 되었다.

HTTP 1.1

HTTP 1.1은 현대 웹의 중요한 기반이 되었다.

  • Keep-Alive: 하나의 TCP 연결을 여러 요청에 재사용한다.
  • Chunked Transfer-Encoding: 전체 길이를 모르는 동적 콘텐츠를 청크 단위로 스트리밍한다.
  • 개선된 캐싱 제어: 브라우저와 서버가 더 세밀하게 캐시를 관리한다.
  • 파이프라이닝: 응답을 기다리지 않고 여러 요청을 연속으로 보낼 수 있게 했다.

HTTP 2.0

웹 페이지가 수많은 리소스를 요구하게 되면서 HTTP 1.x의 전송 방식은 레이턴시 병목을 드러냈다. HTTP 2.0은 메서드, 상태 코드, 헤더 같은 의미 체계는 유지하면서 전송 계층을 재설계했다.

바이너리 프레이밍, 멀티플렉싱, 헤더 압축, 서버 푸시를 통해 더 낮은 레이턴시와 높은 처리량을 목표로 한다.

복습 질문

  • HTTP 1.1의 Keep-Alive는 어떤 비용을 줄이는가?
  • HTTP 1.0에서 헤더와 Content-Type이 중요한 이유는 무엇인가?
  • HTTP 2.0은 HTTP의 의미 체계와 전송 방식을 어떻게 분리했는가?

3부 2장. 웹 성능 이해의 첫걸음

웹 성능은 네트워크 전송 시간만의 문제가 아니다. 브라우저가 HTML, CSS, JavaScript를 처리하고 화면을 그리는 과정, 사용자의 시간 인지, 비즈니스 지표가 모두 연결되어 있다.

핵심 개념

브라우저 렌더링 파이프라인

브라우저는 HTML을 파싱해 DOM 트리를 만들고, CSS를 파싱해 CSSOM을 만든다. DOM과 CSSOM은 렌더 트리로 결합되고, 이후 레이아웃과 페인트 단계를 거쳐 화면에 표시된다.

JavaScript는 DOM과 CSSOM에 접근할 수 있기 때문에 파싱과 렌더링을 블로킹할 수 있다. 따라서 스크립트 크기, 로딩 방식, 실행 타이밍은 렌더링 성능에 큰 영향을 준다.

현대 웹 애플리케이션의 무게

현대 웹 페이지는 많은 이미지, CSS, JavaScript, 폰트, API 요청으로 구성된다. 리소스 수와 전송 크기가 늘수록 DNS, TCP, TLS, HTTP 요청 비용이 누적된다.

네트워크 최적화는 단순한 부가 작업이 아니라 사용자 경험의 기본 조건이 된다.

사용자의 시간 인지

사용자가 느끼는 속도는 절대 시간보다 반응성에 가깝다.

  • 0-100ms: 즉각 반응한다고 느낀다.
  • 100-300ms: 약간의 지연을 인지한다.
  • 300-1000ms: 시스템이 작업 중이라고 느낀다.
  • 1초 이상: 집중력이 흐트러지기 시작한다.
  • 10초 이상: 작업을 포기할 수 있다.

웹 성능의 경제적 가치

느린 페이지는 사용자 만족도, 페이지뷰, 전환율, 매출에 직접적인 악영향을 준다. 성능 개선은 단순한 기술 개선이 아니라 비즈니스 성과 개선이다.

최적화 방향

  • 렌더링을 막는 리소스를 줄인다.
  • 중요한 CSS와 JavaScript를 우선 처리한다.
  • 불필요한 요청을 제거한다.
  • 전송 크기를 줄이고 캐시를 적극 활용한다.
  • 사용자에게 빠르게 의미 있는 화면을 보여주는 지표를 우선한다.

복습 질문

  • JavaScript는 브라우저 렌더링 파이프라인에서 어떤 영향을 주는가?
  • 사용자가 1초 이상의 지연을 다르게 느끼는 이유는 무엇인가?
  • 웹 성능은 전환율과 어떤 관계가 있는가?

3부 3장. HTTP 1.x

HTTP 1.x는 지속 커넥션과 파이프라이닝 등 성능 개선을 도입했지만, 현대 웹처럼 리소스가 많은 환경에서는 구조적 한계를 드러냈다. 그 한계를 보완하기 위해 도메인 샤딩, 파일 결합, 스프라이팅, 인라이닝 같은 애플리케이션 계층의 최적화가 등장했다.

핵심 개념

Keep-Alive 커넥션

HTTP 1.1은 TCP 연결을 닫지 않고 여러 요청에 재사용한다. 이를 통해 매 요청마다 발생하던 TCP 핸드셰이크와 느린 시작 비용을 줄인다.

파이프라이닝과 HOL 블로킹

파이프라이닝은 이전 응답을 기다리지 않고 여러 요청을 연속으로 보내는 방식이다. 하지만 HTTP 1.x는 응답 순서를 지켜야 하므로 앞 요청이 늦어지면 뒤 요청도 함께 대기한다.

이 Head-of-Line 블로킹 때문에 파이프라이닝은 실제 브라우저에서 널리 활용되지 못했다.

다수 TCP 커넥션과 도메인 샤딩

브라우저는 병렬 다운로드를 위해 호스트당 여러 TCP 커넥션을 연다. 더 많은 병렬성을 얻기 위해 리소스를 여러 하위 도메인으로 나누는 도메인 샤딩도 사용되었다.

하지만 도메인 샤딩은 추가 DNS 룩업, 추가 TCP 연결, 느린 시작, 모바일 환경에서의 에너지 비용을 만든다. HTTP/2 환경에서는 오히려 성능을 해칠 수 있다.

결합, 스프라이팅, 인라이닝

HTTP 1.x에서 요청 수를 줄이기 위해 여러 리소스를 하나로 묶는 기법들이 사용되었다.

  • 결합: 여러 JS나 CSS 파일을 하나로 합친다.
  • 스프라이팅: 여러 작은 이미지를 하나의 이미지로 합친다.
  • 인라이닝: 작은 리소스를 HTML이나 CSS 안에 직접 넣는다.

이 기법들은 요청 수를 줄이지만, 캐시 효율 저하, 메모리 낭비, 불필요한 재다운로드, 파일 크기 증가 같은 비용이 있다.

헤더 오버헤드

HTTP 1.x 헤더는 압축되지 않은 텍스트다. 쿠키가 많은 요청에서는 실제 페이로드보다 헤더가 더 큰 오버헤드가 될 수 있다.

복습 질문

  • Keep-Alive는 어떤 네트워크 비용을 줄이는가?
  • HTTP 1.x 파이프라이닝이 HOL 블로킹에 취약한 이유는 무엇인가?
  • 도메인 샤딩은 왜 모바일에서 특히 조심해야 하는가?

3부 4장. HTTP 2.0

HTTP 2.0은 HTTP의 의미 체계는 유지하면서 전송 방식을 새로 설계했다. 핵심 목표는 HTTP 1.x의 요청 병렬성 한계, 헤더 오버헤드, Head-of-Line 블로킹 문제를 줄이는 것이다.

핵심 개념

바이너리 프레이밍 계층

HTTP 2.0은 텍스트 기반 전송 대신 바이너리 프레임을 사용한다.

  • 프레임: 전송의 가장 작은 단위다.
  • 메시지: 하나의 HTTP 요청이나 응답을 이루는 프레임들의 집합이다.
  • 스트림: 하나의 연결 안에서 양방향으로 오가는 프레임의 흐름이다.

멀티플렉싱

HTTP 2.0은 하나의 TCP 연결 안에서 여러 스트림의 프레임을 교차 전송한다. 수신 측은 프레임의 스트림 ID를 보고 원래 메시지로 재조립한다.

이 방식은 HTTP 1.x처럼 앞 요청의 응답이 뒤 요청을 막는 문제를 줄인다.

단일 TCP 커넥션

HTTP 2.0은 일반적으로 도메인당 하나의 장기 TCP 연결을 사용한다. 여러 연결을 만들 때 생기는 핸드셰이크, 느린 시작, 서버 리소스 비용을 줄일 수 있다.

스트림 우선순위

브라우저는 CSS, JavaScript, 이미지 등 리소스의 중요도에 따라 스트림 우선순위를 지정할 수 있다. 서버는 이 정보를 참고해 렌더링에 중요한 리소스를 먼저 보낼 수 있다.

서버 푸시

서버 푸시는 클라이언트가 요청하기 전에 필요할 가능성이 높은 리소스를 미리 보낸다. 리소스 인라이닝처럼 요청을 줄이면서도 개별 캐싱이 가능하다는 장점이 있다.

헤더 압축

HTTP 2.0은 헤더 테이블을 활용해 중복 헤더를 압축한다. 매 요청마다 같은 쿠키와 메타데이터를 반복 전송하던 HTTP 1.x의 오버헤드를 크게 줄인다.

복습 질문

  • 바이너리 프레이밍 계층은 HTTP 메시지를 어떤 단위로 나누는가?
  • HTTP 2.0 멀티플렉싱은 HTTP 1.x의 HOL 블로킹을 어떻게 줄이는가?
  • 서버 푸시는 리소스 인라이닝보다 어떤 점에서 유리한가?

3부 5장. 애플리케이션 전송 최적화

애플리케이션 전송 최적화는 물리 계층, TCP, TLS, HTTP의 특성을 종합해 실제 사용자에게 더 빠른 경험을 제공하는 작업이다. 가장 빠른 요청은 보내지 않는 요청이며, 꼭 보내야 한다면 작고 가까운 경로로 빠르게 보내야 한다.

공통 최적화 원칙

  • 불필요한 요청을 제거한다.
  • Cache-Control, ETag 등을 활용해 브라우저 캐시를 적극 사용한다.
  • HTML, CSS, JavaScript 같은 텍스트 리소스는 압축한다.
  • 이미지는 적절한 크기와 효율적인 포맷으로 제공한다.
  • DNS 룩업을 줄인다.
  • TCP 커넥션을 재사용한다.
  • HTTP 리다이렉션을 줄인다.
  • CDN으로 사용자와 가까운 곳에서 콘텐츠를 제공한다.

HTTP 1.x 최적화와 HTTP 2.0

HTTP 1.x에서는 요청 수를 줄이기 위해 결합, 스프라이팅, 인라이닝, 도메인 샤딩 같은 기법이 자주 사용되었다.

HTTP 2.0에서는 멀티플렉싱, 헤더 압축, 서버 푸시가 이런 기법의 필요성을 크게 줄인다. 과거 방식을 그대로 유지하면 오히려 캐시 효율을 낮추고 멀티플렉싱의 장점을 방해할 수 있다.

듀얼 프로토콜 전략

현실적으로 서버는 HTTP 1.x와 HTTP 2.0 클라이언트를 동시에 상대해야 한다. 이때 클라이언트의 프로토콜 버전에 따라 최적화를 다르게 적용하는 자동화 도구나 중간 계층을 활용할 수 있다.

HTTP 1.x 클라이언트에는 결합이나 샤딩을 적용하고, HTTP 2.0 클라이언트에는 원본 리소스를 유지해 멀티플렉싱을 활용하는 식이다.

리버스 프록시 활용

백엔드 전체를 HTTP 2.0으로 바꾸기 어렵다면 TLS와 HTTP 2.0을 지원하는 리버스 프록시나 로드 밸런서를 앞단에 둘 수 있다.

클라이언트와 프록시 구간에서는 HTTP 2.0 이점을 활용하고, 내부망에서는 기존 HTTP 1.x로 백엔드와 통신한다. 기존 애플리케이션 구조를 크게 바꾸지 않고도 외부 사용자에게 성능 이점을 제공할 수 있다.

복습 질문

  • 가장 빠른 네트워크 요청이 “없는 요청”인 이유는 무엇인가?
  • HTTP 2.0 환경에서 파일 결합이 오히려 손해가 될 수 있는 이유는 무엇인가?
  • 리버스 프록시는 HTTP 2.0 도입에서 어떤 역할을 할 수 있는가?

Part 4. Browser APIs

4부 1장. 브라우저 네트워킹의 첫걸음

브라우저는 TCP, UDP, TLS, HTTP 같은 하위 네트워크 계층의 복잡성을 개발자 대신 처리한다. 개발자는 고수준 API를 사용하지만, 브라우저 내부에서는 커넥션 관리, 보안, 캐싱, 예측 최적화가 계속 일어난다.

핵심 개념

커넥션 관리와 소켓 풀

브라우저는 도메인별 연결 수를 제한하고, 요청을 큐에 넣어 우선순위에 따라 처리한다. Keep-Alive 연결을 재사용해 TCP 핸드셰이크와 느린 시작 비용을 줄인다.

이 소켓 풀 덕분에 개발자는 직접 TCP 소켓을 관리하지 않아도 된다.

예측 네트워킹 최적화

브라우저는 사용자가 요청하기 전에 네트워크 작업을 미리 수행할 수 있다.

  • DNS pre-resolve
  • TCP preconnect
  • 리소스 prefetch
  • 페이지 prerender

이런 작업은 사용자가 실제로 이동하거나 클릭했을 때 체감 지연을 줄인다.

보안과 샌드박싱

브라우저는 TLS 핸드셰이크, 인증서 검증, 보안 정책을 자동으로 처리한다. 동일 출처 정책(SOP)을 강제해 한 사이트의 스크립트가 허가 없이 다른 출처의 데이터에 접근하지 못하게 한다.

캐싱과 클라이언트 상태

브라우저는 쿠키, 세션, 인증 정보, HTTP 캐시를 관리한다. ETag와 Last-Modified 같은 검증 헤더를 사용해 변경되지 않은 리소스를 다시 다운로드하지 않도록 돕는다.

고수준 네트워크 API

  • XMLHttpRequest: 비동기 HTTP 요청
  • Server-Sent Events: 서버에서 클라이언트로 단방향 이벤트 스트림
  • WebSocket: 양방향 텍스트와 바이너리 스트리밍
  • WebRTC: 브라우저 간 P2P 실시간 미디어와 데이터 전송

복습 질문

  • 브라우저의 소켓 풀은 어떤 비용을 줄이는가?
  • 동일 출처 정책은 무엇을 막기 위한 정책인가?
  • 브라우저의 예측 최적화는 어떤 네트워크 작업을 미리 수행하는가?

4부 2장. XMLHttpRequest

XMLHttpRequest(XHR)는 전체 페이지를 새로고침하지 않고 서버와 비동기적으로 데이터를 주고받을 수 있게 해준 API다. AJAX의 기반이 되었으며, 브라우저가 HTTP, 캐싱, 리다이렉션, 인증, 보안 같은 하위 처리를 대신 수행한다.

핵심 개념

XHR의 역할

XHR을 사용하면 JavaScript에서 서버에 비동기 요청을 보내고, 응답 데이터를 받아 화면 일부만 갱신할 수 있다. 개발자는 소켓이나 HTTP 포맷을 직접 다루지 않아도 된다.

CORS

XHR은 기본적으로 동일 출처 정책의 제한을 받는다. 다른 출처의 리소스에 접근하려면 서버가 CORS 헤더로 허용해야 한다.

쿠키나 커스텀 헤더가 포함된 복잡한 요청은 브라우저가 먼저 OPTIONS 사전 요청을 보내 권한을 확인한다.

데이터 타입 처리

XHR은 텍스트뿐 아니라 다양한 응답 타입을 처리할 수 있다.

  • ArrayBuffer
  • Blob
  • Document
  • JSON
  • FormData

responseType을 지정하면 브라우저가 적절한 네이티브 포맷으로 파싱하고 메모리를 효율적으로 사용할 수 있다.

진행 상황 이벤트

XHR은 요청 생명주기를 나타내는 이벤트를 제공한다.

  • loadstart
  • progress
  • load
  • error

다운로드와 업로드 모두 진행률을 추적할 수 있어, 대용량 파일 전송에서 사용자에게 상태를 보여주기 좋다.

폴링과 롱폴링

XHR은 본질적으로 서버 푸시나 양방향 스트리밍에 적합하지 않다. 그래서 실시간 알림을 위해 폴링과 롱폴링이 사용되었다.

폴링은 주기적으로 서버에 업데이트가 있는지 묻는 방식이라 헤더 오버헤드와 배터리 낭비가 크다. 롱폴링은 서버가 응답을 지연시켜 업데이트가 있을 때 답하지만, 메시지마다 HTTP 요청과 헤더 비용이 발생한다.

XHR 스트리밍의 한계

XHR 스트리밍은 표준적으로 깔끔한 방식이 아니며, 텍스트 버퍼를 수동으로 파싱해야 하고 메모리 관리가 어렵다. 바이너리 스트리밍에도 적합하지 않다.

이 한계 때문에 SSE와 WebSocket 같은 더 적합한 실시간 통신 API가 등장했다.

복습 질문

  • CORS 사전 요청은 언제 발생하는가?
  • XHR 폴링은 왜 모바일 배터리에 나쁜가?
  • XHR 스트리밍의 한계는 무엇인가?

4부 3장. Server-Sent Events

Server-Sent Events(SSE)는 서버에서 클라이언트로 실시간 텍스트 이벤트를 보내기 위한 브라우저 API다. EventSource API가 연결 관리, 메시지 파싱, 재연결을 추상화한다.

핵심 개념

EventSource API

클라이언트는 EventSource로 서버의 이벤트 스트림에 연결한다. 브라우저는 연결 유지, 메시지 파싱, 네트워크 장애 시 재연결을 자동으로 처리한다.

개발자는 onmessage나 커스텀 이벤트 리스너로 데이터를 처리하면 된다.

이벤트 스트림 프로토콜

SSE는 기존 HTTP 위에서 동작한다. 서버는 Content-Type: text/event-stream으로 응답하고 연결을 유지한다.

이벤트 데이터는 UTF-8 텍스트이며 다음 필드를 사용할 수 있다.

  • data: 이벤트 페이로드
  • event: 커스텀 이벤트 타입
  • id: 메시지 식별자
  • retry: 재연결 대기 시간

자동 재연결과 상태 복구

연결이 끊어지면 브라우저는 자동으로 재연결을 시도한다. 마지막으로 받은 이벤트 ID를 기억하고 Last-Event-ID 헤더로 서버에 전달할 수 있다.

서버는 이 값을 이용해 클라이언트가 놓친 이벤트부터 다시 보낼 수 있다.

한계와 사용 사례

SSE는 서버에서 클라이언트로 가는 단방향 텍스트 스트림에 최적화되어 있다.

한계는 다음과 같다.

  • 양방향 통신이 아니다.
  • 바이너리 데이터는 직접 전송할 수 없다.
  • HTTP 1.x에서는 브라우저의 도메인당 연결 제한을 차지한다.

주가 업데이트, 뉴스 피드, 알림, 상태 변경 이벤트처럼 단방향 실시간 텍스트 데이터에 적합하다.

복습 질문

  • SSE와 WebSocket의 가장 큰 차이는 무엇인가?
  • Last-Event-ID는 어떤 문제를 해결하는가?
  • HTTP 2.0에서 SSE의 연결 제한 문제는 어떻게 완화되는가?

4부 4장. WebSocket

WebSocket은 클라이언트와 서버 사이에 장기 연결을 만들고, 텍스트와 바이너리 데이터를 양방향으로 주고받는 프로토콜이다. 실시간 채팅, 게임, 협업 도구처럼 양방향 저지연 통신이 필요한 환경에 적합하다.

핵심 개념

HTTP 업그레이드 핸드셰이크

WebSocket은 HTTP 요청으로 시작한다. 클라이언트가 Connection: UpgradeUpgrade: websocket 헤더를 보내고, 서버가 101 Switching Protocols로 응답하면 연결이 WebSocket 프로토콜로 전환된다.

양방향 스트리밍

SSE가 서버에서 클라이언트로만 데이터를 보내는 것과 달리, WebSocket은 양방향 통신을 지원한다. 텍스트뿐 아니라 ArrayBuffer와 Blob 같은 바이너리 데이터도 전송할 수 있다.

가벼운 프레이밍

HTTP 요청마다 큰 텍스트 헤더를 붙이는 방식과 달리, WebSocket은 업그레이드 이후 작은 프레임 오버헤드만 사용한다. 그래서 빈번한 작은 메시지에 효율적이다.

클라이언트에서 서버로 보내는 프레임은 캐시 오염 공격을 방지하기 위해 마스킹된다.

서브프로토콜

WebSocket은 메시지의 의미 체계를 직접 정의하지 않는다. 애플리케이션은 JSON, MessagePack, 커스텀 프로토콜 등을 선택해야 한다.

Sec-WebSocket-Protocol 헤더로 클라이언트와 서버가 사용할 서브프로토콜을 협상할 수 있다.

한계

WebSocket은 자체 멀티플렉싱을 제공하지 않는다. 하나의 큰 메시지가 앞에 있으면 뒤의 작은 메시지가 기다릴 수 있다. 애플리케이션 레벨에서 메시지를 쪼개거나 우선순위를 설계해야 할 수 있다.

또한 프록시나 로드 밸런서가 장기 유휴 연결을 끊을 수 있으므로 실서비스에서는 TLS 기반 WSS를 사용하는 것이 안정적이다.

복습 질문

  • WebSocket은 HTTP 연결을 어떻게 업그레이드하는가?
  • WebSocket이 SSE보다 적합한 상황은 무엇인가?
  • WSS 사용이 권장되는 이유는 무엇인가?

4부 5장. WebRTC

WebRTC는 브라우저 간 P2P 실시간 음성, 비디오, 데이터 전송을 가능하게 하는 기술이다. 플러그인 없이 미디어 처리, NAT 통과, 암호화, 실시간 전송을 브라우저가 지원한다.

핵심 API

MediaStream

카메라와 마이크에서 오디오와 비디오 스트림을 얻는다. 브라우저는 코덱, 에코 제거, 노이즈 감소 같은 미디어 처리를 지원한다.

RTCPeerConnection

피어 간 오디오와 비디오 연결을 생성하고 관리한다. ICE, STUN, TURN을 활용해 가능한 네트워크 경로를 찾는다.

RTCDataChannel

피어 간 임의의 텍스트나 바이너리 데이터를 전송한다. 게임 상태, 파일 전송, 협업 데이터 동기화 등에 사용할 수 있다.

핵심 개념

UDP 기반 실시간 전송

실시간 통신에서는 모든 패킷을 완벽히 재전송하는 것보다 낮은 지연이 중요하다. 늦게 도착한 오디오 패킷은 의미가 없을 수 있으므로, WebRTC는 UDP 기반 전송을 주로 사용한다.

NAT 통과

대부분의 사용자는 NAT나 방화벽 뒤에 있기 때문에 직접 연결이 쉽지 않다.

  • STUN: 자신의 공인 IP와 포트를 확인한다.
  • TURN: 직접 연결이 불가능할 때 중계 서버를 사용한다.
  • ICE: 가능한 후보 경로를 수집하고 가장 좋은 연결 경로를 선택한다.
  • SDP: 미디어 포맷과 네트워크 정보를 교환하는 설명 형식이다.

WebRTC 표준은 신호 채널을 직접 제공하지 않는다. SDP와 연결 정보를 교환하기 위한 WebSocket, SSE, HTTP 같은 별도 채널은 애플리케이션이 구현해야 한다.

데이터 채널과 SCTP

RTCDataChannel은 UDP 위에서 SCTP를 사용한다. SCTP는 순서 보장 여부와 재전송 정책을 조정할 수 있어, TCP의 Head-of-Line 블로킹을 피하면서도 필요한 수준의 신뢰성을 제공할 수 있다.

다자간 통신

1:1 P2P는 비교적 단순하지만, 여러 명이 모두 서로 연결하는 메시 구조는 참가자가 늘수록 연결 수와 업로드 대역폭이 급증한다.

대규모 서비스에서는 SFU, MCU 같은 미디어 서버를 중심에 두는 스타형 구조를 주로 고려한다.

복습 질문

  • WebRTC가 UDP를 선호하는 이유는 무엇인가?
  • STUN, TURN, ICE는 각각 어떤 역할을 하는가?
  • 다자간 WebRTC에서 메시 구조가 확장성에 취약한 이유는 무엇인가?