HTTP 커넥션
- 전세계 모든 HTTP 통신은 TCP/IP
- 어디서든 클라이언트는 서버로 TCP/IP 커넥션 연결 가능
- 커넥션 연결 시 상호간의 메세지들은 손실 및 손상이 없으며, 순서대로 안전하게 전달
- HTTP커넥션은 몇몇 사용규칙을 제외하고는 사실상 TCP 커넥션
- 컴퓨터는 항상 TCP를 여러개 가지고 잇으며 TCP는 포트번호로 여러개의 커넥션 유지
브라우저와 서버 간의 통신 과정
1. 브라우저가 호스트명에 대한 IP 주소와 포트번호를 찾는다. www.dreaming-soohyun.tistory.com:80 -> 192.168.0.1, 80
2. 브라우저가 해당 IP 및 포트로 TCP 커넥션을 생성한다. (커넥션 생성은 서버와의 거리, 서버의 부하, 인터넷 혼잡도에 따라 시간이 걸림)
3. 요청 및 응답 후 커넥션을 끊는다.
TCP
- TCP는 세그먼트라는 단위로 데이터 스트림을 나누고, 각각의 TCP세그먼트는 하나의 IP주소에서 다른 IP주소로 IP패킷에 담겨 인터넷을 통해 데이터를 전달
- 이 과정은 TCP/IP 소프트웨어에 의해 처리되며 http 프로그래머는 보이지 않음
IP 패킷
- IP패킷해더(보통 20Byte)
: 발신자와 목적지 IP주소, 크기, 기타 플래그
- TCP 세그먼트 헤더(보통 20Byte)
: TCP 포트번호, TCP 제어 플래그, 데이터의 순서와 무결성을 검사하기 위해 사용되는 숫자 값
- TCP 데이터 조각(0 or LIMIT)
: 전송할 데이터 조각
TCP 구성 및 식별방법
- 발신지 IP주소, 발신지 포트, 목적지 IP주소, 목적지 포트로 식별하며 네 가지 커넥션 구성요소가 똑같은 커넥션은 존재 불가
TCP 소켓 프로그래밍
- 운영체제는 TCP 커넥션 생성과 관련된 여러 기능을 소켓 API(TCP API)를 통해 제공한다.
- TCP API는 세부사항을 외부로부터 숨긴다. 즉, HTTP 프로그래머는 볼 수 없다.
TCP 성능에 대한 고려사항
- HTTP 트랜잭션의 성능은 TCP 커넥션 성능에 영향을 받음
- HTTP 트랜잭션을 처리하는 시간은 TCP 커넥션을 설정, 요청 전송, 응답메시지 발송에 비해 매우 짧음
즉, 대부분의 HTTP 지연은 TCP 네트워크 지연에 의해 발생
HTTP 트랜잭션을 지연시키는 원인
1. 최근에 방문한 적 없는 사이트 접속 시 DNS 분석으로 호스트명을 IP로 변환하는데 시간이 걸림
2. TCP 커넥션 요청을 보내고 회신하여 연결하는 시간이 수백 개의 HTTP 트랜잭션에 의해 크게 증가
3. 요청과 응답을 주고 받는 시간(거리)
- TCP 네트워크 지연은 하드웨어 성능, 네트워크와 서버의 전송속도, 요청과 응답 메세지의 크기, 클라이언트와 서버 간의 거리, TCP 프로토콜의 기술적인 복잡성이 크게 영향
HTTP 커넥션 관리
- HTTP 메세지는 클라이언트에서 서버까지 중개 서버(프락시, 캐시 등)을 하나하나 거치면서 전달
- Connection헤더로 커넥션을 제어할 수 있으며 다른 곳으로 전달하는 시점에서 반드시 삭제되어야한다. 이를 흡별(hop by hop)이라 한다.
-Conntection 헤더는 총 세가지 종류의 토큰이 전달된다.
(ex. Connection : close)
1. HTTP 헤더 필드 명은, 이 커넥션에만 해당되는 헤더들 나열
2. 임시적인 토큰 값은 커넥션에 대한 비표준 옵션
3. close 값은 커넥션이 작업이 완료되면 종료되어야 함
HTTP 커넥션 성능 향상 방법
- 만약, HTML 하나와 3개의 이미지를 받아와서 띄워주는 페이지가 있다면, 순차적 트랜잭션 처리 시 커넥션을 맺는데 발생하는 지연과 TCP의 느린 시작 지연 등의 문제로 모든 트랜젝션이 종료될 때까지 빈 화면만 출력하게 된다.
간단하게는 HTML 내부 컨텐츠(객체)의 폭과 높이를 명시하여 일단 HTML 틀 먼저 출력 가능하나 완전한 해결책은 아니다.
1. 병렬 커넥션
- 여러 개의 TCP 커넥션을 통한 동시 HTTP 요청
- 위 상황에서 HTML을 먼저 받아 온뒤 여러 개의 커넥션을 이용하여 병렬 방식으로 이미지를 받아온다.
- TCP의 느린 시작으로 인해 각 커넥션 사이에는 짧게 지연이 발생 한다.
- 병렬 처리 시 남는 대역폭을 사용하므로, 네트워크 대역폭이 좁을 때 여러 개의 커넥션을 생성하면서 생기는 부하로 인해 오히려 느려질 가능성이 있다.
- 하지만 사용자 입장에서는 동시에 내려받는 것 처럼 보이기 때문에 심리적으로 빠르다고 느낄 수 있다.
2. 지속 커넥션
- 커넥션을 맺고 끊는 데서 발생하는 지연을 제거하기 위한 TCP 커넥션 재활용
- 커넥션 생성 삭제와 TCP의 느린 시작의 문제를 해결해 순차적이지만 보다 빠름
- 하지만 이 역시 순차적이기에 병렬 커넥션과 함께 사용될 때 가장 효과적
지속 커넥션은 HTTP/1.0의 Keep-Alive와 HTTP/1.1의 '지속' 커넥션을 이용한다.
HTTP/1.0의 Keep-Alive 커넥션
- 현재는 사용하지 않기로 결정되어 HTTP/1.1 명세에서는 제외 되었으나 하휘호환성을 위해 고려해야함
- Keep-Alive 커넥션은 유지를 위해 요청과 응답에 항상 Connection: Keep-Alive를 추가해야한다.
- 서버 요청 시 해당 커넥션 정보가 없다면 클라이언트가 Keep-Alive를 지원하지 않는 것으로 간주
- 응답에 해당 커넥션 정보가 없다면 서버가 Keep-Alive를 끊은 것으로 추정
- 옵션 (ex. Connection: Keep-Alive Keep-Alive: max=5, timeout=120)
: timeout(커넥션 유지시간), max(몇 개의 HTTP 트랜잭션 처리할 때까지 유지될 것인가) 등
위 예제에서는 120초 또는 5개의 요청이 처리될 동안만 유지하게 끔 옵션 설정
문제점
- 커넥션이 끊어지기 전에 엔터티 본문의 길이를 알아야 너넥션 유지 가능
- 프락시와 게이트웨이는 Connection 헤더의 규칙을 철저히 지켜야 하며 메세지 전달 전 삭제 필수
- Keep-Alive를 인식하지 못하는 프락시 때문에 행(hang)에 걸릴 수 있다.
: 프락시에 전달 된 Connection: Keep-Alive헤더를 삭제하지 않고 그대로 서버에 전달한다.
서버는 커넥션을 끊지 않고 다시 해당 헤더를 프락시에게 전달하지만 프락시는 해당 커넥션이 끊어지기를 기다린다.
따라서, 프락시는 다음 요청을 받지 않은 채 Keep-Alive가 끊어지기만을 기다리는 행에 걸린다.
=> 해결방안
Proxy-Connection 헤더 사용
: 클라이언트에서 Proxy-Connection: keep-Alive를 보매년 프락시가 이를 인식, 서버에 Connection: keep-Alive로 보내 주며 서버의 응답에 포함된 해당 커넥션 헤더를 클라이언트에게 반환해준다.
하지만 하나의 프락시만 있는 경우에만 사용 가능하며, 여러 개 존재 시 다른 프락시에 의해 잘못 전달 될 수 있다.
문제를 발생시키는 프락시들은 방화벽, 캐시서버, 리버스 프락시 서버 가속기와 같이 네트워크상에서 보이지 않는
경우 가 많다. 따라서 보이지 않는 웹 애플리케이션들이 지속 커넥션을 명확히 구현해야한다.
HTTP/1.1의 지속 커넥션
- Keep-Alive와 목적이 같지만 설계가 개선됨
- HTTP/1.0과 달리 지속 커넥션이 기본 활성화 되어 있으며, 별도 설정이 없을 시 모든 커넥션을 지속 커넥션으로 취급
- HTTP/1.1의 프락시는 클라이언트와 서버 각각에 대해 별도의 지속 커넥션을 맺고 관리 필요
- 지속 커넥션은 언제든지 끊을 수 있음
- 중간에 끊어지는 커넥션을 복구할 수 있어야 하며 응답을 받기 전 커넥션이 끊어지면, 다시 보낼 준비가 되어야 한다.
- 하나의 클라이언트는 서버 과부화 방지를 위해 2개의 지속 커넥션을 유지해야함. N명 사용자 - 2N개 지속커넥션 유지
3. 파이프라인 커넥션
- 공유 TCP 커넥션을 통한 병렬 HTTP 요청
- 지속 커넥션을 통해 요청을 파이프라이닝 하여 지속 커넥션의 성능을 올려줌
- 예를 들어 첫 번째 요청을 지구 반대편의 서버로 전달했지만 응답이 오지 않았을 때, 여기에 이어 파이프라인을 통해 다음 요청들을 미리 보내는 방식이다.
따라서 전송 대기 시간이 감소 해 통신 속도가 올라가게 되지만 여러가지 제약사항이 있다.
: 1. 지속 커넥션에만 사용 가능 (지속 커넥션 여부 파악 필요)
2. 응답은 요청 순서와 같게 와야된다.
3. 클라이언트는 커넥션이 끊어지더라도, 완료되지 않은 요청이 파이프라인에 있으면 언제든 다시 요청보낼 준비 필요
4. POST 처럼 비멱등 요청(서버의 데이터의 변화가 있을 시)은 반복해서 보낼 경우 문제가 생길 수 있으므로 사용 불가
4. 다중 커넥션
- 요청과 응답들에 대한 중재(실험중인 기술)
커넥션 끊기
- 커넥션 관리(특히, 커넥션 끊기)에는 명확한 기준이 없다.
- 어떠한 HTTP 클라이언트, 서버, 프락시 등 언제든지 TCP 전송 커넥션을 끊을 수 있다.
- 보통 메세지를 다 보낸 후 끊지만, 에러가 있는 상황에서는 헤더의 중간이나 다른 엉뚱한 곳에서 끊길 수 있다.
- 일부 HTTP 서버는 커넥션을 끊으면 데이터 전송이 끝났을을 의미하는 형태이기 때문에 Content-Length의 정확한 값이 필요하다. 만약 Content-Length와 실제 전달된 엔터티의 길이 또는 Content-Length가 존재하지 않으면 정확한 길이를 서버에 다시 요청해야 한다. 이는 절대 캐시하면 안되며 프락시는 Content-Length를 정정 없이 전달해야 한다.
TCP 끊기와 리셋에러
- TCP 끊기는 전체끊기, 절반끊기 두가지 이며, 단순한 HTTP 애플리케이션은 전체 끊기만 사용할 수 있다.
- 하지만 예상치 못한 에러 발생을 예방하기 위해 절반 끊기를 사용 해야한다.
- 보통 커넥션의 출력 채널을 끊는 것이 안전, 모든 데이터를 받고 난 뒤 끊어짐을 알기 때문이다.
- 입력 채널을 끊을 시 심각한 에러로 취급하여 아직 읽히지 않은 모든 데이터를 삭제, 특히 파이프라인 커넥션에서 위험
이 경우 응답 데이터(에러)가 도착 하여도 아직 읽히지 않는 응답 데이터는 삭제되어 문제 발생
=> 권장하는 TCP 끊기 - 우하하게 커넥션 끊기
: 애플리케이션 자신의 출력 채널을 먼저 끊고, 다른 쪽에 있는 출력 채널이 끊기는 것을 기다리는 것 (절반 끊기)
하지만 상대방이 절반끊기를 구현했거나 검사한다는 보장이 없기에 출력 채널을 절반 끊기 한 후에도 데이터나
스트림의 끝을 식별하기 위해 입력 채널에 대해 주기적인 상태검사 필요
'Web' 카테고리의 다른 글
[XFF] 클라이언트 IP 가져오기 (X-Forwarded-For) (0) | 2020.04.14 |
---|---|
[HTTP] PUT, PATCH 차이점 (0) | 2020.04.07 |
동일출처정책과 CORS 그리고 해결 방법 (1) | 2020.03.02 |