kakasoo

[HTTP] 10. 커넥션 관리(2) 성능 저하의 요소 본문

프로그래밍/HTTP

[HTTP] 10. 커넥션 관리(2) 성능 저하의 요소

카카수(kakasoo) 2020. 10. 22. 13:56
반응형

보는 것이 용이하도록, 앞의 내용과 겹쳐서 썼습니다.

4.2 TCP의 성능에 대한 고려

HTTP의 성능은 TCP 바로 위 계층이라 TCP 성능에 영향을 받는다. TCP 커넥션을 이해하면 HTTP 커넥션 최적화 요소를 더 잘 알게 되고, 성능을 높일 수 있다.

4.2.1 HTTP 트랙잭션 지연

HTTP 트랙잭션 과정은 DNS 찾기, 연결, 요청, 처리, 응답, 종료의 단계를 거치는데, 이 중 처리의 시간은 요청 및 응답의 전송에 비하면 상당히 짧은 시간에 이루어진다.

따라서 서버가 너무 큰 데이터를 내려받거나 복잡한 동적 자원을 실행하지 않는 한, 대부분의 HTTP 지연은 TCP 네트워크 지연 때문에 발생함을 알 수 있다.

HTTP 트랜잭션을 지연시키는 원인은 여러 가지가 있다.

  1. 클라이언트는 URI에서 웹 서버의 IP와 포트 번호를 찾아야 하는데, 이 과정이 오래 걸릴 수 있다 → 책이 서술될 당시에는 수 십초가 소요될 수 있었으나 지금은 해결되었다.
  2. TCP 커넥션 요청과 응답 사이에서 커넥션 설정 시간이, HTTP 트랜잭션의 수에 따라 크게 증가한다 → 이 역시 현재는 해결되었다.
  3. 커넥션이 맺어지면 클라이언트는 HTTP 요청을 새로 생성된 TCP 파이프를 통해서 전송한다. 이 요청 메시지가 인터넷을 통해 전달되고 처리되는 데에 시간이 걸린다.
  4. 웹 서버가 응답하는 데에도 시간이 걸린다.

TCP 네트워크 지연은 하드웨어의 성능, 네트워크와 서버의 전송 속도, 요청과 응답 메시지의 크기, 클라이언트와 서버 간 거리에 따라 달라질 수 있다.

즉, 네트워크 개발자가 담당해서 처리해야 할 일이 일이 현재로서는 HTTP 커넥션의 요청과 응답 뿐이라고 할 수 있겠지만, 일단은 가능한 모든 요소에 대해서 다루도록 하겠다.

4.2.2 성능 관련 중요 요소

가장 일반적인 요소는 아래와 같다.

  1. TCP 커넥션의 핸드셰이크 설정
  2. 인터넷 혼잡을 제어하기 위한 TCP의 느린 시작(slow-start)
  3. 데이터를 한데 모아 한 번에 전송하기 위한 네이글(nagle) 알고리즘
  4. TCP의 편승(piggyback) 확인응답(acknowledgment)을 위한 지연 알고리즘
  5. TIME_WAIT 지연과 포트 고갈

고성능의 HTTP 소프트웨어를 개발하고자 한다면 이 내용을 모두 이해해야 하며, 그 정도 까지가 아니라면 건너뛰어도 좋다.

4.2.3 TCP 커넥션 핸드셰이크 지연

TCP 커넥션이 열리면 핸드셰이크를 통해 조건을 맞추는데, 커넥션이 작은 데이터의 단위의 전송을 위해 사용된다면 빈번하게 핸드셰이크가 일어나고, 이는 성능을 저하시킨다.

