서버 트래픽 분산을 위한 6가지 로드 밸런싱 알고리즘 심층 분석

분산 시스템 아키텍처에서 서버 부하를 효과적으로 관리하고 가용성을 높이기 위해 다양한 로드 밸런싱(Load Balancing) 알고리즘이 사용됩니다. 본 글에서는 가장 널리 쓰이는 6가지 알고리즘의 작동 원리, 장단점 및 구현 로직을 기술적 관점에서 상세히 살펴보겠습니다.

1. 라운드 로빈 (Round Robin)

라운드 로빈은 가장 직관적이고 단순한 무상태(Stateless) 스케줄링 기법입니다. 서버 목록을 순차적으로 반복하여 요청을 배정합니다. 각 서버의 성능 차이를 고려하지 않으며, 모든 서버가 동일한 처리 능력을 가진다고 가정할 때 적합합니다.

동작 예시: 서버 A, B, C가 있을 경우, 요청은 A → B → C → A ... 순서로 배정됩니다.

// 라운드 로빈 의사 코드
int currentIndex = 0;
List<Server> serverList = getActiveServers();

if (serverList.isEmpty()) {
    throw new RuntimeException("No available servers");
}

// 인덱스 초기화 또는 증가
currentIndex = (currentIndex + 1) % serverList.size();
return serverList.get(currentIndex);

특징: 구현이 간단하고 오버헤드가 적지만, 서버 사양이 상이한 환경에서는 특정 서버에 과부하가 걸릴 수 있습니다.

2. 랜덤 (Random)

랜덤 알고리즘은 서버 풀에서 임의로 하나의 서버를 선택하는 방식입니다. 통계학적인 대수의 법칙에 따라 충분한 수의 요청이 발생하면 평균적으로 라운드 로빈과 유사한 분포를 보이게 됩니다.

동작 예시: 요청마다 난수 생성기를 사용하여 서버 인덱스를 결정합니다.

// 랜덤 의사 코드
import java.util.Random;

Random random = new Random();
int selectedIndex = random.nextInt(serverList.size());
return serverList.get(selectedIndex);

특징: 상태 정보를 유지할 필요가 없어 경량적입니다. 다만, 단기적으로는 특정 서버에 요청이 집중될 수 있는 편차가 존재합니다.

3. 소스 IP 해시 (Source IP Hash / Sticky Session)

클라이언트의 소스 IP 주소를 해시 함수에 입력하여 값을 도출하고, 이 해시값을 서버 개수로 나눈 나머지를 통해 서버를 배정합니다. 동일한 클라이언트는 항상 동일한 서버로 연결되므로 세션 지속성(Session Persistence)이 필요한 경우에 유용합니다.

동작 예시:

// 소스 IP 해시 의사 코드
String clientIp = request.getSourceIpAddress();
int hashValue = Math.abs(clientIp.hashCode()); // 음수 방지
int serverIndex = hashValue % serverCount;
return serverPool[serverIndex];

특징: 서버 장애 시 해당 서버에 할당된 클라이언트들은 재연결 실패나 서비스 중단을 겪을 수 있으며, 해시 충돌로 인해 특정 서버에 부하가 쏠리는 '핫 스팟(Hot Spot)' 문제가 발생할 수 있습니다.

4. 가중치 기반 라운드 로빈 (Weighted Round Robin)

서버마다 하드웨어 사양이나 네트워크 대역폭이 다른 현실적인 환경을 반영하기 위해 도입된 알고리즘입니다. 각 서버에 가중치(Weight)를 부여하며, 가중치가 높은 서버일수록 더 많은 요청을 처리하도록 조정합니다.

동작 원리: 가중치를 기반으로 가상 서버 목록을 확장하거나, 카운터 방식을 사용해 비율대로 요청을 분배합니다.

서버 주소 가중치 설명
192.168.0.1 10 고사양 서버 (요청 많이 받음)
192.168.0.2 4 중급 사양 서버
192.168.0.3 1 저사양 서버 (요청 적게 받음)

위 설정에서 총 15번의 요청이 들어올 경우, 서버 .1은 약 10회, 서버 .2는 4회, 서버 .3은 1회 정도 요청을 처리하게 됩니다.

5. 가중치 기반 랜덤 (Weighted Random)

랜덤 알고리즘에 가중치를 적용한 변형입니다. 서버를 선택할 확률을 가중치에 비례하게 만듭니다. 즉, 가중치가 큰 서버가 선택될 확률이 높아지지만, 여전히 확률적 요소가 포함되어 있어 완전한 균등 분배보다는 유연한 분산을 허용합니다.

구현 논리: 전체 가중치의 합을 구하고, 그 범위 내에서 난수를 생성하여 누적 가중치와 비교해 서버를 선정합니다.

# 가중치 기반 랜덤 의사 코드 (Python 스타일)
def weighted_random_choice(servers):
    total_weight = sum(s.weight for s in servers)
    r = random.uniform(0, total_weight)
    
    current_sum = 0
    for server in servers:
        current_sum += server.weight
        if r <= current_sum:
            return server
    return servers[-1] # Fallback

특징: 라운드 로빈보다 부드러운 트래픽 분산을 제공하며, 급격한 트래픽 변화에 대해 상대적으로 덜 민감합니다.

6. 최소 연결 수 (Least Connections)

현재 각 서버에 연결되어 있는 활성 커넥션(Active Connection)의 수를 실시간으로 추적하여, 가장 적은 수의 연결을 가진 서버로 새 요청을 배정합니다. 이는 서버의 현재 부하 상태를 직접적으로 반영하므로 동적 디스트리뷰션(Dynamic Distribution)에 매우 효과적입니다.

동작 원리: 요청 수신 시 연결 수 증가, 응답 완료/타임아웃 시 연결 수 감소라는 이벤트 기반 카운팅을 사용합니다.

// 최소 연결 수 의사 코드
Server bestServer = null;
int minConnections = Integer.MAX_VALUE;

for (Server server : serverList) {
    int currentConn = server.getActiveConnectionCount();
    // 가중치를 고려한 정규화된 연결 수 계산 가능
    if (currentConn < minConnections) {
        minConnections = currentConn;
        bestServer = server;
    }
}
return bestServer;

특징: 요청 처리 시간이 제각각인 경우(예: 복잡한 쿼리 vs 간단한 조회) 라운드 로빈보다 훨씬 정확한 부하 분산을 제공합니다. 다만, 연결 상태 정보를 중앙에서 관리해야 하므로 동기화 오버헤드가 발생할 수 있습니다.

알고리즘 선택 가이드

  • 단순성과 속도 우선: 라운드 로빈 또는 랜덤
  • 세션 지속성 필요: 소스 IP 해시
  • 서버 사양 불균일: 가중치 기반 라운드 로빈 또는 가중치 기반 랜덤
  • 실시간 부하 정밀 제어: 최소 연결 수

태그: Load Balancing Round Robin Least Connections Weighted Algorithm Distributed Systems

9월 22일 05:52에 게시됨