Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[4장] 커넥션 관리 #6

Open
eunbc opened this issue Nov 21, 2023 · 7 comments
Open

[4장] 커넥션 관리 #6

eunbc opened this issue Nov 21, 2023 · 7 comments
Labels

Comments

@eunbc
Copy link

eunbc commented Nov 21, 2023

No description provided.

@eunbc eunbc added the 2주차 label Nov 21, 2023
@annahxxl
Copy link

annahxxl commented Nov 21, 2023

TCP 커넥션

  • 클라이언트와 서버간에 주고받는 메시지들은 손실 혹은 손상되거나 순서가 바뀌지 않고 안전하게 전달된다

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

  • TCP는 포트 번호를 통해서 여러 개의 커넥션을 유지한고, 컴퓨터는 항상 TCP 커넥션을 여러개 가진다

  • TCP 커넥션은 네 가지 값으로 식별한다

    <발신지 IP 주소, 발신자 포트, 수신자 IP 주소, 수신자 포트>

TCP 소켓 프로그래밍

  • 소켓 API를 사용하면, TCP 종단 데이터 구조를 생성하고, 원격 서버의 TCP 종단에 그 종단 데이터 구조를 연결하여 데이터 스트림을 읽고 쓸 수 있다
  • 기본적인 네트워크 프로토콜의 핸드셰이킹, TCP데이터 스트림, IP패킷간의 분할 및 재조립에 대한 모든 내용을 외부로부터 숨긴다

TCP의 성능에 대한 고려

TCP 커넥션 핸드셰이크 지연

  • 새로운 TCP 커넥션을 열 때면, TCP 소프트웨어는 커넥션을 맺기 위한 조건을 맞추기 위해 연속으로 IP 패킷을 교환한다
  • 크기가 작은 HTTP 트랜잭션은 50% 이상의 시간을 TCP를 구성하는데 쓴다

💡(참고) TCP 3way, 4way handshake 차이

플래그 종류

  • SYN : 연결 요청 플래그, 임의의 시퀀스 번호
  • ACK : 응답 플래그, 일반적으로 SYN + 1 하여 보낸다
  • FIN : 종료 플래그, 더 이상 전송할 데이터가 없음을 나타냄

3way handshake

  • 클라이언트는 서버에게 요청을, 서버는 클라이언트에게 응답을 전송할 수 있는지 확인하는 방식
  • 3번의 확인 과정을 거친다고 해서 3way handshake 라고 부른다
  • 과정
    1. 한 장치로부터 연결 확인을 위한 SYN(연결 확인을 위해 보내는 무작위의 숫자값)값을 먼저 보내고
    2. 다른 장치에서는 받은 SYN값에 일반적으로 1을 더한 ACK값과 또 다른 SYN를 함께 낸다
    3. 그럼 다시 처음 장치에서는 상대 장치로부터 SYN값을 잘 받았다는 표시로 ACK를 보내게 된다

4way handshake

  • 연결을 해제할때 주고 받는 확인 작업이다
  • 이건 4번의 과정을 거치게 된다
  • 과정
    1. 예를들어 클라이언트(한 장치)부터 앱을 종료하겠다를 의미하는 FIN을 보낸다
    2. 서버는 확인의 표시로 ACK를 보낸다
    3. 그리고 서버에서 다시 앱을 종료하겠다는 의미로 FIN을 보낸다
    4. 클라이언트에선 다시 ACK를 보내게 되어 최종적으로 연결이 종료된다

TCP 느린 시작

  • 급작스러운 부하와 혼잡을 방지하는 데 쓰인다
  • TCP 커넥션은 시간이 지나면서 자체적으로 튜닝되어서, 처음에는 커넥션의 최고속도를 제한하고 데이터가 성공적으로 전송됨에 따라서 속도 제한을 높여나간다 (패킷 수 1개 → 2개 → 4개 •••)
  • 이 혼잡제어 기능 때문에, 새로운 커넥션은 이미 어느 정도 데이터를 주고받은 튜닝된 커넥션보다 느리다

네이글(Nagle) 알고리즘과 TCP_NODELAY

  • 각 TCP 세그먼트는 40byte 상당의 플래그와 헤더를 포함하여 전송하기 때문에 작은 크기의 데이터를 포함한 많은 수의 패킷을 전송하면 네트워크 성능은 크게 떨어진다
  • 네트워크 효율을 위해서, 패킷을 전송하기 전에 많은 양의 TCP 데이터를 한 개의 덩어리로 합친다
  • 세그먼트가 최대 크기가 되지 않으면 전송을 하지 않는데, 다만 다른 모든 패킷이 확인응답을 받았을 경우에는 최대 크기보다 작은 패킷의 전송을 허락한다
  • 이러한 동작의 네이글 알고리즘은 크기가 작은 HTTP 메시지에 대해서 패킷을 채우지 못하기 때문에, 앞으로 생길지 생기지 않을지 모르는 추가적인 데이터를 기다리며 지연될 것이다
  • http 애플리케이션은 성능 향상을 위해서 http 스택에 TCP_NODELAY 파라미터 값을 설정하여 네이글 알고리즘을 비활성화 하기도 한다. 이 설정을 했다면, 작은 크기의 패킷이 너무 많이 생기지 않도록 큰 크기의 데이터를 만들어야 한다

TIME_WAIT 의 누적과 포트 고갈

  • TCP 커넥션의 종단에서 TCP 커넥션을 끊으면, 종단에서는 커넥션의 IP 주소와 포트 번호를 메모리의 작은 제어영역(control block)에 기록하는데, 이 정보는 같은 주소와 포트 번호를 사용하는 새로운 TCP 커넥션이 일정 시간 동안에는 생성되지 않게 하기 위한 것으로, 보통 세그먼트 최대 생명주기의 두 배 정도의 시간동안 유지된다
  • 이 방식은 같은 IP주소와 포트 번호를 가지는 커넥션이 짧은 시간 이내에 또 생성되는 것을 막아준다
  • 일반적인 상황에서는 문제가 되지 않지만, 클라이언트가 접속할 수 있는 IP 주소의 개수를 제한하고 성능측정을 하는 상황에서는 문제가 될 수 있다

