HTTP 커넥션을 생성하고 최적화하는 HTTP 기술에 대해서 알아보자. 우선 잘못 이해하는 Connection 헤더에 대해 먼저 알아보자.
HTTP는 클라이언트와 서버 사이에 프락시 서버, 캐시 서버 등과 같은 중개 서버가 놓이는 것을 허락한다. HTTP 메시지는 클라이언트에서 서버(혹은 리버스 서버)까지 중개 서버들을 하나하나 거치면서 전달된다.
HTTP Connection 헤더 필드는 커넥션 토큰을 쉼표로 구분하여 가지고 있으며, 그 값들은 다른 커넥션에 전달되지 않는다. 예를 들어, 다음 메시지를 보낸 다음 끊어져야 할 커넥션은 Connection: close 라고 명시할 수 있다.
Connection 헤더에는 다음 세 가지 종류의 토큰이 전달될 수 있기 때문에 혼란스러울 수 있다.
- HTTP 헤더 필드 명은, 이 커넥션에만 해당되는 헤더들을 나열한다.
- 임시적인 토큰 값은, 커넥션에 대한 비표준 옵션을 의미한다.
- close 값은, 커넥션이 작업이 완료되면 종료되어야 함을 의미한다.
커넥션 토큰이 HTTP 헤더 필드 명을 가지고 있으면, 해당 필드들은 현재 커넥션 만을 위한 정보이므로 다음 커넥션에 전달하면 안 된다.
Connection 헤더에 있는 모든 헤더 필드는 메시지를 다른 곳으로 전달하는 시점에 삭제되어야 한다.
HTTP 애플리케이션이 Connection 헤더와 함께 메시지를 전달받으면, 수신자는 송신자에게서 온 요청에 기술되어 있는 모든 옵션을 적용한다. 그리고 다음 홉에 메시지를 전달하기 전에 Connection 헤더와 Connection 헤더에 기술되어 있던 모든 헤더를 삭제한다.
순차적인 트랜잭션 처리에 의한 지연
커넥션 관리가 제대로 안되면 TCP 성능이 매우 안 좋아질 수 있다. 예를 들어 3개의 이미지가 있는 웹페이지가 있다고 해보자. 브라우저가 이 페이지를 보여주려면 네 개의 HTTP 트랜잭션을 만들어야 한다. 하나는 해당 HTML을 받기 위해, 나머지 세 개는 첨부된 이미지를 받기 위한 것이다. 각 트랜잭션이 새로운 커넥션을 필요로 한다면, 커넥션을 맺는데 발생하는 지연과 함께 느린 시작 지연이 발생할 것이다.
이를 해결하기 위해 다음과 같은 기술이 있다.
- 병렬(parallel) 커넥션 : 여러 개의 TCP 커넥션을 통한 동시 HTTP 요청
- 지속(persistent) 커넥션 : 커넥션을 맺고 끊는 데서 발생하는 지연을 제거하기 위한 TCP 커넥션의 재활용
- 파이프라인(pipelined) 커넥션 : 공유 TCP 커넥션을 통한 병렬 HTTP 요청
- 다중(multiplexed) 커넥션 : 요청과 응답들에 대한 중재
1. 병렬 커넥션
HTTP 클라이언트가 여러 개의 커넥션을 맺음으로써 여러 개의 HTTP 트랜잭션을 병렬로 처리할 수 있게 된다. 만약 4개의 이미지를 전달받는다면 할당받은 각 TCP 커넥션상의 트랜잭션을 토해 병렬로 내려받는다.
각 커넥션의 지연 시간을 겹쳐 총 지연시간을 줄이고, HTML 먼저 내려받고 남은 세 개의 트랜잭션이 각각 별도의 커넥션에서 동시에 처리된다. 이미지들을 병렬로 내려받아 커넥션 지연이 겹쳐짐으로써 총 지연시간이 줄어든다.
하지만 병렬 커넥션이 항상 더 빠르지는 않다.
만약 클라이언트의 네트워크 대역폭이 좁다면 대부분 시간을 데이터를 전송하는 데만 쓸 것이다. 여러 개의 객체를 병렬로 내려받는 경우, 이 제한된 대역폭 내에서 각 객체를 전송받는 것은 느리기 때문에 성능상의 장점은 거의 없어진다.
또한 다수의 커넥션은 메모리를 많이 소모하고 자체적인 성능 문제를 발생시킨다. 백 명의 가상 사용자가 각각 100개의 커넥션을 맺고 있다면, 서버는 총 10,000개의 커넥션을 맺게 되는 것이다. 이는 서버의 성능을 크게 떨어뜨린다.
브라우저는 이러한 이유로 실제 병렬 커넥션을 사용하긴 하지만 적은 수(대부분 4개)의 병렬 커넥션만을 허용한다.
병렬 커넥션의 단점
- 각 트랜잭션마다 새로운 커넥션을 맺고 끊기 때문에 시간과 대역폭이 소요된다.
- 각각의 새로운 커넥션은 TCP 느린 시작 때문에 성능이 떨어진다.
- 실제로 연결할 수 있는 병렬 커넥션의 수에는 제한이 있다.
2. 지속 커넥션
HTTP/1.1을 지원하는 기기는 처리가 완료된 후에도 TCP 커넥션을 유지하여 앞으로 있을 HTTP 요청에 재사용 할 수 있다. 처리가 완료된 후에도 계속 연결된 상태로 있는 TCP 커넥션을 지속 커넥션이라고 부른다. 비지속 커넥션은 각 처리가 끝날 때마다 커넥션을 끊지만, 지속 커넥션은 클라이언트나 서버가 커넥션을 끊기 전까지는 트랜잭션 간에도 커넥션을 유지한다. 해당 서버에 이미 맺어져 있는 지속 커넥션을 재사용함으로써, 커넥션을 맺기 위한 준비작업에 따르는 시간을 절약할 수 있다. 게다가 이미 맺어져 있는 커넥션은 TCP의 느린 시작으로 인한 지연을 피함으로써 더 빠르게 데이터를 전송할 수 있다.
그렇다면 지속 커넥션과 병렬 커넥션 중 어떤것이 더 빠를까?
지속 커넥션은 병렬 커넥션에 비해 몇 가지 장점이 있다. 커넥션을 맺기 위한 사전 작업과 지연을 줄여주고, 튜닝된 커넥션을 유지하며, 커넥션의 수를 줄여준다. 하지만 지속 커넥션을 잘못 관리할 경우, 계속 연결된 상태로 있는 수많은 커넥션이 쌓이게 된다. 이는 로컬의 리소스 그리고 원격의 클라이언트와 서버의 리소스에 불필요한 소모를 발생시킨다.
지속 커넥션은 병렬 커넥션과 함께 사용될 때에 가장 효과가 좋다. 두 가지 지속 커넥션 타입이 있다.
- HTTP/1.0+ : keep-alive
- HTTP/1.1 : 지속 커넥션
HTTP/1.0 keep-alive 커넥션을 구현한 클라이언트는 커넥션을 유지하기 위해서 요청에 Connection:Keep-Alive 헤더를 포함시킨다. 이 요청을 받은 서버는 그다음 요청도 이 커넥션을 통해 받고자 한다면, 응답 메시지에 같은 헤더를 포함시켜 응답한다. 응답에 Connection:Kepp-Alive 헤더가 없으면, 클라이언트는 서버가 keep-alive를 지원하지 않으며, 응답 메시지가 전송되고 나면 서버 커넥션을 끊을 것이라 추정한다.
Keep-Alive 헤더 사용 다음의 예는 서버가 약 5개의 추가 트랜잭션이 처리될 동안 커넥션을 유지하거나, 2분 동안 커넥션을 유지하라는 내용의 Keep-Alive 응답 헤더다.
HTTP/1.1의 지속 커넥션
HTTP/1.1에서는 keep-alive 커넥션을 지원하지 않는 대신, 설계가 더 개선된 지속 커넥션을 지원한다.
기본적으로 활성화 되어 있으며 별도 설정을 하지 않는 한, 모든 커넥션을 지속 커넥션으로 취급한다. HTTP/1.1 애플리케이션은 트랜잭션이 끝난 다음 커넥션을 끊으려면 Connection: close 헤더를 명시해야 한다. 하지만 헤더가 없더라도 커넥션을 영원히 유지하겠다는 것을 뜻하지는 않는다.
'네트워크' 카테고리의 다른 글
캐시 (0) | 2024.08.07 |
---|---|
웹 서버 (1) | 2024.08.06 |
HTTP 완벽 가이드 - 커넥션 관리 (0) | 2024.07.21 |
HTTP 완벽 가이드 - HTTP 메시지 (0) | 2024.07.11 |
HTTP 완벽 가이드 - URL과 리소스 (0) | 2024.07.10 |