본문으로 바로가기

I. HTTP: 웹의 기초 | 4. 커넥션 관리

category 🌐 Network/🔗 HTTP 2020. 4. 1. 02:39

 

I. HTTP: 웹의 기초

04 커넥션 관리

 

  

  앞서 서버와 브라우저가 소통하기 위해서는 TCP/IP 커넥션을 맺어야 한다고 했는데 정확히 이것이 어떻게 작동하는 지에 대해서는 설명하지 않았다. 이번에 TCP/IP 커넥션이 무엇인지 알아보자.

 

  •   TCP 커넥션

  전 세계 모든 HTTP 통신은 패킷 교환 네트워크 프로토콜들의 계층화된 집합 TCP/IP를 통해 이뤄진다. TCP/IP 커넥션이 일단 맺어지면 메세지들은 유실되거나 순서가 바뀌지 않고 안전하게 전달된다.

 

  구글 주소창에 특정 URL을 입력하면 어떻게 TCP 커넥션을 맺어 데이터를 전달하는지의 순서는 다음과 같다.

 

  (1) http://www.shopping.com:80/power-tools.html 을 입력한다

  (2) 브라우저는 호스트 명에 대한 IP 주소를 찾는다

  (3) 브라우저는 포트번호를 찾는다

  (4) 브라우저가 얻은 IP를 가진 서버의 포트번호로 TCP 커넥션을 생성한다

  (5) 브라우저가 서버로 HTTP GET req 메세지를 보낸다. (단순히 주소창에 쳤으므로 GET)

  (6) 브라우저가 서버로부터 res 메세지를 받고 읽는다

  (7) 브라우저가 커넥션을 끊는다.

 

  여기서 TCP 커넥션에서 당연한 사실이지만 짚고 넘어가야할 것이, 커넥션은 유일해야 한다는 것이다. TCP 커넥션은 <발신지 IP, 발신지 포트, 목적지 IP, 목적지 포트>라는 4 요소로 유일한 커넥션을 생성해야 한다. IP 주소가 겹칠 리는 없으므로 동일한 커넥션이 생성될 수는 없다.

 

  • IP 패킷(IP 데이터그램)

  한편, TCP는 데이터 스트림을 세그먼트라는 단위로 나뉘어서 IP 패킷(IP 데이터그램)이라 부르는 조각에 담아 데이터를 전달한다. 이 과정은 TCP/IP 소프트웨어에 의해 처리되므로 그 과정은 HTTP 프로그래머에게 보이지 않는다. 세그먼트와 IP 패킷이란 용어가 생소하므로 그림으로 TCP 데이터 스트림을 표현해보면 다음과 같다.

 

  IP 패킷 내 IP 헤더, TCP 헤더, TCP 데이터가 들어있으며 각각 적혀 있는 정보에 기반하여 세그먼트가 전달된다.

 

 

 

  • TCP 성능

