주소창에 google.com을 입력하면 단순히 페이지가 열리는 것처럼 보이지만, 그 안에서는 수십 단계의 네트워크·브라우저·운영체제 레벨 프로세스가 연속적으로 일어난다. 이 과정을 이해하면 웹의 전반적인 동작 원리를 완벽히 파악할 수 있다.
1. 도메인 이름 해석 (DNS Lookup)
브라우저는 먼저 사용자가 입력한 문자열이 검색어인지 URL인지 구분한다. google.com처럼 도메인 형식을 띠면 자동으로 https://google.com/ 형태로 완성한다.
이때 브라우저는 HSTS(HTTP Strict Transport Security) 정책을 참고해, 이전에 HTTPS로 접속한 기록이 있으면 HTTP 대신 HTTPS를 우선 사용한다.
그다음 브라우저는 도메인을 실제 서버의 IP 주소로 변환하기 위해 DNS 조회(DNS Resolution)를 수행한다.
이 과정에서 브라우저는 먼저 자체 DNS 캐시를 확인하고, 없을 경우 운영체제(OS) 캐시 → 라우터 → ISP(인터넷 서비스 제공자) DNS → 루트 DNS → TLD DNS → 권한 있는 네임서버(Authoritative DNS) 순으로 조회를 이어간다.
일부 브라우저는 DNS Prefetch 기능을 사용해, 사용자가 링크를 클릭하기 전에 미리 IP 주소를 조회해 네트워크 지연을 줄인다. 또한 전 세계에 분산된 CDN(Content Delivery Network)은 사용자의 지역에 따라 가장 가까운 서버의 IP를 반환해 응답 속도를 최적화한다.
*DNS
DNS는 사람이 이해하기 쉬운 도메인 이름(google.com)을 컴퓨터가 통신할 수 있는 숫자 주소인 IP(142.250.196.110)로 바꾸는 시스템이다.
2. TCP 연결 (3-Way Handshake)
DNS로 IP를 얻으면, 브라우저는 해당 서버와 *TCP 연결을 맺는다. TCP는 데이터 전송의 신뢰성을 보장하기 위해 3단계 핸드셰이크(3-Way Handshake) 과정을 거친다.

