[ HTTP 완벽 가이드 ] 4장 정리 - 커넥션 관리 (2)

현주·2023년 11월 14일

HTTP 완벽 가이드

목록 보기
5/5

Http 커넥션의 성능을 향상시키는 방법

1. 병렬(parallel) 커넥션

  • 객체를 내려받을 때 각각의 커넥션을 만들어 병렬로 거의 동시에 처리하는 것

병렬 커넥션이 일반적으로 빠름

But, 복잡한 웹 페이지에서는 수많은 객체와 함께 사용자의 요청도 함께 처리해야하기 때문에 너무 많은 커넥션을 서버가 떠안게 되어 오히려 서버의 성능을 떨어뜨림

Ex. 백명의 가상 사용자가 각각 100개의 커넥션을 맺고있다면, 서버는 총 10,000개의 커넥션을 떠안게 됨

병렬 커넥션이 항상 더 빠른 것은 아니지만,
사용자 입장에서는 /
병렬 커넥션을 사용하게 되면 화면에서 여러가지 작업이 일어나는 것을 한 눈에 확인할 수 있기 때문에 더 빠르다고 느낄 수 있음

단점

  • 각 트랜잭션마다 새로운 커넥션을 맺고 있기 때문에 시간 / 대역폭 소요
  • 각 새로운 커넥션은 TCP 느린 시작으로 성능이 떨어짐
  • 실제 연결 가능한 병렬 커넥션의 수는 제한이 있음

2. 지속(persistent) 커넥션

  • 처리가 완료된 후에도 계속 연결된 상태로 있는 TCP 커넥션

클라이언트나 서버가 커네견을 끊기 전까지는 트랜잭션 간에도 커넥션 유지

장점

해당 서버에 이미 맺어져있는 지속 커넥션을 사용함으로써

  • 커넥션 맺기 위한 준비 작업 시간 절약 가능
  • 이미 커넥션이 맺어져 있기 때문에 TCP 느린 시작으로 인한 지연 피함 ( 튜닝된 커넥션 유지 )
  • 커넥션의 수를 줄여 부하 가능성 줄임

But, 지속 커넥션을 잘못 관리할 경우, 계속 연결된 상태로 있는 수많은 커넥션들이 쌓임
--> 로컬의 리소스, 원격의 클라이언트와 서버의 리소스에 불필요한 소모 발생

지속커넥션은 병렬 커넥션과 함께 사용될 때 가장 효과적

종류

  1. HTTP/1.0+ 의 Keep-Alive 커넥션
  2. HTTP/1.1 의 지속 커넥션

dumb 프락시에서 1번을 사용할 때 발생하는 문제
프락시는 http의 connection 헤더를 단순히 확장 헤더로 취급하여 이해하지 못함
따라서 일단 클라이언트에게서 Connection: Keep Alive 헤더를 포함한 요청을 보내게 되면 그대로 서버에게 보냄
그럼 서버는 아 연결을 유지하고 싶어하는구나 생각해서 다시 그대로 헤더에 Connection: Keep Alive 포함해서 응답 보냄
여기서도 프락시는 이 말을 이해하지 못하고 클라이언트에게 보냄
여기까지 보면 클라이언트와 서버는 둘 다 커넥션을 유지할것임을 인지하고 있으므로 서버가 커넥션을 끊지 않음
But, 프락시는 몰라서 서버가 이 커넥션을 끊기를 기다림 멍청한 것
따라서 클라이언트가 커넥션이 유지되고 있는 해당 프락시에게 다른 요청을 또 보내면,
프락시는 왜 똑같은 커넥션으로 요청이 또 오지? 생각해서 그걸 무시함
그러면 브라우저는 해당 요청에 대한 응답을 계속 기다리면서 로드 중이라는 표시만 뜨게 함
이러다가 자신이나 서버가 타임아웃으로 커넥션이 끊길 때까지 기다리게 됨
--> 이런 문제를 발생시키지 않으려면, 프락시가 Connection 헤더와 거기에 명시된 헤더들은 삭제하고 전달해야함

-> 그런데 여기서 궁금증 ! (110P)
어차피 그냥 전달해도 프락시가 이해를 못해서 연결 유지를 이해하지 못한다고 했는데,
지워서 전달한다고 해도 어차피 커넥션은 유지되어있고, 프락시는 이해 못해서 또 요청 무시하는 거 아닌가?
아 그리고 해당 헤더를 지워서 서버에게 전달하면 커넥션을 유지하겠다는 요청을 어떻게 알아듣지?

전달받은 서버가 자신과 프락시 간의 커넥션에 대한 것으로 오해하면서 문제가 생기는 것이라고 했는데(111p)
이게 뭔말이지 클라이언트-서버 간으로 인식하는 게 아닌 건가

클라이언트가 예상치 못하는 시점에 커넥션이 끊어졌을 때를 위해 준비해야한다느 말을 몇번을 말하는 거야
--> 요청들을 큐에 쌓아 놔서 중간에 커넥션이 끊겨도 거기부터 다시 보낼 수 있도록 대비하는 거야


3. 파이프라인(pipelined) 커넥션