HTTP 커넥션 관리

  • 커넥션 종류
    • 병렬 커넥션 : 여러 개의 TCP 커넥션을 통한 동시 HTTP 요청
    • 지속 커넥션 : 커넥션을 맺고 끊는 데서 발생하는 지연을 제거하기 위한 TCP 커넥션의 재활용
    • 파이프라인 커넥션 : 공유 TCP 커넥션을 통한 병렬 HTTP 요청
    • 다중 커넥션 : 요청과 응답들에 대한 중재 (실험적인 기술이다)
  • 지속 커넥션은 병렬 커넥션과 함께 사용될 때에 가장 효과적이다

@eunbc
Copy link
Author

eunbc commented Nov 22, 2023

TCP 커넥션

  1. 신뢰할 수 있는 데이터 전송 통로인 TCP
  2. TCP는 세그먼트라는 단위로 데이터 스트림을 잘게 나누고, 세그먼트를 IP 패킷이라고 불리는 봉투에 담아서 인터넷을 통해 데이터를 전달한다
  3. TCP 커넥션은 <src IP, src Port, dst IP, dst Post> 값으로 유일한 커넥션을 생성한다
  4. 소켓은 TCP 프로그래밍 인터페이스이다

TCP의 성능에 대한 고려

  1. HTTP는 TCP 바로 위에 있는 계층이기 때문에 HTTP 트랜잭션의 성능은 그 아래 계층인 TCP 성능에 영향을 받는다
    1. 트랜잭션을 처리하는 시간 < (DNS 찾기 + TCP 커넥션 연결 + HTTP 요청 + HTTP 응답)
    2. TCP 커넥션 핸드셰이크 지연 - 3 way handshake
    3. 확인 응답 지연 : 확인 응답(ACK)은 그 크기가 작기 때문에, TCP는 같은 방향으로 송출되는 데이터 패킷에 확인 응답을 편승(같이 얻어 태워 보냄)시킨다. 편승되는 경우를 늘리기 위해 TCP 스택은 ‘확인 응답 지연’ 알고리즘을 구현한다
    4. TCP 느린 시작 : TCP 커넥션은 시간이 지나면서 자체적으로 튜닝되어서, 처음에는 커넥션의 최대 속도를 제한하고 데이터가 성공적으로 전송됨에 따라서 속도 제한을 높여나간다.
    5. 네이글 알고리즘 : 네트워크 효율을 위해 패킷을 전송하기 전에 많은 양의 TCP 데이터를 한 개의 덩어리로 합친다. 단, 세그먼트가 최대 크기가 되지 않으면 전송을 하지 않기 때문에 크기가 작은 HTTP 메시지는 패킷을 채우지 못하여 지연될 수 있다
    6. TIME_WAIT의 누적과 포트 고갈 : 같은 주소와 포트 번호를 사용하는 새로운 TCP 커넥션이 일정 시간에는 생성되지 않게 하기 위함

HTTP 커넥션 관리

  1. 어떤 경우에는 두 개의 인접한 HTTP 어플리케이션이 현재 맺고 있는 커넥션에만 적용될 옵션을 지정해야 할 때가 있다. 커넥션 토큰이 HTTP 헤더 필드 명을 가지고 있으면, 해당 필드들은 현재 커넥션만을 위한 정보이므로 다음 커넥션에 전달하면 안 된다.
  2. 순차적인 트랜잭션 처리에 의한 지연
    1. 3개의 이미지가 있는 웹페이지일 경우, 각 이미지를 받기 위해 매번 새로운 커넥션을 필요로 한다면, 커넥션을 맺는데 발생하는 지연과 함께 느린 시작 지연이 발생할 것이다

병렬 커넥션

  1. HTTP는 클라이언트가 여러 개의 커넥션을 맺음으로써 여러 개의 HTTP 트랜잭션을 병렬로 처리할 수 있게 한다
  2. HTML 페이지를 먼저 내려받고 남은 세 개의 트랜잭션이 각각 별도의 커넥션에서 동시에 처리되는 예시
  3. 장점
    1. 병렬로 처리하여 커넥션 지연이 겹쳐지므로 총 지연시간이 줄어든다
    2. 사용자는 더 빠르게 내려받고 있는 것처럼 느낄 수 있다
  4. 단, 네트워크 대역폭이 좁을 경우 대부분의 시간을 데이터 전송하는 데만 쓰기 때문에 성능상의 장점은 없어진다
  5. 단점
    1. 각 트랜잭션마다 새로운 커넥션을 맺고 끊기 때문에 시간과 대역폭이 소요된다.
    2. 각각의 새로운 커넥션은 TCP 느린 시작 때문에 성능이 떨어진다
    3. 연결할 수 있는 병렬 커넥션의 수에는 제한이 있다

지속 커넥션

  1. 장점 : 커넥션을 맺기 위한 사전 작업과 지연을 줄어주고, 튜닝된 커넥션을 유지하며, 커넥션의 수를 줄여준다
  2. 지속 커넥션은 병렬 커넥션과 함께 사용될 때에 가장 효과적이다
  3. HTTP/1.0+의 Keep-Alive 커넥션
    1. HTTP/1.0에서 기본적으로 사용되지 않으며, 클라이언트는 keep-alive 커넥션을 사용하기 위해 요청에 Connection:Keep-Alive 헤더를 포함시켜야 한다
    2. keep-alive와 멍청한(dumb) 프락시 문제 : 프락시가 Connection 헤더를 이해하지 못하고 keep-alive를 계속 전달하여 서버 쪽에서 커넥션을 끊지 않게 된다. 한편 프락시는 커넥션이 끊어지길 기다린다. 결국 브라우저는 서버가 타임아웃이 나서 커넥션이 끊길 때까지 기다린다.
    3. 넷스케이프는 멍청한 프락시 문제를 해결하기 위해 Connection 헤더 대신에 비표준인 Proxy-Connection 확장 헤더를 프락시에게 전달한다. 단, 클라이언트와 서버 사이에 한 개의 프락시만 있는 경우에서만 동작한다
  4. HTTP/1.1의 지속 커넥션
    1. keep-alive와는 달리, HTTP/1.1의 지속 커넥션은 기본으로 활성화되어 있다
    2. 트랜잭션이 끝난 다음 커넥션을 끊으려면 Connection: close 헤더를 명시해야 한다