- SYN: SYNchronization 의 약자, 연결 요청 플래그
- ACK: ACKnowledgement 의 약자, 응답 플래그
- ISN: Initial Sequence Numbers 의 약어, 초기 네트워크 연결을 할 때 할당된 32비트 고유 시퀀스 번호
- SYN 단계 [SYN-SENT > SYN-RECEIVED]
- 클라이언트는 서버에 클라이언트 ISN을 담아 SYN을 보낸다.
- ISN은 새로운 TCP 연결의 첫 번째 패킷(네트워크에서 데이터의 전송 단위를 말하는데, 헤더, 데이터, 트레일러 구조로 구성된다)에 할당된 임의의 시퀀스 번호를 말하며 이는 장치마다 다를 수 있다.
- SYN + ACK 단계 [SYN-RECEIVED > ESTABLISHED]
- 서버는 클라이언트의 SYN을 수신하고 서버의 ISN을 보내며 승인 번호로 클라이언트의 ISN + 1을 보낸다.
- ACK 단계 [ESTABLISHED > ESTABLISHED]
- 클라이언트는 서버의 ISN + 1 한 값인 승인번호를 담아 ACK를 서버에 보낸다.
이 과정을 통해 안정적인 통신 채널이 구축된다. 연결 이후에는 Keep-Alive 헤더를 통해 여러 요청을 같은 연결로 처리해 속도를 높이고, 작은 패킷은 **Nagle 알고리즘으로 묶어 전송 효율을 향상시킨다.
*TCP (Transmission Control Protocol): 신뢰성 있는 데이터 전송
- TCP는 데이터의 신뢰성과 순서를 보장하는 역할을 하는 프로토콜이다. 데이터를 여러 패킷으로 나누어 전송하고, 수신 측에서 패킷을 재조립하며, 손실된 패킷이 있으면 다시 요청하여 데이터의 무결성을 보장한다.
- 예시: 파일 다운로드 시, TCP를 사용하면 파일이 손상되지 않고 완전하게 다운로드되도록 보장하고, 패킷이 손실되면 재전송 요청을 통해 누락된 데이터를 보충한다.
**Nagle 알고리즘
TCP는 데이터를 보낼 때, 너무 작은 데이터 조각(패킷)을 자주 보내면 네트워크 부하가 커진다. 예를 들어 키보드 입력처럼 한 글자씩 보내면 매번 TCP 헤더(20바이트 이상)가 붙어서 낭비가 심하기 때문에 Nagle 알고리즘을 이용하여 작은 데이터가 여러 개 생기면, 이전 패킷의 ACK(응답)을 받을 때까지 새 데이터를 버퍼에 모았다가 한 번에 전송한다.
- Nagle 비활성화 시: “h” → “e” → “l” → “l” → “o” → 각각 별도 패킷 전송
- Nagle 활성화 시: “hello”를 한 번에 묶어서 전송
네트워크 자세히 보기 - 네트워크 계층 간 데이터를 송수신하는 과정
3. HTTPS 연결 (TLS/SSL Handshake)
만약 사이트가 HTTPS를 사용한다면, TCP 연결 후에 TLS(Transport Layer Security) 핸드셰이크가 추가로 일어난다. 이 단계에서 브라우저와 서버는 암호화 키를 교환하고 신뢰할 수 있는 통신을 설정한다.
1. 브라우저는 먼저 “어떤 방식으로 안전하게 통신할 수 있는지” 서버에게 제안한다. 이때 브라우저는 자신이 지원하는 TLS 버전, 암호화 알고리즘, 그리고 랜덤한 숫자(난수)를 함께 보낸다.
2. 서버는 그중에서 가장 강력하고 호환되는 암호화 방식을 선택한 뒤, 서버의 신원을 증명하는 인증서(SSL 인증서)를 브라우저에게 전달한다.
3. 브라우저는 이 인증서가 신뢰할 수 있는 기관(CA, Certificate Authority)에서 발급된 것인지 확인하고, 인증서가 위조되었거나 만료되지 않았는지도 검사한다.
4. 이 검증이 끝나면 브라우저와 서버는 서로 같은 비밀키(세션 키)를 만들어낸다. 이 키는 이후의 모든 통신 데이터를 암호화하는 데 사용되며, 외부에서 누가 가로채더라도 내용을 해독할 수 없게 만든다.
브라우저는 HSTS(HTTP Strict Transport Security) 정책을 사용해 HTTP 접근을 자동으로 HTTPS로 전환하며, TLS Session Resumption 기능으로 이미 검증된 세션을 재활용해 재접속 속도를 높인다.
4. HTTP 요청 생성 및 전송
암호화된 연결이 완료되면 브라우저는 실제 HTTP 요청을 생성한다.
GET / HTTP/1.1
Host: google.com
User-Agent: Mozilla/5.0
Accept: text/html
Cookie: ...
브라우저는 필요한 헤더를 포함해 서버로 요청을 전송하고, *Cache-Control이나 **ETag 값이 있으면 브라우저는 로컬 캐시를 확인해 불필요한 네트워크 요청을 줄인다.
최신 브라우저는 HTTP/2의 멀티플렉싱 기능을 사용해 하나의 연결에서 여러 요청을 병렬로 처리하고, HTTP/3에서는 TCP 대신 QUIC(UDP 기반) 프로토콜을 사용해 지연을 더욱 줄인다.
*Cache-Control
Cache-Control은 브라우저나 프록시 서버가 요청·응답을 얼마나 오래, 어떤 방식으로 저장할지를 결정하는 HTTP 헤더다. 즉, “이 데이터를 언제까지 캐시해도 괜찮은가?”를 알려주는 지침 역할을 한다.
Cache-Control: max-age=3600, public
- max-age=3600 → 이 응답은 3600초(1시간) 동안 캐시해도 됨
- public → 브라우저뿐 아니라 중간 프록시 서버에서도 캐시 가능
Cache-Control: no-cache
- 항상 서버에 변경 여부를 확인해야 함
- 단, 완전히 캐시를 금지하는 것은 아님 (“사용 전 검증 필요”)
Cache-Control: no-store
- 민감한 정보(예: 로그인, 결제 페이지) 에 주로 사용
- 브라우저와 프록시가 데이터를 절대 저장하지 않음
**ETag (Entity Tag)
ETag는 서버가 응답 데이터의 버전을 식별하기 위해 붙이는 고유한 태그다. 브라우저는 이 값을 저장해 두었다가 다음 요청 시 함께 전송해 “이전 버전과 같은가?”를 서버에 묻는다.
1. 서버 응답 시
ETag: "v1.23abc"
2. 브라우저가 다음 번 요청에서
If-None-Match: "v1.23abc"
3. 서버가 비교 후
- 데이터가 변경되지 않았다면 → 304 Not Modified (캐시 사용)
- 데이터가 변경되었다면 → 새 콘텐츠와 새 ETag 반환
이 과정을 통해 불필요한 전체 데이터 재다운로드를 방지하고, 네트워크 트래픽을 크게 줄일 수 있다.
ETag 새로 붙이는 기준 상세히 알아보기
서버는 리소스의 내용(content) 이 변경될 때마다 새로운 ETag를 생성한다. 즉, 요청의 형태(URL, 쿼리 등) 이 아니라 응답 데이터의 본질적 내용이 바뀌었는지가 기준이다.
| 상황 | ETag 변경 여부 | 이유 |
| 사용자가 게시물의 좋아요 수를 눌러 +1 | 변경됨 | 리소스 내용(좋아요 수)이 달라짐 |
| 요청 헤더에 Authorization 토큰만 다름 | ❌ 변경 안됨 | 리소스 내용은 동일 |
| 이미지 파일이 새로 업로드됨 | 변경됨 | 파일의 바이트 내용이 달라짐 |
| 단순히 요청 시점(time)만 다름 | ❌ 변경 안됨 | 리소스 내용 그대로 |
ETag 생성 방식 예시
서버마다 다르지만 일반적으로 다음 중 하나로 생성한다.
- 파일의 해시값 (MD5, SHA 등) → 파일 내용이 한 바이트라도 바뀌면 해시값이 달라짐.
- 리소스의 수정 시간 + 크기 기반 → 예: "W/\"16384-171a2b3c\""
- 데이터베이스 row의 updatedAt 필드 기반 → 예: "\"user-42:2025-10-27T10:30:00Z\""
정리하자면,
“ETag는 서버가 리소스의 버전을 구분하기 위해 붙이는 식별자이다. 서버는 리소스의 실제 내용이 변경될 때마다 새로운 ETag를 생성하고,
브라우저는 이전에 받은 ETag를 If-None-Match 헤더로 전송해서 서버에게 ‘이 데이터가 바뀌었는지’를 확인한다. 내용이 같으면 304 응답을 보내 캐시를 재사용하고, 달라졌다면 새 데이터를 내려준다. ETag는 요청 자체보다는 응답 데이터의 ‘실질적인 내용 변화’를 기준으로 새로 생성된다.”
브라우저 캐시의 저장 위치
브라우저는 서버 응답을 캐시할 때 두 가지 저장소 중 하나를 사용한다.
| 구분 | 설명 | 특징 |
| Memory Cache | 브라우저 탭이 열려 있는 동안만 유지되는 휘발성 캐시 | 빠르지만 세션 종료 시 사라진다 |
| Disk Cache | 디스크에 파일 형태로 저장되는 지속적 캐시 | 속도는 느리지만 브라우저를 닫아도 유지된다 |
- API 응답이나 자주 변경되는 데이터는 Memory Cache에 저장되는 경우가 많다.
- JS, CSS, 이미지 등 정적 리소스는 주로 Disk Cache에 저장된다.
캐시 저장 및 동작 과정 (HTTP 요청 → 응답 → 캐싱-> 다음 요청시 검증)
(1) 요청
사용자가 페이지를 요청할 때, 브라우저는 먼저 캐시를 탐색한다. URL, 헤더, 쿼리 스트링 등이 동일한 요청이 있는지 확인하고, 유효 기간(Cache-Control, Expires)이 남아 있다면 캐시에서 바로 응답한다.
GET /users/123
또한, 클라이언트 측에서 강제 캐시 제어 (fetch 예시) 할 수도 있다.
// 브라우저 캐시를 먼저 확인하고, 없으면 네트워크 요청
fetch('/api/products', { cache: 'force-cache' });
// 항상 네트워크 요청 (캐시 무시)
fetch('/api/products', { cache: 'no-store' });
// 캐시 확인 후 만료 시 네트워크 요청
fetch('/api/products', { cache: 'default' });
// 캐시가 있으면 캐시 우선, 없으면 네트워크
fetch('/api/products', { cache: 'only-if-cached' });
(2) 서버 응답 시 캐시 정책 전달
서버는 응답 헤더를 통해 캐시 정책을 명시한다.
HTTP/1.1 200 OK
Cache-Control: public, max-age=3600
ETag: "v1.23abc"
Content-Type: application/json
*Cache-Control 헤더는 캐시 가능 여부와 유효 기간을 정의한다. 예를 들어, public, max-age=3600은 모든 캐시 주체가 1시간 동안 해당 리소스를 재사용할 수 있음을 의미한다.
ETag는 리소스의 버전을 식별하는 고유한 태그로, 캐시된 리소스가 변경되었는지 여부를 판단하는 데 사용한다.
*Cache-Control 헤더의 지시어와 의미
| 지시어 | 의미 | 캐시 주체 | 예시 상황 |
| public | 모든 캐시(브라우저 + CDN + 프록시 서버)에서 캐시 가능 | 모두 가능 | 정적 자원 (이미지, CSS, JS 등) |
| private | 오직 브라우저(클라이언트) 캐시만 가능 | 사용자 개인 브라우저만 | 사용자 맞춤 페이지 (예: 마이페이지) |
| no-store | 아예 캐시하지 않음 (민감 데이터) | 캐시 금지 | 로그인, 결제, 개인정보 페이지 |
| no-cache | 캐시되더라도 항상 서버에 유효성 검증 필요 | 제한적 | 뉴스 메인, 자주 업데이트되는 콘텐츠 |
(3) 브라우저의 캐시 저장
브라우저는 응답을 받은 후 내부 정책에 따라 저장 위치를 결정한다. 리소스의 종류, 크기, 메모리 상태 등을 고려해 MemoryCache 또는 DiskCache 중 하나를 선택한다. 헤더와 본문 데이터를 함께 저장한다.
예시 (개념적 구조):
CacheEntry {
key: "https://api.example.com/users/123",
headers: {
ETag: "v1.23abc",
Cache-Control: "public, max-age=3600"
},
body: "{ name: 'Jay', id: 123 }",
expiresAt: 1730000000000
}
(4) 다음 요청 시 검증 (ETag)
브라우저는 다음 요청 시 이전에 받은 ETag를 함께 보낸다.
GET /users/123
If-None-Match: "v1.23abc"
서버는 전달받은 ETag와 현재 리소스의 ETag를 비교한다. 동일하다면 304 Not Modified로 응답하고, 브라우저는 캐시 데이터를 사용한다. 다르다면 새로운 데이터를 200 OK와 함께 전달하고 ETag를 갱신한다.
5. 서버의 요청 처리 (Back-end Logic)
요청이 서버에 도착하면, 먼저 로드 밸런서(Load Balancer)가 트래픽을 여러 서버로 분산한다. 그다음 웹 서버(Nginx, Apache)가 요청을 분석하고, 내부적으로 애플리케이션 서버(Node.js, Spring 등)에 전달한다. 애플리케이션 서버는 필요한 데이터를 데이터베이스나 캐시 서버(Redis, Memcached), 외부 API에서 조회한다. 이후 결과를 HTML, JSON 등의 형태로 가공해 클라이언트에게 응답한다.
HTTP/1.1 200 OK
Content-Type: text/html
Set-Cookie: session=abc123
Cache-Control: max-age=600
6. 브라우저 렌더링 (Rendering Engine)

