[소프트웨어 개발자 면접] 시스템 디자인 - 로드 밸런서 (Load Balancer)
로드 밸런서 도입 후 sticky session 남용으로 오히려 부하가 쏠린 경험, HAProxy 단독 구성이 단일 장애점이 된 사례, 면접에서 L7을 이유 없이 선택했다가 지적받은 경험을 정리합니다.
서버를 한 대에서 여러 대로 늘리는 순간, 로드 밸런서가 필요하다는 것은 알았습니다. 그런데 막상 도입하고 나서 예상치 못한 문제들을 연달아 만났습니다. 로드 밸런서를 추가했더니 오히려 특정 서버에 부하가 몰렸고, 장애 대응 중에는 로드 밸런서 자체가 죽어서 모든 서버가 멀쩡한데도 서비스가 다운됐습니다. 이 글은 그 경험에서 정리한 내용입니다.
로드 밸런서는 유저 요청을 라운드 로빈, 랜덤, CPU·메모리 부하 기반 가중치 등 정해진 규칙에 따라 여러 서버에 분산합니다. 연결된 서버 전체의 상태를 지속적으로 추적하며, 응답하지 않거나 에러율이 높아진 서버에는 트래픽 전송을 자동으로 중단합니다.

확장성과 가용성을 확보하려면 시스템의 각 계층에 로드 밸런서를 배치해야 합니다.
- 유저와 웹 서버 사이
- 웹 서버와 내부 플랫폼 계층(애플리케이션 서버 혹은 캐시) 사이
- 내부 플랫폼 계층과 데이터베이스 사이
구현 방식은 크게 세 가지입니다.
Smart Clients
스마트 클라이언트는 백엔드 서버 풀을 직접 관리하며 로드 밸런싱을 수행합니다. 응답하지 않는 호스트를 감지해 요청을 보내지 않고, 복구된 호스트를 다시 풀에 추가하는 작업도 처리합니다.
시스템 규모가 작을 때는 이 방식이 구현과 관리가 단순해 보입니다. 제가 처음 부하 분산을 적용할 때도 스마트 클라이언트를 직접 개발하는 방식을 선택했습니다. 초기에는 잘 동작했지만, 서버 수가 늘어나고 장애 시나리오가 다양해지면서 클라이언트 코드가 점점 복잡해졌습니다. 결국 독립형 로드 밸런서 서버로 전환하지 않을 수 없었습니다.
Hardware Load Balancers
Citrix, NetScaler 같은 전용 하드웨어 로드 밸런서는 가장 높은 성능을 내지만, 도입 비용과 설정 복잡도가 상당합니다. 예산이 큰 대기업조차 모든 로드 밸런싱에 하드웨어를 쓰지 않습니다. 외부에서 들어오는 첫 번째 접점에만 하드웨어를 두고, 내부 트래픽은 스마트 클라이언트나 소프트웨어 로드 밸런서로 처리하는 혼합 방식을 씁니다.
Software Load Balancers
스마트 클라이언트의 복잡도와 하드웨어의 비용 사이에서 현실적인 선택지가 소프트웨어 로드 밸런서입니다. HAProxy가 가장 널리 쓰이는 오픈소스 옵션입니다.
HAProxy는 클라이언트와 서버 사이에 둘 수도 있고, 서버와 서버 사이에도 배치할 수 있습니다. 클라이언트 서버를 제어할 수 있다면 동일 서버에서 실행하면서 특정 포트(예: localhost:8080)를 로컬로 바인드하고, 해당 포트의 요청을 HAProxy가 받아 백엔드로 분산합니다. 서버 제어권이 없다면 중간에 별도 인스턴스로 실행합니다. 연결된 모든 서버의 헬스 체크를 수행하며, 서버 추가·제거를 동적으로 관리합니다.
여기서 제가 직접 겪은 실수를 짚고 넘어가겠습니다. HAProxy를 단일 인스턴스로만 운영했더니, HAProxy 자체가 장애 나는 순간 백엔드 서버가 전부 멀쩡해도 서비스 전체가 다운됐습니다. 로드 밸런서도 단일 장애 지점이 됩니다. 이를 방지하려면 active/passive 이중화 구성이 필요합니다. 두 HAProxy 인스턴스 사이에 가상 IP를 두어 하나가 죽으면 다른 인스턴스가 자동으로 이어받게 합니다.
대부분의 시스템은 소프트웨어 로드 밸런서에서 시작해서, 필요에 따라 스마트 클라이언트나 하드웨어 로드 밸런서 방향으로 전환하는 것이 현실적입니다.
면접 팁: 이 실수들은 실제로 감점됩니다
면접에서 로드 밸런서를 다루면서 제가 직접 지적받은 실수와, 이후 면접관 입장에서 자주 보게 된 오답을 정리합니다.
- Sticky session 남용: 세션을 서버 메모리에 저장한 채 로드 밸런서를 붙이면 동일 서버로만 요청이 가야 합니다. 문제는 서버가 재시작되면 세션이 통째로 날아간다는 점이고, sticky session이 켜져 있으면 부하가 특정 서버에만 몰립니다. 올바른 방향은 세션을 Redis 같은 외부 공유 저장소로 내보내 어떤 서버든 요청을 처리할 수 있게 만드는 것입니다.
- L7을 이유 없이 선택: "더 스마트하니까 L7을 쓰겠다"고 답했다가 지적받은 적이 있습니다. L7은 URL, 헤더, 쿠키 기반 라우팅이 필요할 때 쓰는 것이고, 그 기능이 필요 없다면 L4가 더 빠르고 리소스 소모도 적습니다.
- 알고리즘 설명 없이 "LB 추가"만 언급: "로드 밸런서를 추가하겠습니다"만 말하면 감점입니다. 어떤 알고리즘으로 분산할 것인지, 왜 그 알고리즘인지를 함께 설명해야 합니다.
- 로드 밸런서 자체의 이중화 누락: 설계에 로드 밸런서를 하나만 그려놓으면 단일 장애 지점 문제를 지적받습니다. 고가용성 설계라면 로드 밸런서 자체도 이중화해야 합니다.