서버 한 대로는 감당할 수 없을 때
트래픽이 늘면 서버 한 대의 처리 한계에 부딪힙니다. CPU와 메모리, 동시 연결 수에는 물리적 상한이 있어, 그 선을 넘으면 응답이 느려지다 결국 멈춥니다. 로드 밸런서는 들어오는 요청을 여러 대의 서버로 나눠 보내, 어느 한 대가 과부하에 빠지지 않도록 조정하는 장치입니다.
효과는 두 방향으로 나타납니다. 하나는 가용성입니다. 한 서버가 멈춰도 로드 밸런서가 나머지 살아 있는 서버로 요청을 돌려 서비스가 끊기지 않습니다. 다른 하나는 확장성입니다. 트래픽이 늘면 서버를 더 붙이기만 하면 되고, 줄면 떼어내면 됩니다. 한 대를 무한정 키우는 대신 여러 대로 나눠 늘리는 이 방식 덕분에, 현대의 대규모 서비스가 수많은 사용자를 동시에 감당할 수 있습니다.
어느 계층에서 분산하느냐
로드 밸런서는 트래픽을 어느 깊이까지 들여다보는가에 따라 크게 두 부류로 나뉩니다. 얕게 보면 빠르고, 깊게 보면 똑똑하지만 무겁습니다.
L4 로드 밸런싱
전송 계층에서 동작하며 IP 주소와 포트 정보만 보고 분산합니다. 패킷 안의 내용을 해석하지 않으니 처리가 빠르고 부담이 적습니다. 단순히 연결을 받아 뒤로 넘기는 데 집중하므로, 대량의 트래픽을 낮은 지연으로 처리해야 할 때 적합합니다. 다만 요청의 성격을 모르기 때문에 내용에 따라 다르게 보내는 세밀한 라우팅은 하지 못합니다.
L7 로드 밸런싱
애플리케이션 계층에서 동작해 URL 경로, 헤더, 쿠키까지 읽고 판단합니다. 예를 들어 주소가 /api로 시작하는 요청은 API 서버군으로, 이미지 요청은 정적 파일 서버군으로 보내는 식의 콘텐츠 기반 라우팅이 가능합니다. 같은 사용자의 요청을 늘 같은 서버로 보내는 세션 유지도 이 계층에서 처리합니다. 더 똑똑한 분산이 가능한 대신, 내용을 해석하는 만큼 처리 비용은 L4보다 큽니다.
요청을 나누는 알고리즘
요청을 어떤 기준으로 나눌지도 여러 전략이 있고, 서비스 특성에 맞게 고릅니다. 잘못 고르면 분산을 하고도 한쪽으로 부하가 쏠립니다.
라운드 로빈
요청을 서버에 순서대로 돌아가며 배분하는 가장 단순한 방식입니다. 서버 성능이 균일하고 요청 처리 시간이 비슷할 때 무난하게 동작합니다. 구현이 쉽고 예측 가능하다는 것이 장점입니다.
최소 연결
현재 연결 수가 가장 적은 서버로 보냅니다. 요청마다 처리 시간이 들쭉날쭉한 환경에서 유리한데, 오래 걸리는 요청을 처리 중인 서버에 새 요청이 계속 쌓이는 것을 막아주기 때문입니다. 실제 부하를 반영하므로 라운드 로빈보다 고르게 분산됩니다.
가중치 기반
서버마다 처리 능력이 다를 때 씁니다. 성능이 좋은 서버에 더 큰 가중치를 줘서 더 많은 요청을 받게 합니다. 사양이 섞인 서버들을 함께 운용할 때, 강한 서버를 놀리지 않고 약한 서버를 혹사하지 않는 균형을 맞출 수 있습니다.
해시 기반
요청의 특정 속성, 예를 들어 출발지 IP나 URL을 계산해 늘 같은 서버로 보내는 방식입니다. 같은 입력은 항상 같은 서버로 가므로, 캐시를 활용하거나 특정 사용자를 일관되게 처리해야 할 때 유용합니다. 서버가 추가되거나 빠지면 배정이 흔들리는 단점이 있어, 이를 완화하는 일관된 해싱 기법과 함께 쓰입니다.
헬스 체크와 페일오버
로드 밸런서의 진짜 가치는 단순한 분산보다 장애 대응에 있습니다. 로드 밸런서는 주기적으로 각 서버에 상태 점검 신호를 보냅니다. 응답이 정상이면 후보로 두고, 일정 횟수 이상 응답이 없으면 죽은 것으로 판단해 분산 대상에서 자동으로 뺍니다.
덕분에 한 서버가 갑자기 멈춰도 사용자는 그 사실을 모른 채 살아 있는 서버로 연결됩니다. 이후 그 서버가 복구돼 상태 점검을 다시 통과하면 자동으로 후보에 복귀합니다. 사람이 개입하지 않아도 장애를 우회하고 회복하는 이 흐름이 무중단 서비스의 핵심입니다. 한 경로가 막히면 다른 경로로 우회하는 발상은 메시 토폴로지의 자가 복구와 같은 맥락입니다.
세션 유지라는 까다로운 문제
분산에는 한 가지 함정이 있습니다. 로그인처럼 이전 요청의 상태를 기억해야 하는 서비스에서, 같은 사용자의 요청이 매번 다른 서버로 가면 문제가 생깁니다. A 서버에서 로그인했는데 다음 요청이 B 서버로 가면, B는 그 사용자를 모르니 다시 로그인을 요구하게 됩니다.
이를 풀기 위해 같은 사용자의 요청을 늘 같은 서버로 보내는 세션 고정을 씁니다. 사용자를 식별하는 쿠키나 IP를 기준으로 특정 서버에 묶어두는 방식입니다. 다만 이렇게 하면 그 서버가 죽었을 때 세션도 함께 날아갑니다. 그래서 근래에는 세션 정보를 서버 바깥의 공용 저장소에 두어, 어느 서버가 받든 같은 상태를 읽을 수 있게 만드는 방식을 선호합니다. 이러면 분산의 자유도와 장애 복원력을 동시에 얻습니다.
로드 밸런서 자체의 이중화
한 가지 역설이 있습니다. 여러 서버에 장애가 나도 버티려고 로드 밸런서를 뒀는데, 그 로드 밸런서 자체가 멈추면 어떻게 될까요. 모든 트래픽이 그곳을 거치므로, 로드 밸런서가 단일 장애점이 되어버립니다. 그래서 정작 로드 밸런서야말로 이중화가 필수입니다.
보통 로드 밸런서를 두 대 이상 두고, 하나가 멈추면 다른 하나가 즉시 역할을 넘겨받도록 구성합니다. 평소 둘이 함께 트래픽을 나눠 받다가 한쪽이 죽으면 남은 쪽이 전부 받아내는 방식도 쓰입니다. 분산의 관문 자체가 튼튼해야 그 뒤의 모든 분산이 의미를 가지므로, 이 부분을 소홀히 하면 공들인 구조가 한순간에 무너질 수 있습니다.
전 세계로 확장하기
한 데이터센터 안에서의 분산을 넘어, 지역마다 흩어진 서버 풀로 트래픽을 보내는 글로벌 분산도 있습니다. 사용자의 위치를 파악해 지리적으로 가장 가까운 데이터센터로 연결하면 응답 거리가 줄어 속도가 빨라지고, 한 지역 전체에 장애가 나도 다른 지역이 받아냅니다. 이 방식은 흔히 CDN과 결합해 구현됩니다. 대규모 분산 설계의 실제 구성은 nginx 공식 문서의 로드 밸런싱 가이드에서 확인할 수 있습니다.