서버의 응답이 도착하면 브라우저의 렌더링 엔진(Blink, WebKit)이 동작한다. HTML을 파싱해 DOM 트리를 만들고, CSS를 파싱해 CSSOM 트리를 구성한다. 두 트리를 결합해 렌더 트리(Render Tree)를 생성하고, 각 요소의 크기와 위치를 계산(Layout)한다.
그 후 페인팅(Painting)으로 화면에 픽셀을 그려내고, 여러 레이어를 컴포지팅(Compositing)하여 최종 이미지를 표시한다.
이 과정에서 브라우저는 Critical Rendering Path(CRP)를 최적화해 첫 화면 표시 속도를 높이고, 불필요한 Reflow(레이아웃 재계산)와 Repaint(화면 다시 그리기)를 최소화한다. 이미지나 동영상 같은 리소스는 Lazy Loading으로 지연 로드해 초기 로딩 성능을 개선한다.
7. 추가 요청 (Subresource Fetching)
렌더링 중 HTML 안에서 <script>, <link>, <img> 등 외부 리소스가 발견되면 브라우저는 병렬로 추가 HTTP 요청을 전송한다. 이미 캐시에 있는 리소스는 다시 요청하지 않고 로컬에서 재활용한다. 이때 서버는 HTTP/2의 Server Push 기능을 통해 브라우저가 요청하기 전에 필요한 리소스를 미리 전송할 수도 있다.
8. 사용자 상호작용 & 이벤트 루프

