nginx ip-hash 로드 밸런싱 불균형 원인 및 해결 방법

ip-hash 알고리즘의 동작 방식

nginx의 ip-hash 기반 로드 밸런싱은 요청의 클라이언트 IP 주소를 기반으로 후방 서버에 요청을 분산합니다. 내부적으로는 다음과 같은 해시 계산을 수행합니다:

for (;;) {
    for (i = 0; i < 3; i++) {
        hash = (hash * 113 + ip_addr[i]) % 6271;
    }
    p = hash % peers_count;
    n = p / (8 * sizeof(uintptr_t));
    m = (uintptr_t) 1 << (p % (8 * sizeof(uintptr_t)));
    
    if (!(tried_mask[n] & m)) {
        peer = &peers[p];
        if (!peer->down && 
            (peer->max_fails == 0 || peer->fails < peer->max_fails) ||
            (now - peer->accessed > peer->fail_timeout)) {
            break;
        }
        tried_mask[n] |= m;
        tries--;
    }

    if (++attempt_count >= 20) {
        return get_next_round_robin_peer();
    }
}

해당 코드에서 주의할 점은, 실제 IP 주소의 네 개 구간(예: 192.168.1.1) 중 상위 세 구간만 해시에 사용된다는 것입니다. 즉, 첫 세 번째 숫자가 동일한 모든 클라이언트는 동일한 후방 서버로 할당됩니다.

문제 발생 원인

이러한 설계는 일반적인 환경에서는 효과적이나, 특히 네트워크 레벨에서의 로드 밸런서(예: AWS ELB, F5, HAProxy 등)를 거쳐 올 경우 문제가 발생합니다. 이들 장치는 고정된 공유 IP 풀을 사용하며, 클라이언트의 실제 IP가 아닌 로드 밸런서의 내부 또는 공용 IP를 전달하게 됩니다.

결과적으로 여러 사용자가 동일한 중앙 로드 밸런서의 한 정적 IP를 통해 접속하면, nginx는 모든 요청을 동일한 백엔드 서버로 전달하게 되어 로드 밸런싱이 실패하고, 특정 서버에 과도한 부하가 발생합니다.

해결 방법

1. ip-hash 알고리즘 수정 (직접 코드 조정)

기존 해시 함수에서 전체 4개의 IP 구간을 포함하도록 변경할 수 있습니다. 예를 들어, 다음처럼 해시에 네 번째 구간까지 반영:

for (i = 0; i < 4; i++) {
    hash = (hash * 113 + ip_addr[i]) % 6271;
}

이렇게 하면 동일한 첫 세 구간을 가진 클라이언트라도 네 번째 구간 차이에 따라 다른 백엔드 서버로 분배됩니다. 단, 이는 nginx 소스 코드를 직접 수정해야 하며, 업데이트 시 재컴파일이 필요합니다.

2. HTTP_X_FORWARDED_FOR 헤더 기반 진짜 클라이언트 IP 추출

보다 실용적인 방법은 X-Forwarded-For 헤더를 활용하여 실제 클라이언트의 IP를 식별하는 것입니다. 이를 위해 nginx의 ngx_http_realip_module 모듈을 사용합니다:

server {
    listen 80;
    server_name example.com;

    location / {
        # 로드 밸런서나 프록시의 공용 IP를 신뢰하지 않도록 설정
        set_real_ip_from 10.48.10.0/24;
        set_real_ip_from 61.22.22.22;
        set_real_ip_from 192.168.0.0/16;

        # 실제 클라이언트 IP를 추출할 헤더 지정
        real_ip_header X-Forwarded-For;

        # 중첩된 프록시에서도 최종 클라이언트 IP를 확인
        real_ip_recursive on;

        # 이제 ip-hash가 실제 클라이언트의 IP를 기준으로 작동
        proxy_pass http://backend_pool;
    }
}

이 설정을 통해 ip_hash 지시어가 실제로 사용자 각각의 고유한 IP를 기반으로 동작하게 되어, 균형 잡힌 분산이 가능합니다.

요약

  • ip-hash는 기본적으로 클라이언트의 원본 IP를 기반으로 하지만, 중간 프록시가 존재할 경우 해당 정보가 손실됨.
  • 해시 계산에서 네 번째 IP 구간 미반영 → 비균형 분산 발생.
  • 해결책: 실제 클라이언트 IP를 추출하기 위한 real_ip_headerreal_ip_recursive 설정 권장.
  • 직접 코드 수정은 복잡하고 유지보수 어렵기에, 모듈 기반 접근이 더 안정적.

태그: nginx Load Balancing ip-hash X-Forwarded-For real_ip_module

6월 12일 23:41에 게시됨