Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ko/part6: Create korean translation of part 6.The HTTP2 protocol #219

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 96 additions & 3 deletions ko/part6.md
Original file line number Diff line number Diff line change
@@ -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

<img style="float: right;" src="https://raw.githubusercontent.com/bagder/http2-explained/master/images/frame-layout.png" />

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 프레임만 흐름 제어의 대상이 됩니다.