프로그래밍/HTTP

[HTTP 완벽 가이드] HTTP 커넥션 관리

kwon92 2021. 8. 4. 19:08

TCP 커넥션

HTTP 통신은 전송 프로토콜인 TCP/IP를 통해 이루어진다.

TCP/IP 위에서 전송되기 때문에 메시지의 무결성, 순서 등을 보장 할 수 가 있다.

신뢰할 수 있는 데이터 전송 통로 TCP

HTTP 커넥션은 TCP 커넥션에서 몇가지 사용 규칙이 추가된 커넥션이다.

HTTP 커넥션은 TCP 커넥션을 이해 하는 것을 베이스로 한다.

TCP 커넥션은 바이트(데이터)를 순서에 맞게 정확히 전달하게 된다.

 

TCP 스트림은 세그먼트로 나뉘어 IP 패킷을 통해 전송된다.

 

TCP는 세그먼트 단위로 데이터 스트림을 잘게 나눠주고 세그먼트를 IP 패킷으로 감싸서 전달한다.

HTTP 메시지가 TCP 데이터 스트림 청크로 들어가 있고,

이 청크를 TCP 세그먼트가 감싸고, 이 세그먼트를 IP 패킷으로 감싸서 데이터가 전달 되게 된다.

 

TCP 커넥션 유지하기

 

컴퓨터는 여러 TCP 커넥션을 가지고 있다.

커넥션의 유니크 키는 4가지 인데,

 

1. 발신지 IP 주소

2. 발신지 포트

3. 수신지 IP 주소

4. 수긴지 포트

 

저 4값이 모두 동일한 커넥션은 없다.

 

브라우저에서 한 탭에서 구글을 띄어놓고 , 다른 탭에서 또 구글로 접속을 하려고 하면 새로운 포트 번호로 요청을 한다.

구글에서는 성능 향상을 위해 다중 커넥션을 만들어서 여러 데이터를 동시에 받게 되는데 이런 경우엔 여러 포트로 커넥션을 만들게 된다.

 

 

TCP 소켓 프로그래밍

운영체제에서 TCP 커넥션 기능을 제공한다.

 

서버에서는 소켓을 생성해서 80 포트에 소켓을 바인드해놓고

소켓의 연결을 허용해 둔다.

이 상태로 커넥션을 기다리고 있는다.

 

클라이언트에서는 IP 주소와 포트를 알아내고

새로운 소켓을 생성한 후 소켓으로 서버와 연결을 한다.

 

그 후 3 핸드웨이 쉐이크 로 연결을 맺고 데이터를 주고 받고 커넥션을 끊게 된다.

 

TCP는 기본적인 핸드쉐이크, TCP 데이터 스트림과 IP 패킷 간 분할 및 재조립에 대한 세부사항을 외부로부터 숨긴다.

 

 

TCP 성능에 대한 고려

HTTP 통신은 TCP 성능에 의존한다. TCP 의 특성을 이해하면 HTTP 통신의 최적화를 더 잘 할 수 있다.

 

- HTTP 트랜잭션 지연

통신에서 TCP 커넥션을 설정하고 요청을 전송하고 처리 하여 응답을 주고 클라이언트가 다시 응답을 받는 과정 중에

처리는 비중이 매우 낮다. 대부분은 네트워크 지연이다.

 

Process 의 비중이 낮다.

서버에 TCP 커넥션을 맺고 , 커넥션이 맺어지면 HTTP 요청을 생성이 된 TCP 파이프를 통해 전송

웹서버가 응답을 보내는 시간이 걸린다.

 

 

- 성능 관련 중요 요소들

 

1. TCP 커넥션 핸드쉐이크 설정

2. 인터넷의 혼잡을 제어하는 TCP slow-start

3. 데이터를 한데 모아 전송하는 nagle 알고리즘

등등..

 

TCP 커넥션 핸드쉐이크

개발자는 핸드쉐이크를 보지 못한다. 

사실 커넥션을 생성하는 건 굉장히 큰 비용이라고 할 수 있다.

총 3번의 네크워크 비용이 발생하기 떄문

매번 커넥션을 만들지 않고 재활용한다.

 

3 핸드웨이 쉐이크

확인 응답 지연

인터넷 자체가 패킷의 전송을 완벽히 보장하지 않는다.

