keep-alive의 문제점 : 멍청한 프록시
멍청한 프록시에서 keep-alive를 사용할 때 생기는 문제를 알아보자.
커넥션 헤더의 무조건적 전달
javascript
(a) 웹 클라이언트는 프록시에 Connection : Keep-Alive 헤더와 함께 메시지를 전송한다.
클라이언트는 커넥션을 유지하자는 요청에 대한 응답을 확인하기 위해 기다린다.
(b) 멍청한 프록시는 요청받은 HTTP의 Connection 헤더를 이해하지 못한다.
프록시는 Keep-Alive를 모르기 때문에 다음 서버에 메시지를 그대로 전달한다.
하지만 Connection 헤더는 홉별(hop-by-hop) 헤더이다.
여기서부터 문제가 시작된다.
(c) (b)에서 보이는 것처럼 전달된 HTTP 요청이 서버에 도착한다. 웹 서버가 프록시로부터 헤더를 받으면
프록시가 커넥션을 유지하기를 원하는 걸로 잘못 판단하게 된다. 서버는 프록시와 커넥션을 유지하는 것에 동의를 하고
Connection : Keep-Alive 헤더를 포함하여 응답한다. 하지만 프록시는 그 헤더를 이해하지 못한다.
(d) 멍청한 프록시는 서버로부터 받은 Connection : Keep-Alive 헤더를 포함하고 있는 응답 메시지를 클라이언트에게 전달.
클라이언트는 이 헤더를 통해 프록시가 커넥션을 유지하는 것에 동의했다고 생각한다.
하지만 Keep-Alive를 이해하지 못한 프록시는 그렇지 않다.
(e) 멍청한 프록시는 서버로 받은 모든 데이터를 클라이언트에게 전달 후 커넥션이 끊어지기를 기다린다.
하지만 서버는 프록시가 자신에게 커넥션을 유지하기를 요청한 것으로 알고 있기 때문에 커넥션을 끊지 않는다.
또한 클라이언트는 응답 메시지에 Keep-Alive가 있기 때문에 다음 요청을 보내기 시작할 때 커넥션이
유지되고 있는 프록시에 요청을 보낸다.
하지만 프록시는 같은 커넥션상에서 다른 요청이 오는 경우는 예상하지 못하기 때문에
그 요청은 프록시로부터 무시되고 브라우저는 응답 없이 대기를 하게 된다.
그래서 브라우저는 무한정 대기를 하다 타임아웃이 나서 커넥션이 끊기게 된다.
정리하면, 프록시가 keep-alive를 이해 못한 채 막 보낸 결과…
- 프록시는 이미 연결이 끊어진 줄 안다.
- 그치만 서버는 프록시와의 keep-alive가 계속 된줄 알고 하염없이 기다린다.
- 역시 클라이언트도 프록시와의 keep-alive가 계속 된줄 알고 하염없이 기다린다.
해결책 : Proxy-connection
멍청한 프록시가 무조건 전달하는 문제를 해결하기 위해 도입된 방법
javascript
브라우저에서 Connection 헤더 대신에 비표준인 Proxy-Connection 확장 헤더를 프록시에 전달한다.
멍청한 프록시라면,
- Proxy-Connection 헤더를 무조건 전달
- 그러나 웹 서버는 그것을 무시하기 때문에 문제가 되지 않는다.
똑똑한 프록시라면,
- Proxy-Connection 헤더를 Connection 헤더로 변경하여
- 지속 커넥션을 유지할 수 있게 된다.
하지만 이 해결책도 완벽한 것은 아니었으니…
javascript
위 방식은 클라이언트 <-> 서버 사이에 1개의 프록시만 있는 경우에만 동작한다.
만약 멍청한 프록시가 똑똑한 프록시 옆에 존재한다면 똑같은 문제가 발생한다.
- 똑똑한 프록시가 Proxy-Connection 을 Connection으로 바꾸고
- 그 다음 멍청한 프록시가 다시 이를 아무렇게나 보낸다...
또한 문제를 주로 발생시키는 프록시들은 방화벽, 캐시서버, 리버스 프록시 서버 가속기와 같이
네트워크 상에서 보이지 않는 경우가 많다.
그래서, 보이지 않는 웹 어플리케이션들이 지속 커넥션을 명확하게 구현하는 것이 중요.