파이프라인 커넥션

  1. 여러 개의 요청은 응답이 도착하기 전까지 큐에 쌓인다. 대기 시간이 긴 네트워크 상황에서 네트워크상의 왕복으로 인한 시간을 줄여서 성능을 높여준다.

@kimday0326
Copy link
Member

kimday0326 commented Nov 22, 2023

TCP 커넥션

  1. 모든 HTTP 통신은 널리 쓰이는 프로토콜의 집합인 TCP/IP 를 통해 이루어진다.
  2. TCP/IP 커넥션이 맺어지면 서버와 클라이언트 간에 주고받는 메시지는 바뀌지 않고 안전하게 전달된다.
  3. TCP 스트림은 세그먼트로 나뉘어 IP 패킷을 통해 전송되며, 하나의 세그먼트는 여러 개의 패킷으로 쪼개질 수 있다.
  4. TCP는 하나의 컴퓨터에서 포트번호를 통해서 여러개의 커넥션을 유지한다. TCP 커넥션의 식별 값은 아래와 같다.
    <발신지 IP, 발신지 포트번호, 수신지 IP, 수신지 포트번호>
  5. 수신지 IP = 도로명 주소, 수신지 포트번호 = 상세 주소(동, 호수) 와 같다.
  6. TCP 커넥션을 이용한 통신 방법에는 소켓이 있다. 서버는 소켓 API를 사용해 소켓을 열고, 클라이언트와 통신한다.

TCP 성능에 대한 고려

TCP 커넥션 핸드 셰이크 지연

  1. TCP는 커넥션을 맺기 위해 3-way-handshaking을 진행한다.
  2. 그 중, SYN / SYN+ACK 를 주고받는 과정에서 지연이 발생하고, 크기가 작은 HTTP 트랜잭션은 TCP를 구성하는데 전체의 50% 이상의 시간을 사용하게된다.

확인 응답 지연

  1. TCP는 성공적인 전송을 보장하기 위해, 수신자가 세그먼트를 온전히 받으면 확인응답 패킷을 전송한다.
  2. 확인응답 패킷은 크기가 작기때문에, 확인 응답을 다른 패킷에 편승시키는 확인응답 지연 알고리즘을 사용하게 된다.
  3. 그러나, 확인 응답 지연 알고리즘이 편승할 패킷을 찾지 못해 또 다른 지연이 발생한다.
  4. 따라서 해당 알고리즘을 수정하거나 비활성화 할 수 있다.

TCP 느린 시작

  1. TCP 커넥션은 처음에는 최대 속도가 제한되지만, 점차 속도 제한을 늘려나가는 튜닝을 진행한다.
  2. 패킷을 보내고 확인 응답 패킷을 받으면 보낼 수 있는 패킷의 개수가 늘어나며, 이를 "혼잡 윈도우를 연다" 고 한다.
  3. 따라서 튜닝된 커넥션은 새로 생긴 커넥션보다 더 빠르고, 이를 재사용하기 위해 추후에 "지속 커넥션" 이라는 개념이 등장한다.

네이글 알고리즘과 TCP_NODELAY

  1. 작은 데이터를 여러 번에 나눠 전송하면 네트워크 효율성이 떨어지므로, 네이글 알고리즘이 생겨났다.
  2. 네이글 알고리즘은 세그먼트가 최대 크기가 되거나, 모든 패킷이 확인 응답을 받았을 경우에만 버퍼에 저장된 데이터를 전송한다.
  3. 하지만 크기가 작은 HTTP 메시지는 세그먼트를 모두 채우지 못하기 때문에, 추가적인 데이터를 기약없이 기다리게 된다.
  4. 또한, 확인 응답 지연과 함께 쓰일 경우 확인응답 지연시간 + 네이글 알고리즘의 대기시간이 낭비된다.
  5. 따라서 TCP_NODELAY 파라미터 값을 설정해 네이글 알고리즘을 비활성화하기도 한다.

TIME_WAIT의 누적과 포트 고갈

  1. 이전 커넥션의 패킷이 새로 생긴 커넥션으로 삽입되 충돌이 일어나는 상황을 막기 위해, 커넥션이 끊어지면 일정 시간동안은 같은 정보로 커넥션을 생성할 수 없도록 한다.
  2. 일반적으로는 문제가 되지 않지만, 성능 시험 상황에서 적절한 부하를 발생시키지 못 할수도 있다.

HTTP 커넥션 관리

문제점

  • 흔히 잘못 이해하는 Connection 헤더
    해당 커넥션에서만 존재해야하는 Connection 헤더를 다음 헤더까지 전달하는 경우
  • 순차적인 트랜잭션 처리에 의한 지연
    매 트랜잭션마다 커넥션을 맺음으로써 발생하는 지연
  1. 병렬 커넥션 (Parallel Connection)
    -> 여러 개의 독립적인 TCP 커넥션을 사용하여 동시에 여러 HTTP 요청을 처리하는 방식. 페이지 로딩 시간을 단축시키지만, 네트워크 대역폭이 좁을 경우 성능 이점이 줄어들 수 있다.

  2. 지속 커넥션 (Persistent Connection)
    -> 하나의 TCP 커넥션을 여러 HTTP 트랜잭션에 재사용함으로써 커넥션 맺기와 끊기의 오버헤드를 줄이는 방식. 네트워크 효율성을 높이고 전체적인 통신 성능을 개선한다.

  3. 파이프라인 커넥션 (Pipelining Connection)
    -> 하나의 지속 커넥션을 통해 여러 HTTP 요청을 연속적으로 전송하고, 응답을 순서대로 받는 방식. 이는 네트워크 대기 시간을 줄이고, 특히 대기 시간이 긴 환경에서 효율성을 높일 수 있다.

