질문과 답변

Q. 하나의 포트로 수많은 클라이언트의 연결을 받기 위해 사용하는 전략은 무엇무엇이 있을까?

How do multiple clients connect simultaneously to one port, say 80, on a server? (stackoverflow)

stateless 프로토콜 (ex. UDP)

  • 애초에 '연결'이라는 것이 존재하지 않는다.

  • 여러 패킷이 연결과 상관없이 도착하는 순서대로 도착한다.

stateful 프로토콜 (ex. TCP)

  • '연결'의 단위는 소스 ip, 소스 포트,목적지 ip, 목적지 포트 의 4-tuple이다.

    • TCP Connection의 식별자 : 4-tuple

    • IP Connection의 식별자 : 4-tuple + protocol

  • 4개의 모든 조합이 중복되지 않는 이상, 서로 다른 연결이 만들어진다.

  • 따라서 하나의 호스트:포트 조합이 서로 다른 수많은 클라이언트들과 연결되더라도 문제될 것이 없다.

Q. 한 TCP 소켓은 어떻게 동시에 recv / send 할 수 있을까?

소켓과 스트림

일식

  • 서로 다른 thread를 이용할 수 있다.

  • recv나 send는, 단지 packet을 recv, send할 뿐이므로 blocking 작업이 필요 없이 그냥 가능하다.

  • 만일 긴 작업이 필요하다면 socket 단에서 하는 게 아니라 작업이 끝나고 socket에는 결과만 밀어넣어주면 되지 않을까.

  • 로직상으로 queueing을 구현할 수 있다.

Q. HTTP/2와 HTTP/3은 커넥션을 어떻게 관리할까?

http 단일 커넥션에서는 여러 개의 파일 또는 큰 파일을 받을 때 발생하는 비효율적인 문제가 발생하였다.

이를 해결하기 위해 http/1.1 에서는 persistent, 파이프라이닝 등을 사용하였다.

하지만 HoLB 등의 문제는 여전히 발생하였다. http/2 와 http/3 의 커넥션은 어떻게 발전되었을까?

http/2

여러 개의 파일을 fully multiplexed 하게 작동하게 하기 위해 새로운 개념이 추가된다.

Message vs Stream, Frame

  • Message : HTTP/1.1 에서 주고 받는 요청과 응답의 단위

  • Frame : HTTP/2 부터 정의된 message 를 쪼갠 단위(Header Frame 또는 Data Frame). Frame 들이 합쳐져서 하나의 Message 가 된다.

  • Stream : 한 커넥션 안에서 여러 Frame을 주고 받는 흐름의 단위. 하나 이상의 Message 가 될 수 있음. 고로, 여러 개의 요청과 응답을 한 커넥션에서 주고받을 수 있다.

HoLB?

이게 맞는지..?

  • Message 기반 : 요청/응답 시 요청을 여러 개 보내더라도 서버에서 이전에 온 요청을 처리하고 있는 중이면 이후의 요청에 대해서 blocking 이 발생한다.

  • Stream 기반 : 요청과 응답이 한 쌍으로 작용하지 않아 blocking 이 발생하지 않고 요청과 응답이 서로 다른 메시지를 가질 수 있어 여러 메시지가 병렬적으로 오갈 수 있다. 이는 밑에서 설명할 Server Push 가 가능한 이유이기도 하다.

그 외

그 외에도 성능을 높이기 위해 여러가지 기술이 추가되었다.

  • binary data 로 전송 (header 는 압축도 해서 보냄)

  • Server Push Api : 서버가 미리 예측해서 리소스를 전송함

  • 응답 받을 리소스의 우선순위를 지정할 수 있다.

http/3 (quic)

위에서 언급된 HoLB 는 Application Layer (HTTP) 의 HoLB 문제이고 TCP 역시 순서에 의존하여 수송신하고 재조립되기 때문에 Transport Layer (TCP) 에서 발생하는 HoLB는 http/2 에서도 발생한다.

이를 해결하기 위해 프로토콜을 TCP 에서 UDP 로 변경하고 여러가지 튜닝을 하여 신뢰성 있게 사용한다.

TCP VS UDP (QUIC)

https://www.slideshare.net/deview/quic-67614063

  • 순서 없는 패킷

    • TCP 에는 패킷에 순서가 있음

    • QUIC 에는 순서가 없음.

      특정 패킷의 지연이 다른 패킷 응답 속도에 영향을 미치지 않게 한다. (TCP 의 HoLB 문제 해결)

  • 연결 수립 비용 대폭 감소

    • QUIC 은 핸드쉐이크로 연결을 수립하지 않고 Connection id 를 사용하여 수립한다. 암호화 연결 수립에 0RTT ~ 1RTT 가 소요된다. (TCP의 경우 TLS 포함 약 4.5RTT)

  • 등등..

일식

http2

  • 하나의 tcp connection 으로 통신.

  • 모든 http2의 커넥션은 persistent, origin당 하나의 connection만 있으면 됨.

http3

  • UDP를 기반으로 하는 QUIC 프로토콜로 통신.

  • handshake, slow start가 필요없음.

  • HTTP수준 스트림이 QUIC 스트림에 단순 매핑되어, HoLB가 없음.

  • 클라가 첫 요청시 서버의 세션 키를 모르므로, 서버의 connection id를 사용해 initial key를 사용, 통신을 암호화.

  • 한번 연결해 놓으면, 서버는 설정을 캐싱했다가 다음 연결때 바로 연결을 성립시키기에 0RTT로 통신을 시작할 수도 있음.

  • multiplexing을 여전히 지원함.

Q. http2의 다중 커넥션은 무엇?

