diff --git a/ko/part6.md b/ko/part6.md index 439fb07..930066b 100644 --- a/ko/part6.md +++ b/ko/part6.md @@ -1,5 +1,98 @@ -#6. http2 프로토콜 +# 6. HTTP2 프로토콜 -(번역되지 않은) +충분한 배경, 역사, 정책들을 바탕으로 우리가 여기에 왔습니다. 이제 HTTP2를 구성하는 개념과 세부 항목들로 뛰어들어 봅시다. -[영어](../en/part6.md) +## 6.1 Binary + +HTTP2는 바이너리 프로토콜입니다. + +만약 당신이 인터넷 프로토콜을 사용해보거나 개선한 경험이 있다면, text/ascii기반의 프로토콜로 데이터를 전송하는 방법이 사람이 읽거나 수정하기 편하다는 등의 이유로, 더 좋다는 주장을 할 수 있습니다. + +HTTP2는 binary를 통해 framing을 더 쉽게 합니다. 실제로 HTTP 1.1과 같은 text기반의 프로토콜에서 frame의 시작부분과 첫 부분을 찾는 것은 매우 복잡한 일입니다. optional whitespace를 사용하는것과 같은 방법에서 벗어나, 구현이 간단해집니다. + +또한, 실제 프로토콜에 관련된 내용을 Framing에서는 훨씬 쉽게 분리할 수 있습니다. 이는 HTTP1에서 복잡하게 섞여있습니다. + +전송되는 데이터가 압축되거나 TLS를 통해 암호화된다는 것은, Text기반으로 전송되는 장점을 감소시킵니다. 어차피 인간이 읽기 힘들어지기 때문이죠. 우리는 간단하게 HTTP2 프로토콜 레벨에서 어떤 일이 일어나는지에 대해, Wireshark같은 검사기에 익숙해지기만 하면 됩니다. + +이 프로토콜을 디버깅하려면 curl과 같은 도구를 사용하거나 Wireshark의 HTTP2 dissector등으로 네트워크 스트림을 분석해야 합니다. + +## 6.2 The binary format + + + +HTTP2는 binary frame을 보냅니다. 전송할 수 있는 다양한 프레임 타입이 있으며, 동일하게 Type, Flag, Stream Identifier와 frame payload를 갖고 있습니다. + +HTTP2에는 10개의 frame type이 존재하며, HTTP1.1의 특징인 HEADER와 DATA가 이에 매핑됩니다. 다른 유형에 대해서는 차차 설명하겠습니다. + + +## 6.3 Multiplexed stream + +이전 섹션에서 언급한 Stream identifier는 각 프레임을 http2의 "stream"으로 보내는것과 관련이 있다. Stream은 HTTP2기반의 클라이언트와 서버 사이의 독립적인 양방향 프레임 시퀀스이다. + +하나의 HTTP2 커넥션은 여러개의 동시에 열린 스트림들을 포함할 수 있으며, 각각의 종단점에는 여러 개의 프레임을 끼워넣을 수 있습니다. Stream들은 일방적으로 커넥션을 맺거나 사용할 수 있고, 클라이언트 또는 서버에서 공유할 수 있으며, endpoint에서 종료할 수 있습니다. 스트림 내에서 프레임이 전송되는 순서는 중요합니다. 수신측은 프레임을 받은 순서대로 처리합니다. + +스트림 다중화 (Stream Multiplexing)는 하나의 커넥션에서 많은 스트림 묶음이 혼합됨을 의미합니다. 2개 이상의 개별 데이터 시퀀스들은 하나로 이어지고, 수신측에서 다시 나뉘어 전달됩니다. 여기 두 개의 기차가 있습니다: + +![one train](https://raw.githubusercontent.com/bagder/http2-explained/master/images/train-justin.jpg) +![another train](https://raw.githubusercontent.com/bagder/http2-explained/master/images/train-ikea.jpg) + +두 개의 기차는 같은 커넥션으로 다중화되었습니다. + +![multiplexed train](https://raw.githubusercontent.com/bagder/http2-explained/master/images/train-multiplexed.jpg) + +## 6.4. 우선순위와 의존성 + +각 스트림은 weight라고도 알려진, 우선순위를 가지고 있는데, 이는 가장 먼저 보내야 하는 리소스인 경우 어떤 스트림이 가장 중요한지를 고려해 서버가 처음으로 전송할 스트림을 강제하는 데 사용됩니다. + +PRIORITY 프레임을 사용하는 경우, 클라이언트는 서버에게 현재 스트림이 어떤 스트림에 의존해있는지 말해줄 수 있습니다. 이는 클라이언트가 우선순위 "트리"를 만들고, 자식 스트림이 부모 스트림에 의존적인 관계라는 것을 나타냅니다. + +우선순위 가중치와 의존성은 런타임에 동적으로 수정될 수 있어, 브라우저는 유저가 이미지로 가득한 페이지를 스크롤할 때, 어떤 이미지가 가장 중요한지를 판단하거나, 탭을 전환하는 경우 갑작스럽게 집중되는 스트림의 우선순위를 지정할 수 있습니다. + +## 6.5. 헤더 압축 + +HTTP는 stateless한 프로토콜입니다. 이는 모든 요청이 서버가 요청을 처리하는 데 필요한 많은 양의 메타데이터를 저장하지 않고 매번 가져와야 한다는 의미입니다. HTTP2는 이 패러다임을 바꾸지 않기때문에, 여전히 같은 방식으로 동작합니다. + +이는 HTTP가 반복적인 동작을 하게 합니다. 클라이언트가 서버에게 이미지나 웹페이지같은 리소스를 많이 요청했을 때, 서버에는 대량의 엇비슷한 요청 메시지가 쌓입니다. 이 비슷한 메시지 내용에는 압축이 필요합니다. + +페이지당 구성 객체의 수가 늘어나는 동안(앞서 언급했듯), 쿠키와 요청의 크기 역시 커졌습니다. 더불어 쿠키는 모든 요청에 포함되어야 하며, 여러 요청에 같은 쿠키가 자주 포함됩니다. + +HTTP 1.1 요청 크기는 실제로 커져서 때때론 TCP의 초기 윈도우 사이즈로 커버할 수 없는 크기로도 요청되었다. 이는 요청을 매우 느리게했는데, TCP 수신자가 ACK를 통해 요청을 완료해 수신 윈도우에 여유공간이 생겨야 하기 때문입니다. 이 때문에 종종 full round trip하는 시간동안 전체 요청을 보낼 수 없습니다. 이는 압축의 필요성에 대한 또다른 주장이 됩니다. + + +### 6.5.1. 압축은 까다로운 주제입니다. + +HTTPS와 SPDY 압축에서는 [BREACH](https://en.wikipedia.org/wiki/BREACH_%28security_exploit%29) 와 [CRIME](https://en.wikipedia.org/wiki/CRIME) 에 대한 취약점이 발견되었습니다. 알려진 텍스트를 스트림에 넣어 출력값이 어떻게 달라지는지를 판단해 공격자가 전송되는 데이터를 확인할 수 있는 취약점입니다. + + +이런 공격들에 취약해지지 않고 데이터를 압축하는 것은 신중함과 어느정도의 아이디어가 필요합니다. 이는 HTTPbis팀이 시도한 내용입니다. + +[HPACK](https://www.rfc-editor.org/rfc/rfc7541.txt) 은, Header Compression for HTTP2라는 이름에서 알 수 있듯, http2 헤더용으로 특별히 제작된 압축 형식이며, 별도의 rfc 초안을 통해 논의되었습니다. 특정 헤더를 압축하지 않도록 중개자에게 요청하는 비트나 프레임의 선택적 패딩을 통해 압축형식으로 인한 취약점이 발생하기 힘들도록 만듭니다. + + + +HPACK의 제작자 중 한명인 Roberto Peon의 말에 따르면 +> “HPACK은 정보 유출에 대한 단순 구현을 어렵게 만들고, +> 인코딩 및 디코딩을 매우 빠르고/저렴하게 만들고, +> 압축 컨텍스트 크기에 대한 수신기 제어를 제공하고, +> 프록시 재인덱싱(프런트엔드 간의 공유 상태)을 허용하도록 설계되었습니다. +> 이는 Huffman-encoded 문자열의 빠른 압축을 위함입니다. + + +## 6.6. 초기화: 마음가짐을 바꾸기 + +HTTP 1.1의 결점 중 하나는, HTTP 메시지를 고정된 Content-Length로 전송했으면, 이를 쉽게 멈출 수 없다는 점입니다. 물론 TCP연결을 해제하면 되지만, 이는 TCP handshake를 통해 다시 연결을 협상해야 하는 비용이 있습니다. + +더 나은 솔루션은 메시지를 멈추고 다시 보내는 것입니다. 이는 HTTP2의 RST_STREAM 프레임을 보내 수행할 수 있고, 대역폭 낭비와 커넥션을 해제시킬 필요를 없게 해줍니다. + + +## 6.7. 서버 푸시 + +이는 "캐시 푸시"로도 알려져있습니다. 이 아이디어는 클라이언트가 리소스 X를 요청하면, 서버는 클라이언트 Z의 필요를 예측하므로서 클라이언트가 다시 요청하지 않아도 됩니다. 이는 클라이언트의 캐시에 리소스 Z를 끼워넣어, 클라이언트가 원할 때 그 데이터가 존재하도록 합니다. + +서버 푸시는 클라이언트가 명시적으로 서버의 동작을 해야 합니다. 그럼에도 클라이언트가 부분 리소스를 받지 않기 원한다면, RST_STREAM타입 요청을 통해 신속하게 푸시 스트림을 종료할 수 있습니다. + +## 6.8. 흐름제어 + +개별 http2 스트림에는 데이터를 제어할 수 있는 윈도우가 있습니다. SSH가 어떻게 작동하는지 알고 있다면 이것은 스타일과 철학이 매우 유사합니다. + +모든 스트림에 대해 양쪽 끝은 들어오는 데이터를 처리할 충분한 공간이 있고 다른 쪽 끝은 창이 확장될 때까지 해당 양의 데이터만 보낼 수 있음을 피어에게 알려야 합니다. DATA 프레임만 흐름 제어의 대상이 됩니다. \ No newline at end of file