https://jins-dev.tistory.com/entry/HTTP11-%EC%9D%98-HTTP-Pipelining-%EA%B3%BC-Persistent-Connection-%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC

  • 지속 커넥션을 통해 요청을 파이프라이닝

클라이언트가 요청들을 보내면 그에 대한 응답이 오기 전까지는 큐에 쌓여있음
( 중간에 커넥션이 끊겨 요청이 유실되는 것을 방지하기 위해 )

--> 대기시간이 긴 네트워크 상황에서 네트워크 상의 요청-응답 왕복으로 인한 시간을 줄여 성능을 높임

병렬 커넥션

  • 각 요청-응답 당 하나의 커넥션으로 동시에 실행

지속 커넥션

  • 하나의 커넥션을 유지하면서, 요청-응답을 반복

파이프라인 커넥션

  • 하나의 커넥션을 유지하면서, 각 요청에 대한 응답을 기다리지 않고 연속적으로 요청

제약 사항

  • 클라이언트 - 지속 커넥션이 맞는지 확인 전까지는 파이프라인을 이어서는 안됨
    ( 요청을 응답이 오기 전에 막 보내면 안됨 )

  • 응답들은 요청의 순서들과 같게 와야 함
    ( 순서에 맞게 정렬시킬 방법 X )

  • 클라이언트 - 커넥션이 언제 끊어지더라도 응답을 못받은 요청을 다시 보낼 준비 되어있어야 함

  • 비멱등성을 가진 요청은 파이프라인을 통해 보내면 안됨
    ( 클라이언트의 경우, 커넥션이 끊겨 응답을 못받은 요청들이 서버에서 얼만큼 처리되고 있었는지 알 수 없음 - 멱등성을 가진 요청들은 상관이 없는데 비멱등성을 가진 요청은 결과가 변할 수 있기 때문에 파이프라인 커넥션으로 보내지 말아야함 )

멱등(Idempotent)

  • 연산을 여러번 수행하더라도 결과가 변하지 않는 특성
    멱등성을 가진 메서드 - GET,HEAD,PUT,DELETE,TRACE,OPTIONS

비멱등

  • 연산이 한 번 일어날 때마다 결과가 변하는 특성
    비멱등성을 가진 메서드 - POST
    Ex. 대부분의 브라우저는 캐시된 POST 요청 페이지를 다시 로드하려고 할 때, 요청을 다시 보내길 원하는지 묻는 대화상자를 나타냄
    Ex. 물건 주문 페이지에서 다시 로드하면, 해당 주문 요청을 다시 보내시겠습니까? 이런거

각 HTtp 응답은 본문의 정확한 크기와 값을 가지는 Content-Length 헤더를 가지고 있어야 함

클라이언트나 프락시가 커넥션이 끊어졌다는 Http 응답 받은 후에, Content-Length가 실제 길이와 같지 않거나 존재하지 않으면 서버한테 물어봐야함

수신자가 캐시 프락시일 경우에는, 잠재적인 에러가 복합적으로 발생하는 것을 최소화하기 위해 캐시하면 안됨

우아한 커넥션 끊기

TCP 커넥션은 양방향임
클라이언트 -> 서버로 요청하는 경우에는 출력 -> 입력의 큐
서버 -> 클라이언트로 응답하는 경우에는 출력 -> 입력의 큐

전체 끊기

  • close()를 호출하여 TCP 커넥션의 입력 채널 / 출력 채널을 모두 끊는 것

절반 끊기

  • shutdown()을 호출하여 입력 채널이나 출력 채널 중 하나를 개별적으로 끊는 것

But, 절반 끊기를 안전하게 하기 위해서는 출력 채널을 끊어야함
처음으로 지나가는 통로를 끊어야 반대 쪽에서도 아예 데이터 전송 자체가 안오기 때문에 커넥션이 끊어졌다는 것을 알 수 있음

입력 채널을 끊는 것은 위험
-> 클라이언트가 데이터를 더 보낼지 모르기 때문에 위험

이미 끊긴 입력 채널에 데이터를 전송하게 되면 서버의 운영체제는 TCP connection reset by peer 메세지를 클라이언트에게 보냄
( 심각한 에러로 취급 )
--> 버퍼에 저장된, 아직 읽히지 않은 데이터를 모두 삭제
( 파이프라인 커넥션에서 더 악화 )
( --> 응답 데이터가 기기에 잘 도착하였더라도, 아직 읽히지 않은 버퍼에 있는 응답 데이터들은 사라지게 됨

119p에 이미 응답은 운영 체제의 버퍼에 있지만 아직 애플리케이션이 읽지는 않았다고 가정하자는데
이게 무슨 말이지?

--> 우하하게 커넥션 끊기란
자신의 출력 채널을 먼저 끊고 다른 쪽에 있는 기기의 출력 채널이 끊기는 것을 기다리는 것.
절반 끊기를 하고 난 후에도 데이터나 스트림의 끝을 식별하기 위해 입력 채널에 대해 주기적으로 상태 검사를 해주어야함


4. 다중(multiplexed) 커넥션

  • 요청과 응답들에 대한 중재(실험적인 기술)

0개의 댓글