일식

  • http 1.x는 오로지 하나의 response만 전달될 수 있다는 모델을 따른다.

  • http2에서는, http message를 independent frame으로 쪼개서, 끝단에서 조합한다.

  • stream으로 여러개의 response, request를 묶고, 이를 frame으로 구별.

  • frame은 오고가는 데이터의 묶음.

    • HEADERS frame, DATA frame

  • server push - html을 동시에 받고, 렌더링해서 필요한 모든 리소스를 같이 받는다.

  • vs pipelining?

    • head of line blocking. HTTP 1.1의 pipelining은 여전히 큰 response가 뒤의 것들을 막는 현상을 초래한다.

  • 결국 하나의 connection만으로 데이터를 주고받을 수 있게 됨.

  • 어떻게 여러개의 리소스를 주고받을 수 있는가?

    • 바이너리 포맷의 데이터로 만들어, data frame을 여러개로 나누어 전달할 수 있기 때문.

  • http2에서는 헤더 압축도 한다.

    • header table로, 중복 선언된 헤더를 인덱스값만 전송.

      • 새롭게 추가, 변경된 헤더는 HPACK압축으로 전송됨.

  • http2는 SSH/TLS 기반에서만 작동.

References

요청 및 응답 다중화 (HTTP/2 소개)

Multiplexed Streams

  • 하나의 커넥션으로 동시에 여러 개의 메시지를 주고받을 수 있음

  • HTTP 메시지를 독립된 프레임으로 세분화하고, 이 프레임을 인터리빙한 다음, 다른 쪽에서 다시 조립

  • 응답 순서에 상관없이 스트림으로 주고받음

  • HOL(Head-of-Line, 패킷이 같은 큐에 있는 첫번째 패킷에 의해 지연) 차단 문제 해결

  • Stream Prioritization: 리소스 간의 우선 순위를 설정하는 것 (ex. CSS vs img)

Q. 병렬 커넥션에서 대역폭이 좁을 때 전송 속도가 느려지는 정확한 이유?

4장 p.102 인용

병렬 커넥션이 일반적으로 더 빠르기는 하지만, 항상 그렇지는 않다. 클라이언트의 네트워크 대역폭이 좁을 때(예를 들어, 브라우저 28.8Kbps 모뎀으로 인터넷에 연결되어 있는 경우)는 대부분 시간을 데이터를 전송하는 데만 쓸 것이다. 여러 개의 객체를 병렬로 내려받는 경우, 이 제한된 대역폭 내에서 각 객체를 전송받는 것은 느리기 때문에 성능상의 장점은 거의 없어진다.

병렬 커넥션의 전송속도가 대역폭에 직접적으로 연관이 되어 있지는 않다.

  • 커넥션을 병렬로 사용하여 최대 쓰루풋을 가져오는 것이 관건.

  • 대역폭이 좁으면 이미 쓰루풋이 한계치를 달리고 있으므로 굳이 사용할 필요가 없음.

  • 오히려 병렬 커넥션을 사용함으로써 발생하는 부가비용들이 속도를 저하시킴.

    • 각 커넥션의 handshake

    • slow start

    • 등등..

Q. UX 측면에서, 여러 리소스를 병렬로 받아오는 게 더 나은가? 어떻게 나은가?

동문서답 : lazy loading

이 부분에 대한 명쾌한 답은 찾아도 잘 안나온다. 개인 차가 있는 것 같기도 하고...

하지만 다른 방법의 해결방법이 존재함.

적은 용량의 대체 이미지를 보여주고 뒤에서 로딩하는 방식 : 이미지 및 동영상의 지연 로딩

Q. chunked transfer encoding이란 무엇인가?

커넥션이 계속 지속되고 있을 때, 전송의 끝을 알리는 방법은 크게 두 가지가 있다.

  • 첫 번째로 Content-Length 헤더로 데이터의 사이즈를 주어서, 해당 바이트 크기까지 읽었다면 전송이 끝난 것으로 판단할 수 있다.

  • 두 번째로 chunked transfer encoding 을 사용할 수 있다. Transfer-Encoding: chunked 헤더를 사용한다. 데이터를 청크 단위로 쪼개고, 각각의 청크마다 해당 청크의 길이를 표시해 준다.

예시: 길이가 각각 4, 5, 13(E)인 세 개의 청크

Chunked Transfer Encoding (wikipedia)

4\r\n
Wiki\r\n
5\r\n
pedia\r\n
E\r\n
 in\r\n
\r\n
chunks.\r\n
0\r\n
\r\n

서버에서 동적 리소스를 생성해줄 때, 처리가 모두 완료되어야만 리소스를 보내줄 수 있다면, 클라이언트 입장에서는 서버가 처리하는 동안 흰 화면만 보이는 답답함을 느낄 수 있다. 리소스가 완성되지 않았어도 처리된 부분까지만 청크를 보내 주면 이러한 문제를 해결할 수 있다.

Q. 다음 proxy가 connection을 구현하고 있는지 어떻게 아나?

그것은 네이버에도 나와있지 않다.

Q. 지속 커넥션 2개 제한은 무슨 기준?

Clients that use persistent connections SHOULD limit the number of simultaneous connections that they maintain to a given server. A single-user client SHOULD NOT maintain more than 2 connections with any server or proxy. A proxy SHOULD use up to 2*N connections to another server or proxy, where N is the number of simultaneously active users. These guidelines are intended to improve HTTP response times and avoid congestion.

명세에는 proxy 들은 N 개의 커넥션을 지속하기위해 2*N 개의 커넥션을 지속시켜야 하므로 2개 이상 사용하지 말라고 되어있지만 (old browser)

최근에 사용되는 대다수의 모던 브라우저는 기본적으로 6개까지 허용하고 있다.

이는 혼잡 상황을 피하기 위해 지속 커넥션을 그저 최소화 하자는 데에만 이유가 있는 듯 하다.

Last updated