@byulcode
Copy link

byulcode commented Nov 22, 2023

TCP 커넥션


  • TCP 커넥션이 맺어지면 클라이언트와 서버간에 주고받는 메시지들은 손실 혹은 손상되거나 순서가 바뀌지 않고 안전하게 전달된다
  • TCP는 세그먼트 단위로 데이터 스트림을 나누어 IP 패킷에 담아 데이터를 전송한다.
  • 컴퓨터는 항상 TCP 포트를 여러개 가지며, 포트 번호를 통해 여러 개의 커넥션을 유지한다.
  • TCP 커넥션은 네 가지 값으로 식별하여 유일한 커넥션을 생성한다.
    • 발신지 IP 주소
    • 발신지 포트
    • 수신지 IP 주소
    • 수신지 포트

TCP 소켓 프로그래밍

  • 운영체제에서 제공하는 TCP 소켓 API들은 HTTP 프로그래머에게 TCP 와 IP 의 세부사항을 알지 못해도 TCP 커넥션을 이용할 수 있게 해준다.

TCP 성능에 대한 고려


  • TCP 성능은 HTTP 성능에 직접적인 영향을 준다.
  • 하나의 HTTP 트랜잭션 처리에 드는 시간은 TCP 커넥션 설정, 요청, 응답에 비하면 훨씬 짧다.

TCP 커넥션 핸드셰이크 지연

  • TCP 프로토콜은 연결 및 연결 해제에 handshake 과정을 필요로 한다.
  • 크기가 작은 HTTP 트랜잭션은 tcp handshake로 인한 오버헤드가 부담이 될 수 있다.\

확인 응답 지연

  • TCP는 같은 방향으로 송출되는 데이터 패킷에 확인응답(ack)를 편승(piggyback) 시킨다.
    • 특정 시간 (보통 0.1 ~ 0.2 sec) 동안 버퍼에 ack 를 저장해두고 해당 방향의 데이터 패킷이 있다면 편승. 없다면 별도의 패킷을 만들어 전송
  • HTTP는 요청응답으로만 이루어지기 때문에 새로운 요청이 없을 때는 piggybacking을 통해 ACK 정보를 전송할 기회를 감소시키기 때문에 확인응답 지연 알고리즘에 의한 지연이 발생한다.

느린 시작

  • 네트워크를 통해 전송되는 데이터 양을 규제하 혼잡 제어 메커니즘이다.
  • 1개의 패킷으로 시작하여 승인을 기다린 후, 임계값에 도달할 때 까지 2배씩 증가시키며 속도를 높여나간다.
  • 혼잡제어 기능 때문에 새로운 커넥션은 이미 어느 정도 데이터를 주고받은 튜닝된 커넥션보다 느리다.

네이글 알고리즘

  • 네트워크 효율을 위해 패킷을 전송하기 전 많은 양의 TCP 데이터를 한 개의 덩어리로 합친다.
  • 세그먼트가 ack를 수신하거나 최대 크기가 되지 않으면 전송을 하지 않는다.
  • 크기가 작은 HTTP 메시지는 패킷을 채우지 못하기 때문에 오버헤드로 인한 부하가 증가할 수 있다.

TIME_WAIT의 누적과 포트 고갈

  • TCP 커넥션이 종료된 후 곧바로 같은 IP adress 와 port 를 사용하는 커넥션이 생성될 경우, 뒤늦게 도착한 이전 커넥션의 패킷과의 데이터 충돌이 발생할 수 있다. 이를 방지하기 위해 동일한 주소와 포트 번호를 사용하는 새로운 TCP 커넥션이 일정 시간 동안에는 생성되지 않도록 한다.
  • 위 동작을 위해 커넥션이 종료된 후, 이전 커넥션의 IP 주소와 포트번호를 메모리의 control block 에 저장해놓는다.

HTTP 커넥션 관리


  • 커넥션 관리가 제대로 이루어지지 않으면 하나의 리소스 당 하나의 커넥션을 새로 생성해야 할 수도 있기 때문에 성능이 떨어질 수 있다

병렬 커넥션
여러개의 리소스를 요청할 경우, 한번에 여러 개의 TCP 커넥션을 생성해서 병렬로 내려받는다. 각각의 리소스를 내려받는데 필요한 지연시간이 겹치기 때문에 전체 지연시간이 줄어든다. 하지만 대역폭이 좁은 경우 오히려 더 느려질 수 있다.

지속 커넥션
HTTP/1.1 에서는 처리가 완료된 TCP 커넥션을 바로 종료하지 않고 이어지는 HTTP 요청에 재사용할 수 있다. 이를 통해 새로운 커넥션을 생성하는 시간을 절약할 수 있다.

파이프라인 커넥션
파이프라인 커넥션은 하나의 TCP 연결을 통해 여러 요청을 연속적으로 전송하는 방법이다. 요청을 병렬로 처리함으로서 성능을 향상시킨다.

@park0jae
Copy link
Member

TCP 커넥션


 세계 모든 HTTP 통신은 패킷 교환 네트워크 프로토콜의 계층화  집합인 TCP/IP를 통해 이루어진다. 커넥션이 이루어지게 되면
클라이언트와 서버  주고받는 메시지들은 손실 혹은 손상되거나 순서가 바뀌지 않고 안전하게 전달된다.

