TCP Connection
- 전 세계 모든 통신은 패킷 교환 네트워크 프로토콜들의 계층집합인 TCP/IP를 통해 이루어짐
→ 일단 커넥션이 맺어지면 client-server 간에 주고받는 메시지들은 안전하게 전달
(손실/손상 X, 순서 바뀜X)
- 구성
-
발신지 IP주소
-
발신지 port
-
수신지 IP주소
-
수신지 port
⇒ 위 네 가지 값으로 유일한 커넥션 생성
TCP 커넥션이 이루어지는 예
http://www.joes-hardware.com:80/power-tools.html
1) 브라우저가 URL에서 호스트 명 추출: www.joes-hardware.com:80
2) DNS로 호스트 명에 대한 IP 주소를 찾음
3) TCP 커넥션 생성: 호스트 IP 주소와 포트 번호80
4) 브라우저가 서버로 HTTP GET 요청 메시지 전송
5) 서버가 브라우저로 HTTP 응답 메시지 전송
6) 브라우저가 응답 메시지 수신
7) 커넥션 종료
TCP 스트림
- HTTP는 현재 연결되어 있는 TCP 커넥션을 통해서 메시지 데이터의 내용을 순서대로 보냄

- TCP는 segment 단위로 데이터 스트림을 잘게 나누고 IP 패킷에 담아 전달
IP 패킷
- IP 패킷 헤더 (20byte)
- TCP Segment 헤더(20byte)
- TCP 데이터 조각

TCP socket programming

socket API
- TCP endpoint 구조 생성
- 원격 서버의 TCP endpoint에 데이터 스트림을 읽고 쓸 수 있음
- 예시
- socket() : 새로운 익명 소켓 생성 (미연결)
- bind() : 소켓에 ip주소, port번호 할당
- connect() : 로컬 소켓과 원격 host/port 사이에 TCP 커넥션 생성
- listen() : 소켓 커넥션 허가
- accept() : 다른 소켓으로부터의 커넥션 기다림
- read() : 소켓으로부터 버퍼에 n-byte 읽기 시도
- write() : 소켓으로부터 버퍼에 n-byte 쓰기 시도
- close() : TCP 커넥션 종료
HTTP 트랜잭션 지연

HTTP 트랜잭션을 지연시킬 수 있는 원인
- 방문한 적 없는 호스트
⇒ DNS로 호스트 명을 IP 주소로 변환하는 데 시간 소요
- 새로운 TCP 커넥션 설정 시간
⇒ 클라이언트가 TCP 커넥션 요청을 서버에 보내 응답을 회신받는 데 시간 소요
- 서버에서의 요청 처리 시간
- 서버가 HTTP 응답을 보내는 데 걸리는 시간
- etc…
TCP 커넥션의 handshake 지연
- 새로운 TCP 커넥션을 맺을 경우 TCP 소프트웨어가 커넥션 설정을 위해 연속으로 패킷 교환
TCP 커넥션 handshake 순서
1) 새 TCP 커넥션 생성을 위해 client가 server로 SYN(커넥션 생성 요청) 플래그를 포함한 작은 TCP 패킷을 전송
2) server가 그 커넥션 요청을 수락하게 되면 SYN + ACK 플래그를 포함한 TCP 패킷을 client에 전송
3) client가 커넥션이 잘 맺어졌음의 의미로 다시 server로 ACK를 전송
(오늘날에는 ACK와 데이터를 같이 보낼 수 있음)

- 그러나 작은 크기의 데이터를 전송하는 데에도 커넥션이 사용된다면 이런 패킷 교환은 HTTP 성능을 저하시킬 수 있음
- TCP의 ACK 패킷은 HTTP 요청 메시지 전체를 전달할 수 있을만큼 큰 경우 多
- 크기가 작은 HTTP 트랜잭션은 50% 이상의 시간을 TCP 구성에 소요
ACK(확인응답) 지연
- 각 TCP segment는 순번과 데이터 무결성 checksum을 가짐
- 각 segment의 수신자는 segment를 온전히 받으면 작은 ACK 패킷을 반환
- 만약 특정 시간 내로 수신자에게서 ACK 반환이 없으면 데이터 재전송
- ACK는 크기가 작으므로 TCP는 같은 방향으로 송출되는 데이터 패킷과 ACK를 묶어서 전송
확인응답(ACK) 지연 알고리즘
- ACK가 같은 방향으로 가는 데이터 패킷에 편승(piggyback)되는 경우를 늘리기 위한 알고리즘
- 동작
1) 송출할 ACK를 특정시간(보통 0.1~0.2s) 동안 버퍼에 저장
2) ACK를 편승시킬 송출 데이터 패킷 탐색
- 시간 내에 송출 데이터 패킷을 찾지 못하면 ACK는 별도 패킷을 만들어 전송
- 그러나 요청-응답 방식의 HTTP 특성상 같이 송출될 패킷을 찾기 힘듦
⇒ ACK 지연 알고리즘으로 인한 지연 자주 발생
TCP slow start로 인한 지연
slow start (느린 시작)
- TCP 커넥션의 초기에는 최대 속도를 제한하다가
- 데이터가 성공적으로 전송됨에 따라 속도제한 ↑
⇒ 인터넷의 급작스러운 부하와 혼잡 방지
- 한 개의 패킷 전송 → ACK 송신 → 2개의 패킷
⇒ opening the congestion window
- 새로운 커넥션은 튜닝된(이미 데이터를 주고받은 적 있는) 커넥션보다 느림
Nagle 알고리즘
- 작은 크기의 데이터를 포함한 다량의 패킷을 전송하면 네트워크 성능 ↓
Nagle 알고리즘
Nagle 알고리즘이 야기하는 문제
- 충분히 패킷을 채울 때까지 전송 지연
- ACK 지연과 함께 쓰일 경우 성능 하락
해결책
- HTTP 스택에 TCP_NODELAY 파라미터 값을 설정하여 nagle 알고리즘 비활성화 가능
TIME_WAIT 지연, 포트 고갈
TIME WAIT(커넥션 종료 지연)
- TCP 커넥션의 endpoint 에서 커넥션 종료 시,
- 메모리의 control block(제어 블록)에 커넥션의 IP 주소와 포트 번호 기록
⇒ 해당 커넥션이 일정 시간(보통 2MSL 정도) 동안 생성되지 않도록 함
⇒ 이전 커넥션과 관련된 패킷이 똑같은 주소/포트로 된 새로운 커넥션에 삽입되는 문제 방지
TIME WAIT가 야기하는 문제
- client가 server에 접속할 때마다 유일한 커넥션을 생성하기 위해 새로운 발신지 port 사용
- 그러나 사용할 수 있는 발신지 포트 수는 제한되어 있음
- e.g) 발신지 포트 수 = 60,000
- 2MSL초(120초) → 초당 500개로 커넥션 제한
Connection 헤더
사용하는 경우
- HTTP client-server 사이에는 중개 서버(proxy, cache, …)가 놓일 수 있음
- 두 개의 인접한 HTTP 애플리케이션이 맺고 있는 커넥션에만 적용될 옵션을 지정해야 할 경우
- HTTP Connection 헤더 필드에 명시된 커넥션 토큰은 다른 커넥션에 전달 X
Connection 헤더에 명시되는 세 종류의 토큰
- HTTP 헤더 필드명
- 이 커넥션(hop-by-hop)에만 해당되는 헤더들
- 임시적인 토큰
- close