TCP 핸드셰이크 과정에 대해서 보자.

  1. 클라이언트는 TCP 패킷을 서버에게 보낸다. 이 패킷은 SYN이라는 특별한 플래그를 가지는데, 이 과정을 커넥션 생성 요청이라고 한다.
  2. 커넥션 요청이 받아들여지면 서버는 SYN과 ACK 플래그를 포함한 TCP 패킷을 돌려보낸다. (ACK는 SYN보다 1이 더 큰 값으로, 이 숫자 차이를 통해 서로에 대한 확인이 이루어진다.
  3. 클라이언트는 최종적으로, 서로 간에 통신이 잘 이루어지고 있음을 서버에게 알리기 위해, 한 번 더 신호를 보낸다.
    1. 오늘 날에는 이제, 패킷과 데이터를 동시에 보낼 수도 있게 되었다.

HTTP 프로그래머는 TCP 커넥션의 패킷을 보지 못한다. 하지만 HTTP 트랙잭션이 그리 크지 않은 데이터를 주고 받으면 이 때의 지연은 TCP에서의 지연임을 예상해볼 수 있다.

TCP의 ACK 패킷은 HTTP 요청 메시지 전체를 담을 만큼 큰 경우가 많고, 대부분의 HTTP 요청 메시지(304)는 하나의 IP 패킷에도 담길 수 있을 정도이기 때문에, HTTP 트랜잭션 시간의 50%는 TCP에서 쓰인다.

따라서 이런 TCP 구성으로 인한 지연을 제거하는 것이, HTTP 성능 개선의 관건일 것이다.

현재는 얼추 해결된 문제이다.

4.2.4 확인응답 지연

이름은 지연이지만 실제로는 필요한 기능이기도 하다. 다만 속도 면에서는 개선을 할 수도 있다는 의미에서 기재한다.

인터넷 라우터는 과부하가 걸리면 패킷을 파기한다. TCP는 자체적인 확인 체계를 만들었다.

각 TCP 세그먼트는 순번과 데이터 무결성 체크섬을 가진다. 각 세그먼트 수신자는, 세그먼트를 받으면 확인응답 패킷을 반환한다. 만일 반환이 없다면 패킷이 파기되었거나 오류가 있다고 판단해 재전송한다.

이 때 확인응답은 크기가 작기 때문에 같은 방향으로 보내야 할 데이터 패킷에, 확인 응답을 편승(piggyback)시킨다. (같이 태워 보낸다는 의미.)

하지만 막상 편승을 하려고 하더라도 같은 방향으로 보내는 패킷이 많지는 않을 것이기 때문에, 이 지연으로 인해 속도가 느려질 수 있다. 따라서 지연 관련 기능을 수정하거나 비활성화할 수 있다.

참고로 잘못 만들어진 알고리즘으로부터 TCP는 스스로를 보호하기 때문에, 개발자는 항상 자신이 고치고자 하는 바가 무엇인지 알고 고쳐야 한다.

4.2.5 TCP 느린 시작(Slow start)

TCP는 과부하를 방지 하기 위해서 커넥션이 생긴 직후에는 일부러 느린 속도로 시작하고, 이후 점진적으로 속도를 높여 나간다. 이것을 느린 시작이라고 한다.

TCP 느린 시작은 TCP가 한 번에 전송 가능한 패킷의 수를 제한하는 것이다. 패킷이 성공적으로 전달될 때 송신자는 2개의 패킷을 더 전송할 수 있는 권한을 얻는 식이다.

이렇게 한 번에 보낼 수 있는 패킷의 수를 응답마다 2개씩 확보해 나가는 방식으로 점점 빠르게 전송하기 시작하는 것이다.

이로 인해 새로 생성된 커넥션은, 미리 쓰던 커넥션보다 반드시 느릴 수 밖에 없기 때문에, HTTP에 이미 존재하는 커넥션을 재사용하는 방식으로 해결하곤 한다. 자세한 내용은 후술한다.

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

TCP는 아무리 작은 데이터(from 1바이트)라도 하더라도 전달할 수 있도록 데이터 스트림 인터페이스를 제공한다. 그러나 일반적으로 플래그와 헤더를 합쳐도 40바이트 가량이다.

그래서 적은 데이터를 여러 패킷으로 나눠서 보내게 된다면 네트워크 성능은 떨어진다.

네이글 알고리즘은 네트워크 효율을 위해서 패킷을 전송하기 전에 TCP 데이터를 한 개로 합치는 알고리즘이다. 네이글 알고리즘은 세그먼트가 최대 크기 (1500바이트)가 되지 않으면 전송을 멈춘다.

다른 모든 패킷이 확인 응답을 받았을 때는 최대 크기보다 작아도 전송을 허용하지만, 그게 아니라면 데이터를 버퍼에 저장해두다가 충분한 양의 데이터가 쌓일 때에만 전송하는 식이다.

이 알고리즘은 HTTP 성능에 대해 여러 문제를 발생시키는데,

  1. 크기가 작은 HTTP 메시지는 패킷을 채우지 못하기 때문에 계속해서 데이터를 기다리고 지연될 수 밖에 없다.
  2. 여기에 앞서 있던 확인 응답 지연과 동시에 사용될 경우, 데이터를 기다리면서도 확인응답은 지연되니 속도는 매우 느려지게 된다.

HTTP 애플리케이션은 성능을 향상시키기 위해 HTTP 스택에 TCP_NODELAY 파라미터를 설정하여 네이글을 비활성하기도 한다.

4.2.7 TIME_WAIT의 누적과 포트 고갈

TCP 커넥션의 종단에서 TCP 커넥션을 끊으면 해당 포트는 2분 동안 어떠한 애플리케이션도 배정되지 않고 대기 상태로 놓인다. 실 상황에서는 포트가 무척이나 많아서 아무 상관 없는 일이다.

다만 테스트 용으로 포트를 정해놓고 사용한다면 이 문제를 만나게 될 것이고, 심각한 오해를 낳을 수 있으니 조심해야 한다.

앞서 TCP 커넥션을 만들기 위해서는 발신자의 IP와 PORT, 수신자의 IP와 PORT, 총 4가지 요소가 필요하다고 했다. 여기서 클라이언트의 IP, 서버의 IP와 PORT는 고정이다.

즉 클라이언트의 포트만이 커넥션 속도의 기준이 될 것이다.

이 때 클라이언트의 포트가 6만 개고, 대기 시간이 120초라고 한다면, 초당 500개 이상을 쓰면 반드시 겹치는 커넥션이 나올 것임을 알 수 있다.

서버가 더 빨라져서 초당 500개 이상을 처리할 수 있지 않으면, 포트는 고갈될 것이다. 이 문제를 해결하기 위해 부하를 생성하는 장비를 사용하거나, 가상 IP 주소를 쓸 수도 있다.

포트 고갈 문제가 아니더라도 커넥션이 많아지면 전체적인 성능 저하가 발생할 수 있으니 조심해야 한다.

반응형