[ 요청 과정 ]

  1. 브라우저가 호스트 명을 추출하고, 호스트 명에 대한 IP 주소를 찾는다.
  2. 브라우저가 포트 번호(80)를 얻고, 목적지의 IP : port로 TCP 커넥션을 맺는다.
  3. 목적지 서버로 GET 요청 메시지를 보낸다.
  4. 서버로부터 온 HTTP 응답 메시지를 읽는다.
  5. 커넥션을 끊는다.

TCP 스트림은 세그먼트

  • HTTP는 ‘IP, TCP, HTTP’로 구성된 프로토콜 스택에서 최상위 계층으로 하위 프로토콜의 동작에 대해 알지 못해도 통신이 가능
  • HTTP가 메시지를 전송하고자 할 경우, 현재 연결되어 있는 TCP 커넥션을 통해 메시지의 데이터의 내용을 순서대로 보낸다.
  • TCP는 세그먼트라는 단위로 데이터 스트림을 잘게 나누고, 세그먼트를 IP 패킷에 담아 전달한다.

TCP 커넥션 유지하기

  • 발신지 IP 주소
  • 발신지 포트
  • 수신지 IP 주소
  • 수신지 포트

→ TCP 커넥션을 유지하기 위해 위의 4가지로 구성된 값이 필요한데, 이를 4-tuple이라고 한다. 4개 중 일부는 값이 같을 수 있지만 4가지가 모두 같은 서로 다른 TCP 커넥션은 존재할 수 없다.

[ TCP는 소켓을 기반으로 커넥션이 맺어지고, Bind Port와 Connection Port가 존재한다. ]

Bind Port(리스닝 포트) 실제 Connection Port(데이터 전송 포트)
- 서버는 특정 포트에서 연결을 수신하기 위해 bind(바인드) 포트를 가지고 있다. 이는 서버의 리스닝 포트이다.
- 실제로 데이터가 주고받는 포트는 연결이 맺어진  사용되는 포트이다. 이는 서버와 클라이언트  실제 데이터 전송에 사용된다.
- Connection Port는 일반적으로 동적으로 할당되며, 서버가 정해준다.

TCP 소켓 프로그래밍

  • TCP/IP 소켓통신
    • 클라이언트 프로그램과 서버 프로그램은 각각 자신의 포트를 통해 통신을 해야 하는데, 소켓을 통해 연결한다.
  • 소켓 API
    • 가장 널리 사용되는 표준 인터페이스
    • HTTP 프로그래머에게 TCP와 IP의 세부사항들을 숨김
    • TCP 종단(endpoint) 데이터 구조를 생성하고, 원격 서버의 TCP 종단에 그 종단 데이터 구조를 연결하여 데이터 스트림을 읽고 쓸 수 있다.

TCP 커넥션 성능 관리


  • TCP 성능은 HTTP의 성능에 직접적인 영향을 준다.
  • HTTP 트랜잭션 시간에 영향을 주는 요소들
    • TCP 커넥션 설정
    • 요청 전송
    • 요청 처리
    • 응답 전송

→ 실제 요청을 처리하는 시간에 비해 TCP 네트워크 지연이(커넥션 연결, 요청, 응답) 훨씬 크다.

TCP 성능이 많이 느려지는 이유…

  • TCP 커넥션의 HandShake 설정
    • 모든 연결 시 거쳐야하는 과정으로, 크기가 작은 HTTP 트랜잭션은 handshake로 인한 오버헤드가 부담이 될 수 있다.
    • SYN과 SYN-ACK을 위한 시간이 너무 오래 걸린다.
  • 확인 응답 지연
    • TCP의 특징으로 데이터의 손실, 손상을 방지하고 순서를 보장하기 위해 Sequence Number와 Checksum을 통해 순번과 데이터의 무결성을 체크한다.
    • 따라서 수신측이 데이터를 정상적으로 받으면, 확인응답패킷을 송신측으로 보낸다.
    • 여기서 TCP는 효율적인 통신을 위해 확인응답패킷을 데이터 패킷과 함께 전송하는데 이를 편승(Piggybacking)이라고 함
    • 더 많은 확인응답패킷을 한 번에 편승시키기 위해, 확인응답지연 알고리즘을 사용하는데 일정 시간 동안 편승 시킬 패킷을 찾고 찾지 못하면 새로운 패킷을 만들어 전송한다.
    • 그런데 보통, HTTP 통신은 요청과 응답 두 가지로만 이루어지기 때문에 편승될 기회가 많이 없어 이로 인한 지연이 발생한다.
    • 송신측에서는 수신측의 확인응답패킷을 기다리게되고, 수신측에서는 데이터를 정상적으로 수신했지만 편승시킬 패킷을 찾기위해 대기 ⇒ 지연 발생
  • 인터넷 혼잡을 피하기 위한 TCP의 slow start
    • 현재 네트워크 망의 혼잡 상태를 확인하여 한 번에 전송하는 패킷의 양을 조절하는 알고리즘이 존재 (Congestion control)
    • congestion window의 크기는 1부터 시작하여 임계값에 도달할 때까지 2의 지수배로 증가 (이후에는 1씩 증가)
  • Nagle Algorithm (네이글 알고리즘)
    • TCP 세그먼트는 꽤나 큰 크기의 헤더를 포함하기 때문에 아주 작은 데이터를 전송하면 오히려 오버헤드로 인한 부하가 증가한다.
    • 세그먼트가 최대 크기가 될 때 까지 전송을 하지 않고 버퍼에 데이터를 쌓아 두었다가 전송한다.
    • 다른 모든 패킷이 확인 응답을 받으면, 최대 크기보다 작더라도 전송을 허용한다.
    • 확인응답지연과 아주 최악의 상성…
  • TIME_WAIT의 누적과 포트 고갈
    • TCP 커넥션이 끊어지면 종단에서 커넥션의 IP 주소, 포트번호를 기록해놓는다.
    • 보통 2MSL(Maximum Segment Lifetime)을 기반으로 같은 커넥션이 또 생성되는 것을 막는다.
    • MSL은 보통 TIME_WAIT상태에 있는 TCP 소켓이 유지되는 최대 시간을 의미
    • TIME_WAIT은 소켓이 종료되었지만 네트워크 상에 아직 남아있는 패킷이 처리되기를 기다리는 상태이다.
    • TCP 커넥션이 종료되면 한 측에서는 TIME_WAIT 상태로 들어가게 되고, 이 상태에서는 같은 포트를 사용하는 다른 연결이 이루어질 때의 충돌을 방지하기 위해 일정 시간 동안 대기하는데 이 때의 기준이 2MSL이다.
    • 하지만 성능 측정을 위한 서버에서는 이러한 TIME_WAIT으로 인한 문제가 발생할 수 있는데, 클라이언트 IP & 서버 IP & 서버 포트가 고정되어 있고 클라이언트의 포트만을 변경하여 유일한 커넥션을 생성해야 하기 때문에 포트가 고갈될 수 있다.