HTTP는 TCP 위의 계층이기 때문에 HTTP의 성능은 TCP 성능의 영향을 받는다. 흔히 말해 "인터넷이 느리다"고 불평하는 원인이 여기에 있을 수도 있다는 말이다.

 

 

 - TCP 커넥션 핸드쉐이크 지연

 

  새로 TCP 커넥션을 열면 TCP 소프트웨어는 연속으로 IP 패킷을 교환한다. 이를 은유적으로 서버와 클라이언트가 만나서 "악수"(handshake)를 한다고 표현한 것이다. 정확한 과정은 다음과 같이 일어난다.

 

  (1) TCP 커넥션을 생성하기 위해 클라이언트가 IP 패킷을 서버에게 보낸다. 이 IP 패킷엔은 'SYN'이라는 특별한 플래그가 있다. 커넥션 생성 요청이라는 의미이다.

  (2) 서버가 SYN 플래그가 든 IP 패킷을 받으면 몇가지 커넥션 매개변수를 산출해내고 커넥션 요청을 허락하는 플래그인 'SYN', 'ACK' 플래그를 포함한 IP 패킷을 클라이언트에게 보낸다.

  (3) 클라이언트는 커넥션을 성공적으로 맺어졌음을 알리기 위해 확인응답 패킷을 보낸다. 현재는 확인응답 패킷과 함께 데이터를 보낼 수 있다.

 

  (1)과 (2)에서 일어나는 지연을 '커넥션 핸드쉐이크 지연'이라고 부른다.

 

 

 - 확인응답 지연

 

  인터넷 자체가 패킷 전송을 보장하지는 않는다. 심지어 인터넷 라우터는 과부하가 걸렸을 때 패킷을 마음대로 파기할 수도 있다. 때문에 TCP는 성공적인 데이터 전송을 보장하기 위해 자체적인 확인 체계가 있다.

  그 중 하나는 패킷의 수신자는 패킷을 받으면 작은 확인응답 패킷을 송신자에게 반환하는 것이다. 이 때, 확인응답 패킷은 크기가 작기 때문에 같은 방향으로 가는 일반 패킷에 덧붙여서 보낸다. 이를 '편승'(piggyback)이라고 한다.

  TCP는 네트워크를 효율적으로 사용하기 위해 이러한 편승의 빈도를 늘리려고 '확인응답 지연' 알고리즘을 사용한다. 간략히 설명하자면, 특정 시간 동안(0.2초 정도) 버퍼에 저장해두고 편승시킬 송출 패킷을 찾는 것이다. 찾지 못하면 그냥 확인 응답 패킷은 별도로 전송된다.

  그런데 req, res로만 이루어진 HTTP 동작 방식에는 확인 응답이 편승할 기회가 비교적 적다. 편승할 기회가 없으므로 확인응답 패킷이 확인응답 지연 알고리즘에 의해 버퍼에 기다리게 되고 이에 따라 지연이 발생한다.

  OS에 따라 다르지만 확인응답 지연을 수정하거나 비활성화할 수 있다. 그러나 TCP 내부를 수정하는 것은 해당 효과를 잘 이해하고 부작용에 대처할 수 있을 때만 하는 것이 좋다.

 

 

 - TCP 느린 시작 slow start

 

  TCP 커넥션이 만들어진 후 처음에는 최대 속도가 제한되고 데이터가 성공적으로 전송됨에 따라 점차 속도 제한을 높인다. 이러한 조율 과정을 'TCP의 느린 시작'이라고 부르며 인터넷의 갑작스러운 부하를 방지하는 효과가 있다.

 

 

 - Nagle 네이글 알고리즘과 TCP _NODELAY

 

  아주 작은 크기의 TCP 데이터를 여러 패킷에 나눠서 전송하는 것은 네트워크 성능을 떨어뜨리는 일이다. 네이글 알고리즘은 네트워크 효율을 위해 패킷을 전송하기 전 TCP 데이터를 하나의 덩어리로 합친다. 전송하기 충분한 양의 데이터가 쌓이기 전까지 데이터는 버퍼 Buffer에 저장된다.

  때문에 작은 크기의 HTTP 메세지가 네이글 알고리즘이 지정한 양의 데이터를 채우지 못할 경우에는 지연이 발생한다. 네이글 알고리즘을 비활성화하기 위해서 HTTP 스택에 TCP _NODELAY 파라미터 값을 설정하기도 한다. 

 

 - TIME_WAIT의 누적과 포트 고갈

 

  TCP 커넥션을 끊게되면 재접속 시에 또 TCP 커넥션을 생성하는 비효율을 막기 위해 커넥션의 IP 주소와 포트번호를 메모리의 제어영역(control block)에 저장된다. 보통 2MSL, 즉, 2분 정도 저장된다. 현재는 훨씬 짧은 시간 동안만 저장된다. 빠른 라우터 덕에 중복 패킷이 생기는 경우가 거의 없어졌기 때문이다.

  이러한 종료 지연이 문제가 될 일은 별로 없지만 성능 시험 상황에서는 문제가 될 수 있다.

 

 

  • HTTP 커넥션

HTTP 트랙잭션을 지연시키는 원인은 여러가지가 있지만 대표적으로,

(1) URL에서 IP, 포트번호를 가져오는 과정에서 DNS를 거치면서 시간이 걸리며,

