우수한 소프트웨어와 실용적인 튜토리얼
http의 다양한 버전 간의 차이점에 대해 자세히 알아보세요.
http 프로토콜은 무엇인가요? 왜 http1.x, http2.0으로 나뉘나요?http3.0이 세 가지의 차이점은 무엇일까요? 다음은 각 HTTP 프로토콜 버전의 차이점을 자세히 소개하는 것으로, HTTP 프로토콜을 더 깊이 이해할 수 있도록 도와드립니다.
HTTP란 무엇인가요?
하이퍼텍스트 전송 프로토콜하이퍼텍스트 전송 프로토콜(HTTP)은 인터넷에서 가장 널리 사용되는 네트워크 프로토콜입니다. HTTP의 원래 설계 목적은 HTML 페이지를 게시하고 수신하는 방법을 제공하는 것이었습니다. HTTP 또는 HTTPS 프로토콜을 통해 요청된 리소스는 URI(Uniform Resource Identifier)로 식별됩니다.
HTTP는 요청과 응답으로 구성된 애플리케이션 계층 프로토콜이며, 표준 클라이언트-서버 모델입니다. HTTP는 TCP/IP 기반의 비연결, 비상태 프로토콜입니다(각 HTTP 메시지는 이전 메시지의 상태에 의존하지 않습니다). HTTP는 하위 계층 프로토콜이 안정적인 전송을 제공한다고 가정합니다. 따라서 TCP/IP 프로토콜 모음에서 전송 계층으로 TCP를 사용합니다.
HTTP 프로토콜의 주요 특징은 다음과 같이 요약할 수 있습니다.
- 간단합니다. 클라이언트가 서버에 서비스를 요청할 때 요청 메서드와 경로만 전송하면 됩니다. 일반적인 요청 메서드는 GET, HEAD, POST입니다. 각 메서드는 클라이언트와 서버 간의 서로 다른 통신 유형을 지정합니다.
- 유연성: HTTP는 모든 유형의 데이터 객체 전송을 허용합니다. 전송되는 데이터 객체 유형은 Content-Type으로 표시됩니다.
- 요청-응답 모드: 클라이언트가 서버에 요청을 할 때마다 연결이 설정되고, 서버는 클라이언트의 요청을 처리한 후 연결을 끊습니다.
- 무상태: HTTP는 무상태 프로토콜입니다. 무상태란 프로토콜에 트랜잭션 처리를 위한 메모리가 없음을 의미합니다. 상태가 없다는 것은 후속 처리에 이전 정보가 필요하면 재전송해야 한다는 것을 의미합니다.
HTTP 작업 프로세스
HTTP는 요청과 응답으로 구성되며 표준 클라이언트-서버 모델(B/S)입니다. HTTP 프로토콜은 항상 클라이언트가 요청을 시작하고 서버가 응답을 보내는 것으로 시작합니다.
1. 클라이언트(브라우저)가 서버(웹 서버)에 연결 요청을 적극적으로 보냅니다(이 단계에서는 서버의 IP 주소를 얻기 위해 DNS 확인 프로토콜이 필요할 수 있음).
2. 서버는 연결 요청을 수락하고 연결을 설정합니다. (1단계와 2단계는 우리에게 익숙한 TCP 3방향 핸드셰이크입니다.)
3. 클라이언트는 이 연결을 통해 GET과 같은 HTTP 명령을 서버로 전송합니다("HTTP 요청 메시지").
4. 서버는 명령을 수신하고 명령에 따라 해당 데이터를 클라이언트로 전송합니다("HTTP 응답 메시지").
5. 클라이언트는 서버로부터 전송된 데이터를 수신합니다.
6. 데이터를 보낸 후 서버는 적극적으로 연결을 끊습니다("TCP 4방향 끊김").
요약하자면, 클라이언트/서버 전송 프로세스는 네 가지 기본 단계로 나눌 수 있습니다.
1) 브라우저가 서버와 연결을 설정합니다(TCP 3방향 핸드셰이크)
2) 브라우저가 서버에 HTTP 요청 메시지를 보냅니다.
3) 서버가 브라우저 요청에 응답합니다.
4) 연결을 끊습니다. ("TCP 4방향 분리")
HTTP1.X 원칙
http1.0의 동작 과정에서는 HTTP를 이용한 데이터 전송에 3번의 핸드셰이크와 4번의 웨이브가 필요하여 지연시간이 증가합니다.
TCP 연결을 연결 상태로 유지하고 일부 지연을 줄이기 위해 Keep-alive가 http1.1에 추가되었습니다.
HTTP 1.x의 문제
- 연결을 재사용할 수 없습니다. 연결을 재사용할 수 없으므로 각 요청은 3-웨이 핸드셰이크와 슬로우 스타트를 거칩니다. 3-웨이 핸드셰이크는 지연 시간이 긴 시나리오에서 더 뚜렷한 영향을 미치는 반면, 슬로우 스타트는 많은 수의 작은 파일 요청에 더 큰 영향을 미칩니다.
- HOLB(Head-Of-Line Blocking)로 인해 대역폭이 완전히 활용되지 않아 그에 따른 상태 요청이 차단됩니다.홀브첫 번째 패키지가 차단되어 여러 패키지가 동시에 차단되는 현상을 말합니다. 한 페이지가 많은 리소스를 요청해야 할 때, HOLB(Head of Line Blocking)는 남은 리소스가 다른 리소스 요청이 완료될 때까지 기다린 후, 최대 요청 수에 도달하면 요청을 시작하도록 합니다. HOLB 문제에 대한 해결책은 다음과 같습니다.
- HTTP 1.0: 이전 요청이 반환된 후에 다음 요청을 보내야 합니다.
요청-응답
당연히 요청이 오랫동안 반환되지 않으면 이후의 모든 요청은 차단됩니다. - HTTP 1.1: 파이프라이닝을 사용하여 문제를 해결해 보세요. 즉, 브라우저가 한 번에 여러 요청(동일한 도메인 이름, 동일한 TCP 링크)을 전송할 수 있습니다. 그러나 파이프라이닝은 응답이 순서대로 반환되어야 합니다. 이전 요청이 시간이 많이 걸리는 경우(예: 대용량 이미지 처리) 서버가 이미 후속 요청을 처리했더라도 이전 요청이 처리될 때까지 기다렸다가 순서대로 반환을 시작합니다. 따라서 파이프라이닝은 HOLB 문제를 부분적으로만 해결합니다.
- 스프라이트, 인라인 작은 이미지 등을 가져옵니다.
- 요청 헤더는 큰 오버헤드를 가집니다. 메시지 헤더는 일반적으로 "사용자 에이전트", "쿠키", "수락", "서버"(아래 참조)와 같은 많은 고정 헤더 필드를 포함하며, 그 크기는 수백 또는 수천 바이트에 달하지만, 본문은 종종 수십 바이트에 불과합니다. 헤더의 내용이 많으면 전송 비용이 어느 정도 증가합니다.
- 보안 요소 HTTP 1.x에서 데이터를 전송할 때 모든 전송 내용은 일반 텍스트 형식입니다. 클라이언트와 서버 모두 상대방의 신원을 확인할 수 없으므로, 어느 정도 데이터 보안을 보장할 수 없습니다.
- HTTP/1.x에는 푸시 메커니즘이 없기 때문에 서버 푸시 메시지는 지원되지 않습니다. 따라서 일반적으로 두 가지 방법이 있습니다. 하나는 클라이언트가 정기적으로 폴링하는 폴링이고, 다른 하나는 웹소켓입니다.
2.0 작동 방식
2015년에 HTTP/2가 출시되었습니다. HTTP/2는 현재 HTTP 프로토콜(HTTP/1.x)을 대체하지만, 완전히 새롭게 작성된 것은 아닙니다. HTTP 메서드/상태 코드/의미는 HTTP/1.x와 동일합니다.HTTP/2는 SPDY를 기반으로 하며 성능에 중점을 둡니다. 가장 큰 목표 중 하나는 사용자와 웹사이트 간에 단 하나의 연결만 사용하는 것입니다..
HTTP2가 해결하는 문제
http1.x에서 발생하는 문제에 대응하여 http2에는 다음과 같은 솔루션이 있습니다.
- 이진 전송 HTTP/2는 HTTP 1.x의 텍스트 형식 대신 이진 형식을 사용하여 데이터를 전송합니다. 이진 프로토콜은 파싱하는 데 더 효율적입니다. HTTP/1 요청 및 응답 메시지는 시작 줄, 헤더, 그리고 엔티티 본문(선택 사항)으로 구성되며, 각 부분은 텍스트 줄바꿈으로 구분됩니다. HTTP/2는 요청 및 응답 데이터를 더 작은 프레임으로 나누고 이진 형식으로 인코딩합니다.
HTTP/2를 이해하기 전에 몇 가지 일반적인 용어를 알아야 합니다.
- 스트림: 양방향 스트림입니다. 연결에는 여러 개의 스트림이 있을 수 있습니다.
- 메시지: 논리적인 요청과 응답입니다.
- 프레임: 데이터 전송의 최소 단위입니다. 각 프레임은 특정 스트림 또는 전체 연결에 속합니다. 메시지는 여러 프레임으로 구성될 수 있습니다. 프레임은 HTTP/2에서 데이터 전송의 최소 단위입니다. 프레임은 다음과 같이 정의됩니다.
길이: 프레임의 길이입니다. 기본 최대 길이는 16KB입니다. 더 큰 프레임을 전송하려면 최대 프레임 크기를 명시적으로 설정해야 합니다.
유형: DATA, HEADERS, PRIORITY 등과 같은 프레임 유형
플래그 및 R: 예약된 비트.
스트림 식별자: 해당 프레임이 속한 스트림을 식별합니다. 0이면 해당 프레임이 전체 연결에 속함을 의미합니다.
프레임 페이로드: 유형에 따라 다양한 형식이 있습니다.
스트림에는 많은 중요한 기능이 있습니다.
- 연결에는 여러 개의 스트림이 포함될 수 있으며, 여러 스트림에서 보낸 데이터는 서로 영향을 미치지 않습니다.
- 스트림은 일방적으로 사용될 수도 있고, 클라이언트와 서버가 공유할 수도 있습니다.
- 스트림은 두 세그먼트 중 하나로 닫힐 수 있습니다.
- 스트림은 프레임을 보내는 순서를 결정하고, 다른 쪽에서는 프레임을 받은 순서대로 처리합니다.
- 스트림은 고유 ID로 식별됩니다. 스트림이 클라이언트에 의해 생성되면 ID는 홀수이고, 서버에 의해 생성되면 ID는 짝수입니다.
이진 전송은 TCP 프로토콜의 일부 기능을 애플리케이션 계층으로 이전하여 원래의 "헤더+본문" 메시지를 여러 개의 작은 이진 "프레임"으로 분할합니다. "헤더" 프레임에는 헤더 데이터를 저장하고 "데이터" 프레임에는 엔티티 데이터를 저장합니다. HTP/2 데이터가 프레임화된 후에는 "헤더+본문" 메시지 구조가 완전히 사라지고 프로토콜은 "조각"만 인식합니다.
HTTP/2에서는 동일한 도메인 이름으로 이루어지는 모든 통신이 단일 연결에서 완료되며, 이 연결은 여러 개의 양방향 데이터 스트림을 전송할 수 있습니다. 각 데이터 스트림은 메시지 형태로 전송되며, 메시지는 하나 이상의 프레임으로 구성됩니다. 여러 프레임은 순서에 관계없이 전송될 수 있으며, 프레임 헤더의 스트림 식별자를 기반으로 재구성될 수 있습니다.
헤더 압축
HTTP/1에서는 헤더가 텍스트 형태로 전송되므로, 헤더에 쿠키와 사용자 에이전트가 포함될 경우 수백에서 수천 바이트를 매번 반복적으로 전송해야 할 수 있습니다. HTTP/2는 기존의 압축 알고리즘을 사용하지 않고, 특수한 "HPACK" 알고리즘을 개발하고, 클라이언트와 서버 모두에 "사전"을 구축하며, 반복되는 문자열을 나타내기 위해 인덱스 번호를 사용하고, 정수와 문자열을 압축하기 위해 허프만 코딩을 사용하여 50%~90%의 높은 압축률을 달성합니다.
자세한 내용은 다음과 같습니다.
- HTTP/2는 클라이언트와 서버에서 "헤더 테이블"을 사용하여 이전에 전송된 키-값 쌍을 추적하고 저장합니다. 각 요청과 응답에서 동일한 데이터가 더 이상 전송되지 않습니다.
- 헤더 테이블은 HTTP/2 연결 동안 항상 존재하며 클라이언트와 서버에 의해 점진적으로 업데이트됩니다.
- 각각의 새로운 헤더 키-값 쌍은 현재 테이블의 끝에 추가되거나 테이블의 이전 값을 대체합니다.
- 다중화(요청 및 응답 다중화) 동일한 도메인 이름은 하나의 TCP 연결만 차지하면 됩니다. 하나의 TCP 연결에서 다른 쪽에게 프레임을 연속적으로 전송할 수 있습니다. 각 프레임의 스트림 식별자는 프레임이 속한 스트림을 나타냅니다. 상대방이 프레임을 수신하면 각 스트림의 모든 프레임이 스트림 식별자에 따라 결합되어 완전한 데이터 블록을 형성합니다.
위 프로토콜 분석에서 언급된 스트림 ID는 연결 공유 메커니즘으로 사용됩니다. 하나의 요청은 하나의 스트림에 대응하며 ID가 할당되므로, 연결에 여러 스트림이 존재할 수 있으며 각 스트림의 프레임은 무작위로 혼합될 수 있습니다. 수신자는 스트림 ID를 기반으로 프레임을 여러 요청에 할당할 수 있습니다. 요청과 응답은 서로 영향을 미치지 않습니다.
멀티플렉싱(MultiPlexing)은 긴 연결의 확장 기능과 같습니다. 각 요청은 무작위로 혼합될 수 있으며, 수신자는 요청 ID에 따라 해당 요청을 여러 서버 요청에 할당할 수 있습니다.
멀티플렉싱에서는 스트림 우선순위(스트림 종속성)가 지원되므로 클라이언트가 서버에 어떤 콘텐츠가 우선순위가 더 높은 리소스인지 알려서 먼저 전송할 수 있습니다.
- 서버 푸시 HTTP/2에 추가된 또 다른 강력한 새 기능은 서버가 클라이언트 요청에 여러 개의 응답을 보낼 수 있다는 것입니다. 즉, 서버는 초기 요청에 대한 응답 외에도 클라이언트가 명시적으로 요청하지 않아도 클라이언트에 추가 리소스를 푸시할 수 있습니다.
서버는 능동적으로 푸시할 수 있으며, 클라이언트는 수신 여부를 선택할 권리가 있습니다. 서버가 푸시한 리소스가 브라우저에 캐시된 경우, 브라우저는 RST_STREAM 프레임을 전송하여 해당 리소스를 거부할 수 있습니다.
능동적 푸시는 동일 출처 정책을 준수합니다. 서버는 임의로 타사 리소스를 클라이언트에 푸시할 수 없으며, 양측의 확인을 받아야 합니다.
- 향상된 보안 HTTP/2는 HTTP/1의 "일반 텍스트" 기능을 그대로 유지하며 이전과 마찬가지로 일반 텍스트로 데이터를 전송할 수 있습니다. 암호화된 통신을 강제로 사용하지는 않습니다. 하지만 형식은 여전히 이진 형식이지만, 복호화가 필요하지 않습니다.
HTTPS가 일반적인 추세이고 Chrome과 Firefox와 같은 주류 브라우저는 암호화된 HTTP/2만 지원한다고 공개적으로 발표했기 때문에 "실제로" HTTP/2는 암호화되어 있습니다. 즉, 인터넷에서 흔히 볼 수 있는 HTTP/2는 "https" 프로토콜 이름을 사용하고 TLS 기반으로 실행됩니다. HTTP/2 프로토콜은 두 개의 문자열 식별자를 정의합니다. 암호화된 HTTP/2의 경우 "h2", 일반 텍스트 HTTP/2의 경우 "h2c"입니다.
HTTP2의 문제
- http1.x와 http2는 모두 TCP 기반입니다. TCP는 안전하고 안정적인 전송 프로토콜이지만, 연결 설정 지연 시간이 여전히 다소 높습니다. 이는 주로 TCP와 TCP+TLS 간의 연결 설정 지연 때문입니다.
- TCP 헤드 오브 라인(Head-of-Line) 혼잡 문제는 해결할 수 없습니다. HTTP2는 다중화를 통해 HTTP 계층 헤드 오브 라인 혼잡 문제를 해결하지만, TCP 실패 재전송 문제는 여전히 해결 불가능합니다.
HTTP 3.0 원칙
TCP는 매우 오랫동안 존재해 왔기 때문에 다양한 장치에서 사용되었으며, 이 프로토콜은 운영 체제에 의해 구현되므로 업데이트하는 것은 실용적이지 않습니다.
이러한 이유로,Google은 UDP 프로토콜을 기반으로 QUIC 프로토콜을 만들어 HTTP/3에 사용했습니다.HTTP/3는 이전에 HTTP-over-QUIC라고 불렸습니다. 이 이름에서 HTTP/3의 가장 큰 변화는 QUIC의 사용임을 알 수 있습니다. QUIC(Quick UDP Internet Connections)는 UDP를 기반으로 하며, UDP의 속도와 효율성을 기반으로 합니다. 동시에 QUIC은 TCP, TLS, HTTP/2의 장점을 통합하고 최적화합니다.
QUIC의 두 번째 목표는 연결 및 전송 지연 시간을 줄이고, 혼잡을 피하기 위해 각 방향의 대역폭을 추정하는 것입니다. 또한, 혼잡 제어 알고리즘을 커널 공간이 아닌 사용자 공간으로 이동하고, 순방향 오류 정정(FEC)을 통해 확장하여 오류 발생 시 성능을 더욱 향상시킵니다.
HTTP3에서 구현된 기능
- 빠른 핸드셰이크 기능을 구현하려면 HTTP/2 연결에 3 RTT가 필요합니다. 세션 재사용, 즉 첫 번째 핸드셰이크에서 계산된 대칭 키가 캐시되는 경우 2 RTT가 추가로 필요합니다. 또한 TLS가 1.3으로 업그레이드되면 HTTP/2 연결에는 2 RTT가 필요하고, 세션 재사용에는 1 RTT가 필요합니다. 그러나 HTTP/3는 첫 번째 연결에는 1 RTT만 필요하고 이후 연결에는 0 RTT가 필요합니다.
QUIC 프로토콜을 사용하는 클라이언트와 서버는 1RTT를 사용해야 합니다.키 교환, 사용된 교환 알고리즘은 DH(Diffie-Hellman)입니다.디피-헬만 알고리즘.
처음 접속 시클라이언트와 서버 간의 주요 협상 및 데이터 전송 프로세스여기에는 DH 알고리즘의 기본 프로세스가 포함됩니다.
- 클라이언트는 처음으로 연결한 서버에 client hello 요청을 보냅니다.
- 서버는 소수 p와 정수 g를 생성하고, 개인 키 a로 사용할 난수도 생성합니다. 그런 다음 공개 키 A = mod p를 계산합니다. 서버는 세 요소 A, p, g를 구성(config)으로 패키징하여 클라이언트로 전송합니다.
- 클라이언트는 자신의 개인 키 b를 무작위로 생성한 후, 설정 파일에서 g와 p를 읽어 클라이언트 공개 키 B = mod p를 계산합니다. 그런 다음 클라이언트는 A, p, b를 기반으로 초기 키 K를 계산합니다. B와 K가 계산된 후, 클라이언트는 K를 사용하여 HTTP 데이터를 암호화하고 B와 함께 서버로 전송합니다.
- 클라이언트는 자신의 개인 키 b와 서버에서 보낸 구성에서 읽은 서버의 공개 키를 사용하여 후속 데이터 암호화를 위한 키 K = mod p를 생성합니다.
- 클라이언트는 키 K를 사용하여 비즈니스 데이터를 암호화하고 자체 공개 키를 추가한 다음 서버로 전달합니다.
- 서버는 자신의 개인 키 a와 클라이언트 공개 키 B를 기반으로 클라이언트 암호화 키 K = mod p를 생성합니다.
- 데이터 보안을 위해 위에서 생성된 키 K는 한 번만 사용됩니다. 이후 서버는 동일한 규칙에 따라 새로운 공개 키와 개인 키 세트를 생성하고, 이 공개 키와 개인 키 세트를 사용하여 새로운 키 M을 생성합니다.
- 서버는 새로운 공개 키와 새로운 키 M으로 암호화된 데이터를 클라이언트로 전송합니다. 클라이언트는 새로운 서버의 공개 키와 원래의 개인 키를 기반으로 키 M을 계산하고 이를 복호화합니다.
- 클라이언트와 서버 간의 모든 후속 데이터 상호작용은 키 M을 사용하여 완료되고, 키 K는 한 번만 사용됩니다.
클라이언트와 서버가 처음 연결되면 서버는 다음을 전달합니다.구성 패키지여기에는 서버 공개 키와 두 개의 난수가 포함되어 있습니다.클라이언트는 구성을 저장합니다., 나중에 다시 연결할 때 직접 사용할 수 있으므로 1RTT를 건너뛰고 0RTT 비즈니스 데이터 상호 작용을 실현할 수 있습니다.
클라이언트는 시간 제한 동안 구성을 저장하며, 구성이 만료된 후에도 첫 번째 연결 시 키 교환이 여전히 필요합니다.
- 통합 TLS 암호화 기능
- 안전한 전진전방 보안은 키가 유출되더라도 이전에 암호화된 데이터는 유출되지 않는다는 것을 의미합니다. 현재 데이터에만 영향을 미치며 이전 데이터에는 영향을 미치지 않습니다..
QUIC은 구성의 유효 기간을 사용하고 이후 암호화 및 복호화에 사용되고 상호작용이 완료되면 파기되는 새로운 키를 생성하여 전방 보안을 달성합니다.
- 순방향 오류 정정(Forward Error Correction)은 순방향 오류 정정 부호(Forward Error Correction Code)라고도 하며, FEC(Frequency Correction)로 줄여서 부르기도 합니다. 이는 데이터 통신의 신뢰성을 높이는 방법입니다. 단방향 통신 채널에서 오류가 발견되면 수신자는 더 이상 전송을 요청할 권리가 없습니다.
FEC는 데이터와 함께 중복된 정보를 전송하는 방법으로, 전송 중에 오류가 발생하면 수신기가 데이터를 재구성할 수 있습니다.
QUIC가 데이터 그룹을 보낼 때마다 데이터를 처리합니다.XOR 연산결과는 FEC 패킷으로 전송됩니다. 이 데이터 세트를 수신한 후, 수신자는 데이터 패킷과 FEC 패킷을 기반으로 검증 및 오류 정정을 수행할 수 있습니다. 데이터를 10개의 패킷으로 나눈 후, 각 패킷을 차례로 XOR 연산하고, 연산 결과를 데이터 패킷과 함께 FEC 패킷으로 전송합니다. 전송 과정에서 데이터 패킷이 손실된 경우, 나머지 9개의 패킷과 FEC 패킷을 기반으로 손실된 패킷의 데이터를 유추할 수 있어 프로토콜의 내결함성이 크게 향상됩니다.
- 안전한 전진전방 보안은 키가 유출되더라도 이전에 암호화된 데이터는 유출되지 않는다는 것을 의미합니다. 현재 데이터에만 영향을 미치며 이전 데이터에는 영향을 미치지 않습니다..
- 멀티플렉싱, TCP HTTP2.0 프로토콜의 Head-of-Line 블로킹 문제 해결멀티플렉싱 메커니즘HTTP 계층에서 헤드 오브 라인 블로킹 문제를 해결하지만TCP 계층은 여전히 HOL(Head-of-Line) 블로킹 문제가 있습니다..
TCP 프로토콜이 데이터 패킷을 수신한 후, 이 부분의 데이터는 순서가 어긋나 도착할 수 있지만, TCP는 상위 계층에서 사용할 수 있도록 모든 데이터를 수집, 정렬, 통합해야 합니다.패킷 중 하나가 손실되면 재전송을 기다려야 하며, 이로 인해 패킷 손실이 발생하여 전체 연결의 데이터 사용이 차단됩니다..
QUIC 프로토콜은 UDP 프로토콜을 기반으로 구현됩니다.다중 스트림, 흐름 사이에는상호 영향 없음패킷 손실이 발생하더라도 흐름에 미치는 영향은 매우 작아서 헤드 오브 라인 블로킹 문제가 해결됩니다.
- TCP와 유사한 흐름 제어를 구현합니다(… 이 부분은 길기 때문에 참조를 참조하세요)