서버에는 다수의 사용자가 송신한 다수의 패킷이 흐를 것이다.
서버에 액세스가 증가할 경우 서버로 통하는 회선을 빠르게 하는 방법이 효과적이지만 이 방법만으로는 부족한 경우가 있다.
일단 모든 하드웨어는 성능에 한계가 존재하며, 액세스 회선을 빠르게 했다 하더라도 고속화한 회선에서 흘러오는 대량의 패킷을 웹 서버에서 처리 할 능력이 없을 수도 있기 때문이다.
특히 CGI 등의 애플리케이션에서 페이지의 데이터를 동적으로 만드는 경우 동적인 데이터를 위해 서버 머신의 프로세스가 사용되므로 이런 문제가 발생할 확률이 더 높아진다.
이런 문제를 해결하기 위한 가장 간단한 방법은 웹 서버 머신을 고성능 기종으로 교체하는 것이다.
하지만 위에서 말했듯 모든 하드웨어에는 성능적 한계가 존재하므로 아무리 고성능 기종을 사용하더라도 다수의 사용자가 집중적으로 액세스한다면 웹 서버 머신 1대로는 패킷을 모두 처리하지 못할 것이다.
이럴 경우 1개가 아닌 복수의 서버를 사용하여 패킷의 처리를 분담함으로써 서버 한 대 당 처리하는 패킷 양을 줄이는 것이 효과적이다.
그리고 이러한 처리 방법을 "분산 처리"라고 한다.
가장 간단한 분산 처리 방법은 단순히 여러 대의 웹 서버를 설치함으로써 웹 서버 1개가 담당하는 패킷이나 사용자 수를 줄이는 방법이다.
이 방법을 선택할 경우 클라이언트가 보내는 리퀘스트를 설치된 여러 웹 서버에 분배하는 구조가 필요하다.
리퀘스트를 분배하는 가장 간단한 방법은 DNS 서버에서 분배하는 구조이다.
이전에 배웠지만 웹 서버에 액세스 하기 위해선 DNS 서버를 통해 IP 주소를 조사하는데 DNS 서버에 같은 도메인명으로 여러 웹 서버 IP 주소를 등록해 놓으면 DNS 서버는 조회 요청이 들어올 때마다 차례대로 IP 주소를 돌려줄 것이다.
이 때 등록한 1주기를 순환하는 방식으로 IP 주소를 돌려주는 방법이 "라운드 로빈(RR; Round Robin)" 방식이다.
"www.sample.com"이라는 도메인에 접근하고 싶다고 가정하자.
이 때 DNS 서버에 "www.sample.com"이라는 도메인 명에 대응하는 IP 주소로 "1.2.3.4", "1.2.3.5", "1.2.3.6" 을 등록시키는 것이다.
최초로 "www.sample.com"에 접근하는 유저에게는 "1.2.3.4"를, 그 다음 유저에게는 "1.2.3.5"를, 그리고 세 번째 접근하는 유저에게는 "1.2.3.6"의 IP 주소를 반환하는 것이다.
이후 "www.sample.com"에 접근하는 4번째 유저에게는 다시 "1.2.3.4"를 반화함으로써 1주기를 순환하여 IP 주소를 반환하는 것이다.
이 방법에는 결점이 존재하는데, 바로 웹 서버의 고장에 대응할 수 없다는 점이다. 조금 더 자세히 말해보자.
웹 서버가 많으면 요청을 분배하여 처리할 수 있다는 장점을 가지지만, 그만큼 유지보수 해야 하는 웹 서버 머신 또한 많아진다. 그리고 이런 상황에서는 웹 서버 중 고장 나는 머신도 있을 것이다.
DNS 서버는 반환하는 IP 주소를 가진 웹 서버가 정상적으로 동작하는지 확인하지 않으므로 웹 서버가 정지하거나 고장나 있다 하더라도 해당 웹 서버의 IP 주소를 반환할 것이다.
단지 최근 많은 브라우저는 DNS 서버에서 받은 IP 주소로 엑세스에 실패했다면 다음 IP 주소를 시도하는 기능을 많이 가지고 있어 이런 결점이 많이 줄어들었다.
라운드 로빈을 통해 차례대로 웹 서버를 분배하면 복수의 페이지에 걸쳐 대화하는 상황에 대응할 수 없다는 문제도 존재한다.
CGI 등의 애플리케이션에서 페이지를 만드는 경우 복수의 페이지에 걸쳐 대화를 수행하는데, 웹 서버가 변하면 대화가 도중에 끊길 수 있다.
예를 들어 회원가입을 수행하는데 개인 정보를 입력한 뒤 다음 창에서 아이디와 패스워드를 입력했다고 가정하자.
이 경우 개인 정보가 "1.2.3.4", 아이디와 패스워드가 "1.2.3.5" IP 주소를 가지는 웹 서버에 저장되는 경우가 충분히 발생할 수 있다.
이 경우 "1.2.3.4"와 "1.2.3.5" 웹 서버 사이에 통신이 가능한 상황이 아니라면 서로의 서버에 저장되어 있는 값을 확인하지 못하므로 대화가 끊길 것인데 이 경우 올바르게 회원가입 로직이 작동하지 않을 것이다.
라운드 로빈 방식의 결점을 피하기 위하여 "부하 분산 장치" 혹은 "로드 밸런서"라고 부르느 기기가 고안되었다.
로드 밸런서를 사용할 경우 웹 서버 대신 로드 밸런서의 IP 주소를 DNS 서버에 등록한다.
이렇게 되면 도메인명에 대응되는 IP 주소는 사실 로드 밸런서의 IP 주소이기 때문에 모든 유저가 DNS 서버를 통해 IP 주소를 조회한 뒤 리퀘스트를 보내면 모든 리퀘스트들은 로드 밸런서에 도착하게 될 것이다.
리퀘스트가 로드 밸랜서에 도착했다면 가장 중요한 것은 로드밸런서와 연결된 웹 서버 중 어느 웹 서버에 리퀘스트를 전송해야 할지 판단하는 것이다.
판단 근거는 여러 가지 존재하지만 대화가 복수 페이지에 걸쳐있는지에 따라 판단 기준이 전혀 다르다.
먼저 복수 페이지에 걸쳐 있지 않은 단순한 액세스 상황이다.
이 경우 웹 서버의 부하 상태가 판단 근거가 될 것이다.
로드 밸런서는 웹 서버와 정기적으로 정보를 교환하여 CPU나 메모리의 사용률 등을 수집하고 이를 바탕으로 어느 웹 서버의 부하가 낮은지 판단할 수 있으며, 시험 패킷을 웹 서버에 보내 응답 시간을 통해 부하를 판단할 수도 있다.
단지 웹 서버의 부하 확인 과정을 조정하는 것이 꽤 어렵다.
웹 서버의 부하는 단시간에 갑자기 증가하거나 감소하므로 꼼꼼히 웹 서버의 상황을 조사해야 한다. 그렇다고 너무 자세한 상황을 조사하려 하면 부하를 조사하는 동작 자체가 웹 서버의 부하가 되버릴 수도 있다.
이런 문제를 피하기 위해 웹 서버의 부하를 조사하지 않고 로드 밸런서 측에 미리 웹 서버의 능력을 설정한 뒤 비율에 따라 리퀘스트를 분배하는 방법도 존재한다.
대화가 복수 페이지에 걸쳐 있는 액세스 상황일 경우 웹 서버의 부하 상태와 관계 없이 이전 리퀘스트를 처리한 웹 서버에 전송되어야 한다.
따라서 이 경우 이전에 리퀘스트를 처리했던 웹 서버가 무엇인지가 판단 근거가 될 것이다.
이를 위해선 일단 대화가 복수 페이지에 걸쳐있는지 먼저 판단되어야 한다.
TCP 연결의 경우 TCP 접속 동작을 수행한 뒤 응답 메시지를 반송받는 순간 연결을 끊는다. 이후 다시 웹 서버에 액세스할 때는 TCP 접속 동작부터 다시 시작한다.
웹 서버 측에선 리퀘스트마다 새로운 연결이 수행되는 것이므로 HTTP의 모든 대화는 독립된 것 처럼 보인다.
즉, 웹 서버는 이번 리퀘스트가 이전 리퀘스트와 연결된 요청인지 아니면 완전히 독립된 요청인지 판단할 수 없는 것이다.
이처럼 HTTP 프로토콜에서 요청마다 연결을 생성하고 바로 끊는 구조는 의도적으로 만들어진 구조이다.
만약 전후 관계 판단을 위해 연결 상태를 유지한다면 웹 서버측에서는 커넥션 및 이전 요청에 대한 응답 데이터를 유지해야 한다. 이는 웹 서버의 부담을 높이게 된다.
또한 웹 서버는 CGI 애플리케이션 등을 사용한 동적 페이지보다는 정적인 문서 데이터를 취급하는 것에 중점을 둔다.
정적인 문서 데이터는 전후 관계를 판단하지 않아도 되므로 굳이 연결을 유지할 필요가 없다.
조금 창의력이 있고 헤더에 대해 잘 공부한 사람이라면 리퀘스트의 송신처 IP 주소를 통해 전후 관계를 파악하면 되지 않을까 생각할 수도 있다.
만약 패킷의 송신처 IP 주소가 같다면 1개의 웹 서버에서만 리퀘스트를 처리하게 하는 것이다.
하지만 이는 불가능한데, 다음 섹션에서 설명하는 "프록시" 구조 때문이다.
프록시에 대해 간단히 말하자면 클라이언트와 웹 서버 사이에 설치하여 액세스 동작을 중개하는 구조이다.
프록시는 클라이언트가 송신한 패킷을 중계하는 역할을 맡기 때문에 리퀘스트의 송신처 IP 주소가 프록시의 IP 주소로 설정된다.
이렇게 되면 특정 프록시를 통해 중계된 패킷은 동일한 송신처 IP 주소를 가질 것이므로 실제 리퀘스트를 보낸 클라이언트가 누구인지 모르게 된다.
비슷한 이유로 주소 변환을 이용하는 경우도 송신처 IP 주소가 주소 변환 장치의 IP 주소로 변환되므로 클라이언트 판별이 어렵다.
이런 상황에서 전후 관계를 판단하기 위해 여러 방법이 고안되었다.
사용자가 입력한 데이터를 웹 서버에 보낼 때 그 안에 전후 관련을 나타내는 정보를 부가하거나 HTTP 사양을 확장하여 HTTP 헤더 필드에 전후 관계를 판단하기 위한 제어 정보를 저장하는 방법이 있다.
이때 전후 관계를 파악하기 위하여 HTTP 헤더 필드에 부가하는 정보를 흔히 "쿠키(cookie)"라고 부른다.
로드 밸런서는 부가된 정보를 조사하여 전후 관계가 존재하는 동작일 경우 이전 리퀘스트를 처리한 웹 서버에, 전후 관계가 없다면 부하가 가장 적은 웹서버에 전송하도록 동작하는 것이다.