- HTTP 애플리케이션이 Connection 헤더와 함께 메시지를 전달받으면
- 수신자는 송신자에게서 온 요청에 기술되어 있는 모든 옵션 적용
- 다음 hop에 메시지 전달 전 Connection 헤더 삭제
순차적인 트랜잭션 처리에 의한 지연
- 각 트랜잭션이 새로운 커넥션을 필요로 할 경우
- 커넥션 생성에 발생하는 지연
- slow start 지연 발생

HTTP 커넥션 성능을 향상시킬 방법
- 병렬(parallel) 커넥션
- 지속(persistent) 커넥션
- 파이프라인(pipelined) 커넥션
- 다중(multiplexed) 커넥션
병렬 커넥션
- 여러 개의 TCP 커넥션을 통한 동시 HTTP 요청
페이지를 더 빠르게 내려받을 수 있음
- 각 커넥션의 지연 시간을 겹치게 함
⇒ 총 지연 시간 ↓
- 대역폭이 남으면 나머지 객체를 내려받는 데 사용 가능
항상 더 빠르지는 X
- 클라이언트의 네트워크 대역폭이 좁은 경우
⇒ 병렬 처리 장점 X
- 다수의 커넥션
⇒ 메모리 소모 ↑, 자체적인 성능 문제 발생
- 각 트랜잭션마다 새로운 커넥션을 맺고 끊어야 하므로 시간과 대역폭 소모
실제로는
- 브라우저: 적은 수(대부분 6-8개)의 병렬 커넥션 허용
- 서버: 특정 클라이언트로부터 과도한 수의 커넥션이 맺어졌을 경우 임의로 끊기 가능
지속 커넥션
- TCP 커넥션을 재활용함으로서 커넥션 연결에서 발생하는 지연 제거
site locality
- 리소스를 요청했던 서버에 재요청할 가능성 높음
- HTTP/1.1은 트랜잭션 처리 완료 후에도 계속 연결된 상태 유지 가능
- slow start 지연 X, 빠르게 데이터 전송
병렬 커넥션과 비교한 장점
- 커넥션 연결의 사전 작업과 지연 ↓
- 튜닝된(다수의 패킷을 전송할 수 있는 권한을 얻은) 커넥션 유지
- 커넥션 수 ↓
무조건 좋은 건 아님
- 지연 커넥션을 잘못 관리하여 쌓이게 될 경우,
- client와 server의 리소스에 불필요한 소모 발생
지속 커넥션 + 병렬 커넥션
HTTP/1.0 Keep-Alive 커넥션
- 하나의 지속 커넥션으로 트랜잭션들 처리
- client
- 커넥션을 유지하고자 할 때
- 요청에 Connection: Keep-Alive 헤더 포함
- server
- 다음 요청도 이 커넥션을 통해 받고자 할 경우
- 응답 메시지에 같은 헤더 포함
- Keep-Alive 헤더 options
- timeout: 커넥션 유지 시간
- max: 커넥션이 유지 동안 처리되는 HTTP 트랜잭션 수
- 단점
- HTTP/1.0의 proxy는 Connection 헤더를 인식하지 못해 그대로 전달 ⇒ dumb proxy
HTTP/1.1 지속 커넥션
- 기본으로 활성화
- 모든 커넥션을 지속 커넥션으로 취급
- 커넥션을 종료하고자 할 경우 Connection: close 헤더 명시
- 제한
- 커넥션에 있는 모든 메시지가 자신의 길이 정보를 정확히 가지고 있을 때만 커넥션 지속
- 정확한 Content-Length 값
- 청크 전송 인코딩 (Chunked transfer encoding)
- HTTP 1.1 proxy server는 client와 server 각각에 대해 별도의 지속 커넥션을 맺고 관리
- HTTP/1.1 애플리케이션은 언제든지 중간에 끊어진 커넥션을 복구할 수 있어야 함