HTTP 커넥션의 성능을 향상시킬 수 있는 기술


[ 병렬 커넥션 ]

  • 각 커넥션의 지연 시간을 겹치게 하여 총 지연 시간을 줄일 수 있음
  • 네트워크 대역폭이 좁으면 여러 커넥션을 생성하며 생기는 부하로 인해 느릴 수 있다.
  • 다수의 커넥션은 메모리를 많이 소모하고 성능 문제가 있기 때문에 각 클라이언트마다 제한된 병렬 커넥션을 허용
  • 실제로 빠르게 내려받지 않아도 한 번에 여러 객체가 보이기 때문에 더 빠르게 느껴질 수 있다.

[ 지속 커넥션 ]

  • 한 웹페이지에 첨부된 리소스들은 보통 같은 웹 사이트에 있기 때문에 같은 서버로 또 요청하게 된다.
  • HTTP/1.1 에서는 처리가 완료된 TCP 커넥션을 바로 종료하지 않고 이어지는 HTTP 요청에 재사용 (지속 커넥션)
  • 커넥션을 위한 비용과 지연을 줄이고, 커넥션의 수를 줄인다. (메모리 소모 ⬇️)
  • 병렬 커넥션과 함께 사용하면 효율적 ⇒ 제한된 수의 병렬 커넥션을 맺고 그것을 유지하며 재사용
  • HTTP 버전 별로 이를 위한 커넥션이 마련되어 있음 (HTTP/1.1은 Default 값이 지속 커넥션)
  • 지속 커넥션을 인식하지 못하는 이전 버전의 프록시 서버를 멍청한 프록시(dumb proxy)라고 부르며, 클라이언트 입장에서는 계속 유지되고 있는 커넥션으로 요청을 보내지만 프록시 서버가 이 요청을 무시해버리기 때문에 브라우저는 자신이나 서버가 타임아웃이 나서 커넥션이 끊길 때까지 기다리게 된다.

[ 파이프라인 커넥션 ]

  • HTTP/1.1은 지속 커넥션을 통해 요청을 파이프라이닝 즉, 병렬 처리할 수 있다.
  • 병렬 커넥션과의 차이점은 지속 커넥션이기 때문에 매 트랜잭션마다 HTTP 커넥션 open, close 단계가 없다.
  • 제약사항
    • HTTP 클라이언트는 커넥션이 지속 커넥션인지 확인 후 파이프라인 커넥션을 사용해야 함
    • HTTP 클라이언트는 커넥션이 끊어지더라도 완료되지 않은 요청에 대해 다시 커넥션을 맺고 남은 요청을 보낼 수 있어야 함
    • 멱등성이 없는 POST 같은 요청을 파이프라인을 통해 보내선 안된다. (요청 중 일부만 실패하면 어떤 요청이 실패했는지 파악이 어려우며, 응답을 기다리지 않고 요청을 보내기 때문)

HTTP 커넥션 끊기


  • ‘마음대로’ 커넥션 끊기
    • 보통 커넥션은 메시지를 다 보낸 다음 끊지만, 에러가 있는 상황에선 끊길 수 있다.
    • HTTP 애플리케이션은 언제든지 지속 커넥션을 임의로 끊을 수 있다.
  • Content-Length와 Truncation
    • 각 HTTP 응답은 본문의 정확한 크기 값을 가지는 Content-Length 헤더를 가지고 있어야 한다.
    • 커넥션이 끊어졌다는 HTTP 응답을 받고, 실제 전달된 엔터티 길이와 Content-Length가 일치하지 않거나 존재하지 않으면, 수신자는 데이터의 정확한 길이를 서버에게 물어봐야 한다.
  • 우아한 커넥션 끊기
    • 전체 끊기와 절반 끊기
      • 애플리케이션은 TCP 입력 채널과 출력 채널 중 한 개만 끊거나 둘 다 끊을 수 있다.
      • close() 호출 시 모두 끊고, shutdown() 호출 시 개별적으로 끊는다.
    • TCP 끊기와 리셋 에러
      • 커넥션의 출력채널(서버 → 클라이언트로 가는 채널)을 끊는 것이 가장 안전하다.
      • 입력 채널을 끊은 상태에서 클라이언트가 서버로 요청을 보내면 서버의 OS는 ‘connection reset by peer’라는 메시지를 클라이언트로 전송한다.
      • ‘서버가 이미 연결을 끊었는데 클라이언트는 그걸 모르고 요청을 보냈구나’라고 이해하면 될 것 같다.
      • 주의할 점은 파이프라인을 사용할 때 10개의 요청이 정상 처리되어 버퍼에 담겨있고 11번째 요청을 보낼 때 서버에서 입력 채널을 끊어 RST 패킷이 반환되면 정상 처리된 10개의 응답 데이터 조차 모두 지워지게 된다.
  • 우아하게 커넥션 끊기
    • 자신의 출력 채널을 먼저 끊고, 반대쪽이 출력 채널을 끊기를 기다리는 식으로 만들어진다.
    • 하지만 클라이언트는 어떤 서버가 절반 끊기를 구현했다는 사실을 명확히 알 수 없다.
    • 따라서 애플리케이션은 자신의 입력 채널에 대한 상태 검사를 주기적으로 하고, 타임아웃 시간을 설정할 수 있다.

