응용 계층 프로토콜: HTTP와 DNS
HTTP 메시지 구조와 메서드·상태 코드·캐시, DNS 질의 흐름, HTTP 버전 진화를 응용 계층 관점에서 정리합니다.
Contents
응용 계층은 사용자 프로그램이 직접 다루는 프로토콜의 영역이고, 그 중심에 HTTP와 DNS가 있습니다.
응용 계층이 맡는 일
인터넷 프로토콜 스택은 네 계층으로 나뉩니다. 응용 계층(Application Layer)은 가장 위에 있고, 웹 브라우저나 채팅 프로그램 같은 사용자 프로그램이 직접 다루는 프로토콜을 담습니다. 대표적으로 HTTP, DNS, FTP가 여기에 속합니다.
아래 전송 계층의 TCP와 UDP가 데이터를 실어 나르고, 응용 계층은 그 위에서 무엇을 어떤 형식으로 주고받을지 정합니다. 즉 같은 TCP 연결 위에서도 HTTP는 웹 문서를, FTP는 파일을 자기 규칙으로 교환합니다.
이 글은 그중 가장 많이 쓰는 둘을 다룹니다. HTTP(HyperText Transfer Protocol)는 웹 자원을 주고받는 프로토콜입니다. DNS(Domain Name System)는 사람이 읽는 도메인 이름을 통신에 필요한 IP 주소로 바꾸는 시스템입니다.
HTTP 메시지 구조
HTTP는 클라이언트가 요청을 보내고 서버가 응답하는 요청-응답 구조입니다. 요청과 응답은 같은 골격을 공유합니다. 시작 라인, 헤더, 빈 줄, 본문 순서입니다.
GET /search?q=hello&hl=ko HTTP/1.1
Host: www.google.com요청의 시작 라인은 메서드 + 요청 대상 + HTTP 버전으로 이뤄집니다. 위 예시는 /search?q=hello&hl=ko 경로를 GET으로 조회하는 요청입니다. 헤더에는 호스트나 콘텐츠 형식 같은 부가 정보를 담고, 빈 줄(CRLF) 뒤에 본문이 옵니다.
HTTP/1.1 200 OK
Content-Type: text/html;charset=UTF-8
Content-Length: 3423
<html>
<body>...</body>
</html>응답의 시작 라인은 HTTP 버전 + 상태 코드 + 사유 문구입니다. 메시지의 정확한 문법은 RFC 9112(HTTP/1.1 메시지 포맷)에 정의돼 있습니다. 메서드와 상태 코드 같은 의미는 RFC 9110(HTTP 의미론)이 버전과 무관하게 규정합니다.
HTTP 메서드와 멱등성
메서드는 자원에 무엇을 하려는지를 나타냅니다. 메서드를 이해할 때 핵심은 안전성(Safety)과 멱등성(Idempotency)입니다. 안전한 메서드는 호출해도 자원을 바꾸지 않습니다. 멱등한 메서드는 같은 요청을 여러 번 보내도 서버 상태가 같게 유지됩니다.
| 메서드 | 안전 | 멱등 | 주 용도 |
|---|---|---|---|
| GET | 예 | 예 | 자원 조회 |
| POST | 아니오 | 아니오 | 새 자원 생성 |
| PUT | 아니오 | 예 | 자원 전체 대체 |
| PATCH | 아니오 | 아니오 | 자원 부분 수정 |
| DELETE | 아니오 | 예 | 자원 삭제 |
POST가 멱등하지 않은 이유는 두 번 호출하면 자원이 두 번 생길 수 있기 때문입니다. 같은 PUT은 매번 같은 값으로 자원을 덮어쓰므로 결과가 같습니다. PUT은 자원 전체를 대체하고, PATCH는 일부만 고친다는 점에서도 다릅니다.
멱등성은 실무에서 재요청 판단 기준이 됩니다. 서버가 타임아웃으로 응답을 못 줬을 때, GET·PUT·DELETE는 그대로 다시 보내도 안전합니다. 반면 POST 재시도는 결제 중복 같은 문제를 부를 수 있어 별도 방어가 필요합니다. 위 속성 분류는 RFC 9110의 메서드 정의를 따릅니다.
상태 코드와 캐시
상태 코드는 요청 처리 결과를 응답에서 알려주는 세 자리 숫자입니다. 앞자리로 다섯 부류로 나뉩니다.
| 부류 | 의미 | 예 |
|---|---|---|
| 1xx | 요청 수신, 처리 중 | 100 Continue |
| 2xx | 정상 처리 | 200 OK, 201 Created |
| 3xx | 추가 행동 필요(리다이렉트·캐시) | 301, 302, 304 |
| 4xx | 클라이언트 오류 | 401, 403, 404 |
| 5xx | 서버 오류 | 500, 503 |
클라이언트가 모르는 코드를 받으면 앞자리 부류로 해석합니다. 예컨대 299는 2xx 성공으로, 451은 4xx 오류로 처리하므로, 새 코드가 추가돼도 클라이언트를 바꿀 필요가 없습니다. 자주 헷갈리는 쌍으로는 401(인증 실패)과 403(인가 실패), 301(영구 이동)과 302(임시 이동)가 있습니다.
캐시 제어에서는 304 Not Modified와 Cache-Control 지시자가 중심입니다. no-cache는 저장은 허용하되 쓰기 전에 서버 재검증을 요구하고, no-store는 저장 자체를 금지합니다. 재검증에는 ETag나 Last-Modified를 조건부 요청에 실어 보냅니다. 자원이 그대로면 서버가 304만 돌려주고 본문은 다시 보내지 않습니다.
무상태성과 쿠키
HTTP는 무상태(Stateless) 프로토콜입니다. 서버가 이전 요청 정보를 기억하지 않으므로, 각 요청은 필요한 정보를 스스로 담아야 합니다. 이 성질 덕분에 어느 서버가 받아도 같은 응답을 줄 수 있어 수평 확장(스케일 아웃)에 유리합니다.
문제는 로그인처럼 상태가 필요한 경우입니다. HTTP 자체는 상태를 모르므로 별도 수단을 얹습니다. 쿠키가 그 표준 장치이며, 서버가 Set-Cookie 헤더로 값을 내려주면 브라우저가 저장했다가 이후 요청의 Cookie 헤더로 돌려보냅니다. 이 메커니즘은 RFC 6265에 정의돼 있습니다.
보통은 쿠키에 민감 정보를 직접 넣지 않고 세션 식별자만 둡니다. 실제 사용자 상태는 서버 세션이 들고, 쿠키는 그 세션을 가리키는 열쇠만 담는 구조입니다. 쿠키 보안 속성으로는 자바스크립트 접근을 막는 HttpOnly, HTTPS 전송만 허용하는 Secure, 교차 사이트 전송을 제한하는 SameSite가 기본입니다.
DNS가 이름을 주소로 바꾸는 과정
브라우저에 도메인을 입력하면 가장 먼저 이름을 IP로 바꿔야 합니다. 해석 순서는 캐시부터 시작합니다. 브라우저 캐시, 운영체제 캐시(hosts 파일 포함)를 보고, 없으면 로컬 DNS인 재귀 리졸버(Recursive Resolver)에 묻습니다. 리졸버는 다시 루트, TLD(Top-Level Domain), 권한(Authoritative) 서버를 따라 내려가며 최종 IP를 찾습니다.
여기서 재귀 질의와 반복 질의를 구분합니다. 클라이언트가 로컬 DNS에 한 번 묻고 최종 답을 받는 흐름이 재귀 질의입니다. 로컬 DNS가 상위 서버에 "다음에 물어볼 곳"만 받아 직접 차례로 묻는 흐름이 반복 질의입니다. 보통 클라이언트와 로컬 DNS 사이는 재귀, 로컬 DNS와 상위 서버 사이는 반복으로 동작합니다.
| 레코드 | 가리키는 대상 |
|---|---|
| A | 도메인의 IPv4 주소 |
| AAAA | 도메인의 IPv6 주소 |
| CNAME | 다른 도메인 이름(별칭) |
| MX | 메일 서버 |
| NS | 해당 도메인의 권한 네임서버 |
| TXT | 임의 텍스트(소유권 확인 등) |
리졸버는 응답을 TTL(Time To Live) 동안 캐싱합니다. TTL은 캐시 유효 시간이라, 짧으면 변경 전파가 빠르고 길면 조회 부하가 줄어듭니다. 둘 사이는 트레이드오프 관계입니다. 없는 이름에 대한 부정 응답(NXDOMAIN)도 캐싱이 권장되며, RFC 2308이 트래픽과 응답 시간 관점에서 이를 설명합니다. 이름 체계와 프로토콜 자체는 RFC 1034와 RFC 1035에 정의돼 있고, 루트 서버 주소는 13개로 운영됩니다(root-servers.org 기준).
HTTP 버전의 진화
같은 HTTP 의미론을 어떤 전송 위에 어떻게 싣느냐가 버전마다 다릅니다. 성능 차이의 원인이 메시지 형식에서 전송 특성으로 옮겨 간 흐름입니다.
| 버전 | 전송 | 핵심 | 남은 병목 |
|---|---|---|---|
| HTTP/1.1 | TCP | Keep-Alive로 연결 재사용 | 응답 순서로 인한 HOL Blocking |
| HTTP/2 | TCP | 스트림 멀티플렉싱, HPACK 헤더 압축 | 패킷 손실 시 TCP 레벨 HOL Blocking |
| HTTP/3 | QUIC(UDP) | 스트림별 독립 손실 복구, QPACK | TCP HOL Blocking 해소 |
HTTP/1.1은 연결을 재사용했지만 한 응답이 늦으면 뒤 응답도 막히는 HOL(Head-of-Line) Blocking이 컸습니다. HTTP/2는 하나의 TCP 연결에서 여러 스트림을 동시에 처리하는 멀티플렉싱과 HPACK(RFC 7541) 헤더 압축으로 HTTP 레벨 병목을 줄였습니다. 다만 여전히 TCP 위에 있어, 패킷 하나가 유실되면 모든 스트림이 함께 대기하는 TCP 레벨 HOL Blocking이 남았습니다.
HTTP/3는 이를 풀려고 UDP 기반 QUIC 위에서 동작합니다. QUIC은 스트림별로 손실을 따로 복구하고, TLS 1.3을 통합해 1-RTT 연결 수립이 가능합니다. 헤더 압축은 QPACK(RFC 9204)을 씁니다. 각 명세는 HTTP/2가 RFC 9113, HTTP/3가 RFC 9114, QUIC이 RFC 9000입니다.
정리
응용 계층은 전송 계층 위에서 무엇을 어떤 형식으로 주고받을지 정하는 영역이고, HTTP와 DNS가 그 핵심입니다. HTTP는 요청-응답 메시지 구조를 바탕으로 메서드의 멱등성, 상태 코드, 캐시, 무상태성과 쿠키라는 규칙을 쌓아 올립니다. DNS는 캐시와 재귀·반복 질의로 도메인 이름을 IP로 바꾸며, TTL로 일관성을 약하게 유지합니다. HTTP 버전의 진화는 같은 의미론을 더 나은 전송 위에 싣는 과정으로, HTTP/3에서 TCP의 HOL Blocking까지 줄였습니다. 더 깊은 검증은 본문에 인용한 RFC 문서를 1차 출처로 확인하면 됩니다.