(2) TCP 커넥션 req를 날리고 서버가 허락해주기 까지 res를 기다려야 한다.

(3)커넥션이 만들어진 후 일반적인 req를 받고 서버가 이를 처리한 후 res를 보내줄 때까지의 지연도 있다

 

  이러한 지연을 다른 곳에서 최대한 줄이기 위해 사용하는 HTTP 커넥션을 생성하고 최적화하는 HTTP 기술에 대해 알아보자. 이는 TCP 커넥션의 영향을 받긴 하지만 별개의 개념이다. 트랜잭션을 어떻게 처리할지에 대한 방법론이라고 보는 것이 쉽다.

  예컨대, 순차적으로 트랜잭션 처리를 한다면 각각의 이미지를 하나씩 차례대로 불러오게 될 것이다. 동기적(synchronous)으로 일을 처리하면 요즘 세상에서는 답답할 것이다. 또한 사용자는 이미지를 하나씩 내려받는 방식을 느리다고 느낀다. 더 느리더라도 이미지들이 한 번에 내려받는 것이 더욱 빠르다고 느낀다. 

 

  빠른 HTTP 통신을 위해서는 다른 방식으로(다른 HTTP 커넥션으로) 트랜잭션을 처리해야 한다.

 

 

 - 병렬(parallel) 커넥션

 

  여러 개의 커넥션을 맺어서 병렬적으로 트랜잭션을 처리하는 것. 클라이언트의 네트워크 대역폭이 좁을 경우 순차적인 커넥션봐 별로 차이가 없어질 수 있으며 서버의 메모리를 많이 소모한다는 특징이 있다. 때문에 서버는 특정 클라이언트가 과도하게 커넥션을 맺을 경우 임의로 커넥션을 끊어낼 수 있다.

  현재 브라우저는 병렬 커넥션을 사용하고 있는데 대부분 6~8개의 병렬 커넥션을 지원한다. 

 

 

 - 지속(persistent) 커넥션

 

  TCP 커넥션을 끊기 전까지 트랜잭션 간에도 커넥션을 유지하는 것이다. 새로 HTTP 커넥션을 맺기 위한 준비 작업을 아껴준다. 이는 튜닝된 TCP를 계속 이용하기 때문에 TCP의 느린 시작을 거치지 않아도 된다는 장점이 있다. HTTP/1.1에는 기본으로 지속 커넥션이 활성화 되어있다. 모든 커넥션을 지속 커넥션으로 취급하는 것이다.

 

 - 파이프라인(pipelined) 커넥션

  공유 TCP 커넥션을 통한 병렬 HTTP 요청

 

 - 다중(multiplexed) 커넥션

  요청과 응답들에 대한 중재

 

 

  

  • 커넥션 끊기

  언제 커넥션을 끊어야 하는 지에 대해서는 기준이 없다. 사실 클라이언트, 서버, 프록시는 언제든지 내키는대로 TCP 커넥션을 끊을 수 있다. 보통 HTTP 메세지를 다 보낸 다음 끊는 것이 정석이지만 에러가 있는 상황에선 엉뚱한 곳에서 끊길 수도 있다.

  특히, POST 메소드를 사용하는 req들은 커넥션이 끊기면 여러번 주문된 것으로 중복처리될 가능성도 있다. 여기서 "멱등(idempotent)"이란 개념이 등장한다. GET, HEAD, PUT, DELETE, TRACE, OPTIONS 메서드들은 몇 번 실행됐는 지에 상관 없이 같은 결과를 반하므로 멱등하다. 반면 POST는 멱등하지 않기 때문에 커넥션이 끊어질 경우 결과는 알 수 없다. 흔히 상품 담기, 로그인에서 오류가 발생할 경우 에러 메세지를 본 경험이 있을 것이다. 이는 POST가 멱등하지 않은 메서드이기 때문이다.

  때문에 비멱등인 메서드를 다시 로드하려고 하면 요청을 다시 보내길 원하는지 묻는 대화 상자를 보여주는 것이 일반적이다.

 


darren, dev blog
블로그 이미지 DarrenKwonDev 님의 블로그
VISITOR 오늘 / 전체