@cloudwi
Copy link
Contributor

cloudwi commented Nov 22, 2023

https://www.notion.so/4-77785706ef18419091d65fcc9e7befbe?pvs=4

HTTP통신은, 지구상의 컴퓨터와 네트워크 장비에서 널리 쓰이고 있는 패킷 교환 네트워크 프로토콜들의 계층화된 집합인 TCP/IP를 통해 이루어진다.

즉 TCP 알아야한다.

왜 → 특징 : 커넥션이 맺어지면 클라이언트와 서버 컴퓨터 간에 주고받는 메시지들은 손실 혹은 손상되거나 순서가 바뀌지 않고 안전하게 전달된다.

Untitled

Untitled

TCP 커넥션

세그먼트

세그먼트

TCP 커넥션은 네 가지 값으로 식별한다.

발신지 IP 주소, 발신지 포트, 수신지 IP 주소, 수신지 포트

Untitled

네트워크 비용이 굉장히 많이 발생한다.

실제로 작업 시간은 짧다.

msa를 고려해보아야 하는 점 중 하나일 것이다.

Untitled

네이글 알고리즘은 좋은 것인가 ?

병렬 커넥션

앞서 언급했듯이 브라우저는 HTML 페이지에 이어 첫 번째 첨부된 객체, 두 번째 첨부된 객체를 하나씩 내려받는 식으로 웹페이지를 보여줄 수 있다. 하지만 이 방식은 너무 느리다.

병렬 커넥션이 일발전으로 더 빠르기는 하지만, 항상 그렇지는 않다. 클라이언트의 네트워크 대역폭이 좁을 때는 대부분 시간을 데이터를 전송하는 데만 쓸 것이다.

또한 다수의 커넥션을 메모리를 많이 소모하는 자체적인 성능 문제를 발생시킨다.

결과적으로 사용자는 빠르게 느낄 것이다.

우리가 화면의 이미지를 비동기 형식으로 내려 받는 것과 유사하다고 본다.

지속 커넥션

처리가 완료된 후에도 계속 연결된 상태로 있는 TCP 커넥션을 지속 커넥션이라고 부른다.

해당 서버에 이미 맺어져 있는 지속 커넥션을 재사용함으로써, 커넥션을 맺기 위한 준비작업에 따르는 시간을 절약할 수 있다. 게다가 이미 맺어져 있는 커넥션은 TCP의 느린 시작으로 인한 지연을 피함으러써 더 빠르게 데이터를 전송할 수 있다.

Keep-Alive 동작

응답에 Connection: Keep-Alive 헤더가 없으면, 클라이언트는 서버가 Keep-Alive를 지원하지 않으며, 응답 메시지가 전송되고 나면 서버 커넥션을 끊을 것이라 추정한다.

Keep-Alive 옵션

Keep-Alive 헤더는 커넥션을 유지하기를 바라는 요청일 뿐이다.

언제든지 현재의 keep-alive 커넥션을 끊을 수 있으며 keep-alive 커넥션에서 처리되는 트랜잭션의 수를 제한할 수 있다.

파이프라인 커넥션

상황 : 첫 번쩨 요청이 네트워크를 통해 지구 반대편에 있는 서버로 전달되면, 거기에 이어 두 번째와 세 번째 요청이 전달될 수 있다. 이는 대기 시간이 긴 네트워크 상황에서 네트워크상의 왕복으로 인한 시간을 줄여서 성능을 높여준다.

POST 요청같이 반복해서 보낼 경우 문제가 생기는 요청은 파이프라인을 통해 보내면 안 된다.

다중 커넥션

@KarmaPol
Copy link
Member

TCP 커넥션

HTTP 통신은 TCP/IP 프로토콜을 통해 이루어진다

  • 이때 메시지들은 손실, 손상되거나 순서가 바뀌지 않는다
  • 메시지는 세그먼트 단위로 나뉘어 IP 패킷에 담겨 전달된다
    • IP 패킷 구성 - IP 패킷 헤더(IP주소), TCP 세그먼트 헤더(포트번호), TCP 데이터 조각
  • 커넥션은 (발신지 IP, 발신지 포트, 수신자 IP, 수신자 포트)로 식별 -> 유일한 값

TCP 소켓 프로그래밍

유닉스 및 대부분의 운영체제에서 사용 가능

  • 소켓 API
    s = socket(), bind(s, IP:port), close(s)...
  • 소켓 API로 TCP 종단 데이터 구조를 생성해 데이터 스트림을 읽고 쓸 수 있다
    -> 이때 핸드셰이킹, TCP 스트림, IP 패킷 분할 등 세부사항은 숨긴다

TCP 성능 고려

  • HTTP 트랜잭션 성능은 TCP 성능에 영향을 받는다

HTTP 트랜잭션 지연

TCP 지연에 비해 트랜잭션 처리 시간 자체는 매우 짧음

지연원인
  • DNS 검색 시간
  • TCP 연결 시간
  • 클라이언트 -> 서버 메시지 전송 시간
  • 서버 -> 클라이언트 메시지 전송 시간

TCP 관련 지연

TCP 커넥션 핸드셰이크 지연

커넥션 생성시

  1. 클라이언트 -> 서버 SYN
  2. 서버 -> 클라이언트 SYN + ACK
  3. 클라이언트 -> 서버 ACK + 메시지
    이러한 과정은 정작 HTTP 메시지에 비해 큰 경우가 많다 -> 커넥션 재활용

확인 응답 지연