라우터는 과부하에 걸렸을때 패킷을 파기할 수 있기 때문이다.

 

각 TCP 세그먼트는 순번과 데이터 무결성 체크섬을 가지는데, 수신자는 세그먼트를 받았을때 정확한 데이터가 왔는지 ACK 응답 패킷을 요청자에게 보내는데, 이 값은 하나의 비트기 때문에 비트 하나를 위해 패킷을 만들기가 자원이 아깝다. 그래서 방향이 같은 다른 패킷에 동승(piggyback)해서 간다. 

확인 응답지연은 확인 응답(ACK) 를 효율적으로 보내기 위해 동승할 패킷을 기다리는 행위다.

 

TCP slow-start

패킷의 전송속도는 네트워크 대역폭에 의해 결정되는데 대역폭을 미리 알 수 가 없다.

처음부터 많은 데이터를 보내게 되면 대역폭이 감당하지 못해 문제가 발생하기 때문에 안전을 위해 

낮은 속도로 먼저 보내다가 조금씩 늘리게 된다. 이걸 slow-start라 한다.

 

Nagle 알고리즘

데이터가 모일때까지 기다렸다가 보내는 알고리즘

 

커넥션 전략

 

웹에서 주고 받는 데이터가 크기 때문에 HTTP 요청을 주고 받기 위해 

4가지 전략이 있다.

 

병렬 커넥션 - 여러 개의 TCP 커넥션을 통한 동시 HTTP 요청

지속 커넥션 - 커넥션을 끊지 않고 재활용해서 커넥션을 맺고 끊는 지연을 없앤다

파이프라인 커넥션 - 공유 TCP 커넥션을 통한 병렬 HTTP 요청

다중 커넥션 - 요청과 응답들에 대한 중재

 

 

병렬 커넥션

동시에 여러 커넥션을 사용하여 병렬 처리

 

 

병렬 커넥션은 페이지를 빠르게 내려받지만 메모리를 많이 소모한다.

다만 네트워크 대역폭이 낮다면 더 빠르지 않다.

 

지속 커넥션

 

커넥션을 폐기하지 않고 재활용하는 것으로 HTTP/1.0+ 부터 사용한다.

 

지속 커넥션 vs 병렬 커넥션

 

병렬 커넥션은 커넥션 생성 비용이 너무 많이 들고 

slow-start에 커넥션 수 도 제한되어있다는 단점이 있다.

 

지속 커넥션은 위 제한들을 커버 할 수 있기 때문에

병렬커넥션과 지속 커넥션을 함께 사용한다.

 

HTTP/1.0+ 에서는 Keep-Alive 옵션을 사용했지만

HTTP/1.1 부터는 deprecated 되고 더 개선이 된 지속 커넥션이 사용되었다.

 

 

Keep-Alive 동작

클라이언트에서 Connection: Keep-Alive 를 보내고 서버도 똑같이 보내면 커넥션을 재활용하게 된다.

 

 

 

 

Keep-Alive 와 멍청한 프록시

클라이언트가 Keep-Alive 를 헤더에 포함해서 전달했지만,

프록시는 이 헤더를 이해하지 못한 채로 서버에 요청을 보낸다.

 

서버에서는 지속 커넥션을 사용하기 위해 커넥션을 끊지 않는데

프록시에서는 커넥션이 끊어질때까지 기다리게 된다.

이런 잘못된 통신을 피하려면 프록시는 커넥션 헤더들을 전달하면 안된다.

 

 

 

Proxy-Connection

멍청한 프록시 때문에 나온 옵션이라고 할 수 있다.

멍청한 프록시에 Proxy-Connection 을 보내면 헤더를 알지못하고 서버에 보내는데

서버도 저 옵션을 모르니 지속 커넥션을 연결하지 않는다.

 

똑똑한 프록시는 저 옵션을 Connection으로 변경시켜서 지속 커넥션이 가능하게 해준다.

 

 

커넥션 끊기

커넥션은 언제 끊어야 하는가에 대한 명확한 기준은 없다.

 

보통 에러가 나오면 커넥션을 끊지만 언제든 끊을수 있음

 

우아하게 커넥션 끊기

 - 전체 끊기 와 절반 끊기 등등등..