독서 스터디도 4주차가 지나가네요.
이번 4주차도 어김없이 읽은 내용을 정리하고 문제를 만들어 가야합니다!
전세계 모든 HTTP 통신은, 지구상의 컴퓨터와 네트워크 장비에서 널리 쓰이고 있는 패킷 교환 네트워크 프로토콜들의 계층화된 집합인 TCP/IP를 통해 이루어진다. 세계 어디서든 클라이언트 애플리케이션은 서버 애플리케이션으로 TCP/IP 커넥션을 맺을 수 있다.
-HTTP 완벽 가이드 p.85-
TCP 커넥션은 인터넷을 안정적으로 연결해준다. HTTP에게 신뢰할 만한 통신 방식을 제공한다.
HTTP가 메시지를 전송하고자 할 경우, 현재 연결되어 있는 TCP 커넥션을 통해서 메시지 데이터의 내용을 순서대로 보낸다. TCP는 세그먼트라는 단위로 데이터 스트림을 잘게 나누고, 세그먼트를 IP 패킷이라고 불리는 봉투에 담아서 인터넷을 통해 데이터를 전달한다.
TCP는 포트 번호를 통해서 여러개의 커넥션을 유지한다. 포트 번호는 회사 직원의 내선전화와 같다. 대표 전화번호는 안내 데스크로 연결되고 내선전화는 직원으로 연결되듯이 IP주소는 해당 컴퓨터에 연결되고 포트번호는 애플리케이션으로 연결된다. TCP 커넥션은 네가지 값으로 식별한다.
발신지 IP 주소, 발신지 포트, 수신지 IP 주소, 수신지 포트
이 네 가지 값으로 유일한 커넥션을 생성한다. 서로 다른 두 개의 TCP 커넥션은 네가지 주소 구성요소의 값이 모두 같을 수 없다.
SYN
라는 특별한 플래그를 가지는데, 이게 커넥션 생성 요청이다.SYN
과 ACK
플래그를 포함한 TCP 패킷을 클라이언트에게 보낸다.HTTP 프로그래머는 패킷들을 보지 못한다. 오직 TCP 커넥션이 생성될 때 발생하는 지연이 전부다.
크기가 작은 HTTP 트랜잭션은 50% 이상의 시간을 TCP를 구성하는 데 쓴다. 이러한 지연을 제거하기 위해 HTTP 이미 존재하는 커넥션을 어떻게 재활용하는지 후에 나온다.
인터넷 자체가 패킷 전송을 완벽히 보장하지 않기에, TCP는 자체적인 확인 체계를 가진다. 각 세그먼트의 수신자는 세그먼트를 온전히 받으면 확인응답 패킷
을 송신자에게 반환한다. 송신자가 이를 받지 못하면 데이터가 유실되었거나 오류가 생겼다고 판단, 다시 보낸다.
확인응답은 그 크기가 작기에, 데이터 패킷에 편승
시킨다. 안타깝게도 요청과 응답 두 가지 형식으로만 이루어지는 HTTP 동작 방식은, 편승할 기회를 감소시킨다.
막상 편승하려고 해도, 패킷이 많지 않기에 확인응답 지연 알고리즘
으로 인해 지연이 자주 발생한다.
확인응답 지연은 송출할 확인응답을 특정 시간 동안 버퍼에 저장해 두고, 확인응답을 편승시키기 위한 송출 데이터 패킷을 찾는다. 만약 일정 시간 안에 송출 데이터 패킷을 찾지 못하면 확인응답은 별도 패킷을 만들어 전송된다.
TCP 커넥션은 시간이 지나면서 자체적으로 튜닝
되어서, 처음에는 커넥션의 최대 속도를 제한하다고 데이터가 성공적으로 전송됨에 따라 속도 제한을 높여나간다. 이는 인터넷의 급작스러운 부하의 혼잡을 방지한다.
네이글 알고리즘은 세그먼트가 최대 크기(LAN상에서 1500바이트, 인터넷상에서 수백바이트)가 되지 않으면 전송하지 않는다. 다만 다른 모든 패킷이 확인응답을 받았을 경우에는 최대 크기보다 작은 패킷의 전송을 허락한다. 이 알고리즘은 HTTP 성능 관련해서 여러 문제가 있다.
따라서 TCP_NODELAY 값을 설정해 알고리즘을 비활성화하기도 한다.
일반적으로 2MSL의 커넥션 종료 지연이 문제가 되지는 않지만, 성능시험을 하는 상황에서는 문제가 될 수 있다. ...(중략)... 클라이언트가 서버에 접속할 때마다, 유일한 커넥션을 생성하기 위해서 새로운 발신지 포트를 쓴다. 하지만 사용할 수 있는 발신지 포트의 수는 제한되어 있고(60,000개로 가정) 2MLS(120초로 가정)동안 커넥션이 재사용될 수 없으므로, 초당 500개로 커넥션이 제한된다. 서버가 초당 500개 이상의 트랜잭션을 처리할 만큼 빠르지 않다면 TIME_WAIT 포트 고갈은 일어나지 않는다. 포트 고갈 문제가 아니더라고, 커넥션을 너무 많이 맺거나, 대기 상태로 있는 제어 블록이 너무 많아지는 상황은 주의해야 한다.
커넥션 토큰이 HTTP 헤더 필드 명을 가지고 있으면, 해당 필드들은 현재 커넥션만을 위한 정보이므로 다음 커넥션에 전달하면 안 되고, 다른 곳으로 전달하는 시점에 삭제되어야 한다.
3개의 이미지가 있는 웹페이지가 있다. 하나는 해당 HTML을, 나머지 세 개는 첨부된 이미지를 받기 위한 것이다. 각 트랜잭션이 새로운 커넥션을 필요로 한다면, 커넥션을 맺는데 발생하는 지연과 함께 느린 시작 지연이 발생한다. 순차적인 처리로 인한 지연으로 물리적인 지연뿐 아니라, 심리적인 지연도 동반된다.
사용자는 여러개의 이미지가 동시에 로드되는 것을 더 좋아한다.
또한 브라우저의 경우 객체를 화면에 배치하려면 객체의 크기를 알아야 하기 때문에, 모든 객체를 내려받기 전까지는 텅 빈 화면을 보여준다.
여러개의 커넥션을 맺음으로써 여러개의 HTTP 트랜잭션을 병렬로 처리할 수 있다.
각 커넥션의 지연시간을 겹치게 하면 총 지연 시간을 줄일 수 있고, 클라이언트의 인터넷 대역폭을 한 개의 커넥션이 다 써버리는 것이 아니라면 나머지 객체를 내려받는 데에 남은 대역폭을 사용할 수 있다.
클라이언트의 네트워크 대역폭이 좁을 때는 대부분 시간을 데이터를 전송하는 데만 쓴다. 다수의 커넥션은 메모리를 많이 소모하며, 성능 문제를 발생시킨다. 실제로 병렬 커넥션을 사용하긴 하지만, 최신 브라우저 기준으로 대부분 6~8개의 적은 병렬 커넥션을 지원한다.
실제로는 더 빠르게 로드하지 않는데, 화면에 여러개의 객체가 동시에 보이면서 내려받는 상황을 유저가 볼 수 있기 때문에 더 빠르다고 여긴다.
HTTP/1.1을 지원하는 기기는 처리가 완료된 후에도 TCP 커넥션을 유지하여 앞으로 있을 HTTP 요청에 재사용할 수 있다. 처리가 완료된 후에도 계속 연결된 상태로 있는 TCP 커넥션을 지속 커넥션
이라고 부른다.
병렬 커넥션의 단점
지속 커넥션의 장점
잘못 관리할 경우, 계속 연결된 상태로 있는 수많은 커넥션이 쌓이게 될 것이다. 이는 로컬의 리소스 그리고 원격의 클라이언트와 서버의 리소스에 불필요한 소모를 발생시킨다. 오늘날 많은 웹앱플리케이션은 적은 수의 병렬 커넥션만을 맺고 그것을 유지한다.
Keep-alive는 HTTP/1.1 명세에서 빠졌다. 하지만 아직도 keep-alive 핸드셰이크가 널리 사용되고 있기에, HTTP 애플리케이션을 이를 처리할 수 있게 개발해야 한다. 동작하는 방식을 간단히 살펴보면
Keep-Alive 헤더는 커넥션을 유지하기를 바라는 요청일 뿐이다. 이를 무조건 따를 필요는 없다. 언제든지 커넥션을 끊을 수 있고, Keep-Alive 커넥션에서 처리되는 트랜잭션의 수를 제한할 수도 있다.
넷스케이프는 멍청한 프락시 문제를 해결하기 위해 브라우저에서 전달하는 Connection 헤더 대신에 비표준인 Proxy-Connection 확장 헤더를 프락시에게 전달한다. 영리한 프락시라면, 이 의미 없는 Proxy-Connection 헤더를 Connection 헤더로 바꾼다.
HTTP/1.1에서 keep-alive를 지원하지 않는 대신, 지속 커넥션을 기본적으로 지원한다. 트랜잭션이 끝난 다음 커넥션을 끊으려면 Connection:close
헤더를 명시해야 한다. 그치만 Connection:close를 보내지 않는 것이 서버가 커넥션을 영원히 유지하겠다는 뜻은 아니다.
HTTP 명세에서는 클라이언트나 서버가 예기치 않게 커넥션을 끊어야 한다면, 우아하게 커넥션을 끊어야 한다
라고 하지만, 정작 그 방법은 설명하고 있지 않다.
일반적으로 자신의 출력을 먼저 끊고 다른 쪽에 있는 기기의 출력 채널이 끊기는 것을 기다리는 것이다.
IP는 ( )계층, TCP는 ( )계층, HTTP는 ( )계층이다. HTTP에 보안 기능을 더한 HTTPS는 ( ) 혹은 ( )이라 불리기도 하며 HTTP와 TCP 사이에 있는 ( )계층이다.
네트워크, 전송, 애플리케이션, TLS, SSL, 암호화(보안)
a) TCP 커넥션은 네 가지 값으로 식별한다. 서로 다른 두개의 TCP 커넥션은 네가지 주소 구성요소의 값이 모두 같을 수 있다.
b) HTTP 프로그래머는 새로운 TCP 커넥션이 생성될 때 발생하는 지연 및 패킷까지 보고 제어한다.
c) HTTP 커넥션의 성능을 향상시킬 수 있는 여러 최신 기술들로는 병렬, 지속, 파이프라인, 다중커넥션이 있다.
d) 병렬 커넥션은 언제나 더 빠른 방식임을 보장한다.
e) 클라이언트나 서버가 keep-alive 요청을 받았다면 반드시 이를 따라야 함을 보장해야 한다.
f) 애플리케이션은 트랜잭션이 끝난 다음 커넥션을 끊으려면 Connection: close 헤더를 명시해야 한다. 해당 헤더가 없으면 서버가 커넥션을 영원히 유지하겠다는 뜻이다.
g) 클라이언트나 서버가 예기치 않게 커넥션을 끊어야 한다면 우아하게 커넥션을 끊어야 한다
라고 하지만, 정작 그 방법은 설명하고 있지 않다.
c, g
내용이 꽤 많았다. TCP에 대해서 꽤 깊숙하게 들여다 본 느낌... 왜 지연이 일어나는지에 대해 책을 읽다보면 내용이 꽤 재밌다. 이걸 기억하는건 별개의 문제겠지만! 특히 우아한 커넥션 끊기는 정말이지... 기억에 남는다.