수신자가 TCP 세그먼트를 온전히 받으면 송신자에게 확인 응답 패킷 반환

  • 확인 응답 지연 알고리즘
    TCP 확인 응답 메시지를 데이터 패킷에 '편승'
    일정 시간 동안 대기하면서 편승할 패킷 찾음
    -> HTTP 특성 상 기회가 많지 않음 -> 오히려 성능 저하

TCP slow start

TCP는 급작스러운 부하를 막고자 연결을 맺고 점차 속도 제한을 높여 나간다

  • opening the congestion window
    1개를 보내고 ACK를 받으면 2개, 2개를 보내고 ACK를 받으면 4개..

네이글 알고리즘

네트워크 효율을 위해 많은 양의 TCP 데이터를 한 개의 덩어리로 합친다

  • 문제점
    1. 작은 데이터의 경우, 추가적인 데이터를 무작정 기다리게 됨
    2. 다른 모든 패킷이 확인 응답을 받을때 최대 크기보다 작은 패킷 전송을 허용하는데,
      확인 응답 지연 알고리즘은 확인 응답을 100~ 200밀리초 지연시킨다

TIME_WAIT 누적과 포트 고갈

TCP 연결을 끊으면 해당 커넥션 정보를 control block에 기록
<- 같은 IP주소와 포트를 갖는 커넥션을 2MSL(약 2분) 동안 생기는 것을 방지

이때 성능 시험과 같이 IP 주소를 제한할 경우, 연결의 조합이 제한된다
-> TIME_WAIT가 누적되어 포트를 바로 재활용하는 것이 어려워진다

HTTP 커넥션 관리

Connection 헤더

  • HTTP 헤더 필드는 해당 커넥션에서만 사용하고 삭제
  • close 값은, 작업 종료 시 커넥션도 종료되어야함을 의미

순차적인 트랜잭션 처리에 의한 지연

커넥션 맺고, 리소스 요청-응답 과정을 순차적으로 반복
->모든 객체를 내려받기 전까지 텅 빈 화면만 출력
=> 병렬, 지속, 파이프라인, 다중 커넥션으로 해결 가능

병렬 커넥션

여러 개의 커넥션을 한번에 맺고 동시에 다운

  • 일반적으로 빠르지만 네트워크 대역폭 자체가 좁으면 성능 상 장점이 사라지고,
    커넥션 갯수가 너무 많으면 성능 과부하 가능
  • 항상 더 빠르게 로드하지 않음에도 화면 상으로 더 빠르게 느껴짐

지속 커넥션

앞으로도 있을 HTTP 요청에 TCP 커넥션을 재활용 -> TCP 커넥션 지연 및 slow start 회피

  • 병렬 커넥션과 함께 사용하는 것이 효과적

Keep-Alive

HTTP/1.0의 지속 커넥션 타입, 1.1버전에서 제거되었음에도 아직 많이 사용
헤더에 Connection: Keep-Alive 포함
Keep-Alive: max=5, timeout=120 옵션 파라미터 설정 가능

  • Dumb Proxy
    프락시는 keep-alive를 이해하지 못하고 그대로 서버로 보낸다
    -> 서버는 프락시가 지속 커넥션을 맺었다고 이해
    -> 정작 프락시는 커넥션이 끊어질 때까지 대기
    -> 클라이언트에서 다시 요청을 보내면 프락시는 해당 요청을 무시하고 대기 => 장애 발생
  • Proxy Connection
    영리한 프락시를 위한 확장헤더
    클라이언트와 지속 커넥션을 하고, 서버에는 Connection 헤더만 전달한다
    이때 영리한 프락시는 Connection 헤더는 무시한다
    -> 하지만, 프락시를 여러개 사용하면 멍청한 프락시가 껴있을 수 있다.. => 같은 문제 발생

HTTP/1.1 지속 커넥션

keep-alive를 지원하지 않는다
Connection: close 헤더가 없으면 응답 후에도 유지하는 것으로 간주

파이프라인 커넥션

여러 개의 요청을 큐에 쌓고, 응답이 도착하기 전에 다음 요청 송신

  • 지속 커넥션을 확인하기전에 파이프라인 X
  • HTTP 응답은 요청 순서에 맞게 와야한다
  • 중간에 커넥션이 끊어지더라도 다시 요청을 보낼 준비가 되어야한다
  • 비멱등 요청을 파이프라인으로 보내면 안된다

커넥션 끊기

마음대로 끊기

서버, 클라이언트, 프록시에서 마음대로 끊을 수 있음
-> 클라이언트가 요청을 보내는 중이었다면 문제 발생

Content-Length와 Truncation

커넥션이 끊어졌을 때, 실제 전달된 엔티티 길이와 Content-Length가 일치하지 않으면 서버에 확인해야한다
캐시 프락시의 경우, 캐시하거나 Content-Length를 정정하지 말고 메시지를 그대로 전달해야한다

커넥션 끊기의 허용, 재시도, 멱등성

커넥션이 예상치 못하게 끊어졌을때, 비멱동성 메서드를 보내면 알 수 없는 결과를 초래한다
-> 이전 요청에 대한 응답을 받을 때까지 기다리고, 요청을 다시 보내길 원하는 대화상자를 보여줘야한다

우아한 커넥션 끊기

  • TCP 커넥션은 입, 출력 채널을 따로 끊을 수 있다
  • 예상치 못한 결과를 방지하기 위해 출력 채널을 끊는게 안전하다
    -> 입력 채널을 먼저 끊으면, 끊긴 채널에 도착한 데이터에 의해 OS 에러 발생
    => 자신의 출력 채널을 먼저 끊고, 다른 쪽 출력 채널이 끊기는 것을 기다리는 것이 가장 안전
    -> 하지만, 상대방이 절반 끊기를 하는지 보장이 없으므로 내 입력 채널 상태 검사를 하다가 타임아웃 후 끊기

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

7 participants