렌더링이 완료되면 페이지는 사용자와 상호작용 가능한 상태가 된다. 브라우저의 JavaScript 엔진(V8, SpiderMonkey)은 이벤트 루프(Event Loop)를 통해 비동기적으로 동작을 관리한다. Call Stack은 실행 중인 코드 컨텍스트를, Task Queue는 대기 중인 콜백을, Microtask Queue는 Promise 같은 우선순위 높은 작업을 처리한다. 이 구조 덕분에 페이지는 클릭, 입력, 스크롤 같은 이벤트에 부드럽게 반응한다.
9. 전체 요약 및 마무리
| 단계 | 핵심 역할 | 주요 기술 |
| DNS 조회 | 도메인을 IP로 변환 | DNS, CDN, CNAME |
| TCP 연결 | 안정적 통신 채널 확보 | 3-Way Handshake, Keep-Alive, Nagle Algorithm |
| TLS Handshake | 암호화 통신 보장 | HTTPS, CA, HSTS, TLS Session Resumption |
| HTTP 요청 | 리소스 요청 전송 | HTTP/1.1~3, Cache-Control, ETag |
| 서버 처리 | 데이터 생성·응답 | Load Balancer, 웹 서버(Nginx/Apache/Caddy), 애플리케이션 서버(Node.js/Spring/Django), Cache, DB, API |
| 렌더링 | 화면 표시 | DOM, CSSOM, 렌더 트리, CRP, Reflow/Repaint, Lazy Loading |
| 추가 요청 | 리소스 병렬 로드 | HTTP 캐시, Server Push, CDN |
| 이벤트 루프 | 사용자 인터랙션 처리 | JS Engine, Event Loop, Call Stack, Task Queue, Microtask Queue |
‘주소창에 google.com을 입력하면?’이라는 단순한 질문 안에는 네트워크, 보안, 브라우저, 서버, 렌더링, 자바스크립트 엔진 등 웹 전체의 원리가 모두 담겨 있다. 이 과정을 이해하면 단순히 “웹이 동작한다”를 넘어서, “웹이 어떻게 작동하는가”를 시스템적으로 사고할 수 있게 된다. 즉, 이 한 질문이야말로 프론트엔드와 백엔드, 그리고 네트워크 전반을 관통하는 가장 본질적인 개념이라고 생각한다.
'Computer Science > Web Development' 카테고리의 다른 글
| 웹 서버(Nginx, Apache..) 의 역할 (0) | 2025.10.18 |
|---|---|
| CORS Error 는 왜 자주 발생할까? — 교차 출처 리소스 공유 (0) | 2025.10.18 |
| JWT(Json Web Token) (0) | 2025.10.17 |
| SPA, CSR, SSR, 그리고 Hybrid Rendering — 웹 렌더링의 진화 (0) | 2025.10.17 |
| z-index가 같아도 겹치는 순서가 달라지는 이유 (0) | 2025.10.16 |