하나의 요청이 완성하는 전체 여정
서문
브라우저에 URL을 입력하고 Enter를 누른 후 페이지가 표시되기까지, 그 사이에 무슨 일이 일어날까요? 이 질문은 면접의 고전적인 질문이자, 전체 웹 아키텍처를 이해하는 열쇠입니다. 이 경로를 이해하면 프론트엔드, 백엔드, 네트워크, 데이터베이스가 어떻게 협력하는지 이해할 수 있습니다.
이 글에서 무엇을 배울 수 있나요?
이 장을 마치면 다음을 얻을 수 있습니다:
- 전체 경로 관점: HTTP 요청이 발송부터 반환까지의 완전한 과정 이해
- 각 계층 역할 인지: DNS, TCP, 로드 밸런서, 웹 서버, 애플리케이션 서버, 데이터베이스가 각각 무엇을 하는지
- 문제 진단 능력: 요청이 느리거나 실패할 때 어느 계층부터 조사해야 하는지
- 성능 최적화 아이디어: 각 계층마다 최적화 여지가 있으며, 최적화 포인트가 어디인지 파악
| 장 | 내용 | 핵심 개념 |
|---|---|---|
| 제1장 | 브라우저가 요청 시작 | DNS 해석, TCP 연결, HTTP 요청 |
| 제2장 | 네트워크 전송 | 라우팅, CDN, 로드 밸런싱 |
| 제3장 | 서버 처리 | 웹 서버, 애플리케이션 로직, 데이터베이스 쿼리 |
| 제4장 | 응답 반환 | 직렬화, 압축, 렌더링 |
| 제5장 | 전체 경로 최적화 | 캐싱, 연결 재사용, 비동기 처리 |
0. 전체 그림: 하나의 요청이 겪는 일
비유를 들어 이해해 봅시다: 온라인으로 책을 주문하는 과정은 HTTP 요청과 놀랍도록 유사합니다.
| 요청 단계 | 책 구매 비유 | 기술적 대응 |
|---|---|---|
| URL 입력 | "어느 서점에 가겠다"고 말함 | 브라우저가 URL 파싱 |
| DNS 해석 | 지도에서 서점 주소 찾기 | 도메인 → IP 주소 |
| TCP 연결 | 서점 문 앞에 도착, 문을 열고 들어감 | 3-way 핸드셰이크로 연결 수립 |
| 요청 전송 | 점원에게 "《xxx》 책을 주세요"라고 말함 | HTTP 요청 메시지 |
| 서버 처리 | 점원이 창고에서 책 찾기, 재고 확인, 가격 계산 | 애플리케이션 로직 + DB 쿼리 |
| 응답 반환 | 점원이 책을 건네줌 | HTTP 응답 메시지 |
| 브라우저 렌더링 | 책을 펼쳐 읽기 시작 | HTML/CSS/JS 파싱 및 렌더링 |
1. 브라우저가 요청 시작
1.1 URL 파싱
https://api.example.com/books?id=123을 입력하면 브라우저는 이를 여러 부분으로 분해합니다:
| 부분 | 값 | 의미 |
|---|---|---|
| 프로토콜 | https | 암호화 방식으로 통신 |
| 도메인 | api.example.com | 서버의 "이름" |
| 경로 | /books | 접근할 리소스 |
| 쿼리 파라미터 | id=123 | 추가 조건 |
1.2 DNS 해석: 도메인 → IP 주소
컴퓨터는 도메인을 모르고 IP 주소(예: 93.184.216.34)만 인식합니다. DNS는 인터넷의 "전화번호부"입니다.
브라우저 캐시 → 시스템 캐시 → 라우터 캐시 → ISP DNS → 루트 도메인 네임 서버
↓ 히트 시 바로 사용, 미스 시 다음 단계로 조회DNS 캐싱의 의미
매 요청마다 루트 도메인 네임 서버부터 조회한다면 전 세계 인터넷이 DNS 쿼리로 마비될 것입니다. 그래서 각 계층에 캐시가 있으며, 대부분의 요청은 브라우저나 시스템 계층에서 해석이 완료됩니다.
1.3 TCP 3-way 핸드셰이크
IP 주소를 찾은 후, 브라우저는 서버와 "연결을 수립"해야 합니다. TCP는 3-way 핸드셰이크로 양측이 모두 준비되었는지 확인합니다:
클라이언트 → 서버: 안녕하세요, 연결하고 싶습니다 (SYN)
서버 → 클라이언트: 좋습니다, 준비됐습니다 (SYN + ACK)
클라이언트 → 서버: 확인했습니다, 통신 시작합니다 (ACK)HTTPS의 경우 추가로 TLS 핸드셰이크가 필요하여 암호화 방식을 협상합니다.
1.4 HTTP 요청 전송
연결 수립 후 브라우저는 HTTP 요청 메시지를 전송합니다:
GET /books?id=123 HTTP/1.1
Host: api.example.com
Accept: application/json
Authorization: Bearer eyJhbGci...
User-Agent: Chrome/120.0| 구성 요소 | 내용 |
|---|---|
| 요청 라인 | 메서드(GET) + 경로 + 프로토콜 버전 |
| 요청 헤더 | 메타 정보: 인증, 기대 데이터 형식 등 |
| 요청 본문 | POST/PUT 요청만 존재, 제출할 데이터 포함 |
2. 네트워크 전송: 요청이 이동하는 길
2.1 라우팅 포워딩
요청이 컴퓨터를 떠난 후 여러 라우터의 포워딩을 거칩니다. 마치 택배가 여러 중계 지점을 거치는 것과 같습니다:
내 컴퓨터 → 가정용 라우터 → ISP 네트워크 → 백본 네트워크 → 대상 데이터센터각 라우터는 IP 주소에 따라 "다음 홉"을 어디로 포워딩할지 결정합니다. traceroute 명령어로 요청이 어떤 노드를 거쳤는지 확인할 수 있습니다.
2.2 CDN 가속
대상 웹사이트가 CDN(콘텐츠 전송 네트워크)을 사용하는 경우, 요청이 원본 서버까지 도달하지 않을 수 있습니다:
| 시나리오 | 경로 |
|---|---|
| 정적 리소스 요청(이미지, CSS, JS) | CDN 엣지 노드가 직접 반환 |
| 동적 데이터 요청(API) | CDN을 통과하여 원본 서버 도달 |
CDN의 본질은 "콘텐츠를 사용자와 가장 가까운 곳에 미리 배치하는 것"입니다.
2.3 로드 밸런싱
대형 웹사이트는 서버가 한 대만 있지 않습니다. 로드 밸런서가 요청을 여러 서버에 분배합니다:
사용자 요청 → 로드 밸런서 → 서버 A (30% 트래픽)
→ 서버 B (30% 트래픽)
→ 서버 C (40% 트래픽)일반적인 분배 전략:
| 전략 | 원리 | 적용 시나리오 |
|---|---|---|
| 라운드 로빈 | 순차적 분배 | 서버 사양이 동일할 때 |
| 가중 라운드 로빈 | 가중치에 따라 분배 | 서버 사양이 다를 때 |
| IP 해시 | 동일 사용자는 동일 서버로 고정 | 세션 유지 필요 시 |
| 최소 연결 | 현재 연결이 가장 적은 곳으로 | 요청 처리 시간 차이가 클 때 |
3. 서버 처리: 주방에서 무슨 일이 일어나는가
요청이 서버에 도착하면 여러 계층의 처리를 거칩니다.
3.1 웹 서버(Nginx / Apache)
요청을 가장 먼저 받는 것은 보통 웹 서버이며, 다음을 담당합니다:
| 역할 | 설명 |
|---|---|
| 정적 파일 서비스 | HTML, CSS, JS, 이미지 직접 반환 |
| 리버스 프록시 | API 요청을 백엔드 애플리케이션으로 전달 |
| SSL 종료 | HTTPS 암호화/복호화 처리 |
| 요청 필터링 | 악의적 요청 차단, 속도 제한 |
3.2 애플리케이션 서버 처리
웹 서버는 요청을 애플리케이션 서버(Node.js, Spring, Django 등)로 전달하며, 처리 흐름은:
요청 진입 → 미들웨어 체인 → 라우트 매칭 → 컨트롤러 → 서비스 계층 → 데이터 접근 계층미들웨어가 하는 일:
- 요청 본문 파싱(JSON, 폼 데이터)
- 신원 확인(Token 검증)
- 권한 확인(이 사용자가 이 API에 접근 가능한가?)
- 로그 기록(누가 언제 무엇에 접근했는가)
3.3 데이터베이스 쿼리
대부분의 요청은 결국 데이터베이스와 상호작용합니다:
애플리케이션 코드: SELECT * FROM books WHERE id = 123
↓
데이터베이스 엔진: SQL 파싱 → 쿼리 최적화 → 실행 계획 → 데이터 읽기
↓
결과 반환: { id: 123, title: "xxx", price: 59.9 }데이터베이스는 가장 흔한 성능 병목
네트워크 전송은 보통 밀리초 단위, 애플리케이션 로직도 빠르지만, 인덱스가 없는 데이터베이스 쿼리는 몇 초에서 수십 초가 걸릴 수 있습니다. 따라서 "느린 요청"은 대부분 데이터베이스 쿼리가 느린 경우입니다.
4. 응답 반환: 데이터의 귀환
4.1 HTTP 응답 구성
서버 처리가 완료되면 응답 메시지를 구성합니다:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Encoding: gzip
Cache-Control: max-age=3600
{"id": 123, "title": "xxx", "price": 59.9}| 구성 요소 | 내용 |
|---|---|
| 상태 라인 | 프로토콜 버전 + 상태 코드(200 성공, 404 찾을 수 없음, 500 서버 오류) |
| 응답 헤더 | 데이터 형식, 캐시 정책, 압축 방식 등 |
| 응답 본문 | 실제 데이터 내용(JSON, HTML 등) |
4.2 데이터 압축
서버는 보통 gzip 또는 brotli로 응답 본문을 압축하여 전송량을 줄입니다:
| 압축 알고리즘 | 압축률 | 속도 |
|---|---|---|
| gzip | 약 70% | 빠름 |
| brotli | 약 80% | 느리지만 압축률 우수 |
100KB의 JSON이 압축 후 20-30KB만 될 수 있습니다.
4.3 브라우저 렌더링
브라우저가 응답을 받은 후:
- HTML 파싱 → DOM 트리 구축
- CSS 파싱 → 스타일 트리 구축
- 병합 → 렌더 트리 생성
- 레이아웃 → 각 요소의 위치와 크기 계산
- 페인팅 → 픽셀을 화면에 그리기
5. 전체 경로 최적화: 모든 계층을 더 빠르게
5.1 각 계층별 최적화 수단
| 계층 | 최적화 수단 | 효과 |
|---|---|---|
| DNS | DNS 프리페치, 빠른 DNS 서비스 사용 | DNS 쿼리 시간 단축 |
| 네트워크 | CDN, HTTP/2, 연결 재사용 | 전송 지연 감소 |
| 서버 | 캐싱(Redis), 비동기 처리 | 처리 시간 단축 |
| 데이터베이스 | 인덱스, 쿼리 최적화, 읽기/쓰기 분리 | 쿼리 시간 단축 |
| 프론트엔드 | 지연 로딩, 코드 분할, 리소스 압축 | 렌더링 시간 단축 |
5.2 캐싱: 가장 효과적인 최적화
캐시는 요청 경로의 모든 계층에 존재합니다:
브라우저 캐시 → CDN 캐시 → 리버스 프록시 캐시 → 애플리케이션 캐시(Redis) → 데이터베이스 캐시캐싱의 본질
공간을 시간과 교환하는 것. 계산된 결과를 저장해 두었다가 다음에 바로 사용하며, 다시 계산하지 않습니다. 캐시 적중률이 10% 향상될 때마다 시스템 성능이 몇 배 향상될 수 있습니다.
5.3 요청 실패 시 진단 사고
| 현상 | 가능한 문제 계층 | 진단 방법 |
|---|---|---|
| 완전 무응답 | DNS / 네트워크 | ping, nslookup |
| 연결 타임아웃 | 네트워크 / 서버 다운 | telnet, curl |
| 4xx 반환 | 클라이언트 요청 오류 | URL, 파라미터, Token 확인 |
| 5xx 반환 | 서버 내부 오류 | 서버 로그 확인 |
| 응답 매우 느림 | 데이터베이스 / 애플리케이션 로직 | 슬로우 쿼리 로그, APM 도구 확인 |
6. 요약
하나의 HTTP 요청이 완성하는 전체 여정:
- 브라우저: URL 파싱 → DNS 쿼리 → TCP 연결 → 요청 전송
- 네트워크: 라우팅 포워딩 → CDN 판단 → 로드 밸런싱 분배
- 서버: 웹 서버 수신 → 미들웨어 처리 → 비즈니스 로직 → 데이터베이스 쿼리
- 반환: 응답 구성 → 압축 → 네트워크 전송 → 브라우저 렌더링
전체 경로 이해의 가치
머릿속에 요청의 완전한 경로를 그릴 수 있게 되면, 어떤 문제든 어느 계층에서 발생했는지 빠르게 파악할 수 있습니다. 이는 "주니어 개발자"에서 "독립적으로 문제를 진단할 수 있는" 수준으로 도약하는 핵심입니다.
더 읽어보기
- HTTP 권위 가이드 — MDN의 HTTP 문서
- High Performance Browser Networking — 브라우저 네트워크 성능 최적화
- What happens when... — 고전적인 "URL 입력 후 무슨 일이 일어나는가" 상세 해설