날씨 정보를 불러오는 중...

HAProxy + Keepalived로 구축하는 리눅스 L4 로드밸런싱 & 이중화

2026-09-06 21:20 · IT기술 · 조회 39
HAProxy Keepalived L4 로드밸런싱

HAProxy + Keepalived로 구축하는 리눅스 L4 로드밸런싱 & 이중화

서비스를 운영하다 보면 트래픽이 늘어나 서버 한 대로는 감당이 안 되거나, 로드밸런서 자체가 죽었을 때 서비스 전체가 멈춰버리는 문제를 만나게 됩니다. 이번 글에서는 HAProxy로 L4(전송 계층) 로드밸런싱을 구성하고, Keepalived로 로드밸런서 자체를 이중화하여 단일 장애점(SPOF)을 없애는 방법을 정리합니다.

L4 1. 개념 정리 — L4 로드밸런싱과 이중화란?

L4 로드밸런싱은 IP/포트(TCP·UDP) 정보만 보고 트래픽을 여러 백엔드 서버로 분산하는 방식입니다. HTTP 헤더나 URL 같은 애플리케이션 데이터를 들여다보는 L7 방식보다 오버헤드가 적고 처리 속도가 빠르다는 장점이 있어, 대량 트래픽을 빠르게 흘려보내야 하는 구간에 많이 사용됩니다.

문제는 로드밸런서 자체가 단일 장애점이 된다는 점입니다. 백엔드 서버를 아무리 여러 대 둬도 앞단의 로드밸런서가 죽으면 서비스 전체가 마비됩니다. 그래서 로드밸런서를 최소 2대(Active-Standby) 이상 두고, Keepalived가 VRRP(Virtual Router Redundancy Protocol) 프로토콜로 두 서버 사이에서 살아있는지 서로 감시하다가, MASTER가 죽으면 BACKUP이 순식간에 가상 IP(VIP)를 넘겨받아 서비스를 이어가도록 만듭니다.

  1. HAProxy: 실제로 트래픽을 받아서 백엔드 서버들에게 분산시키는 로드밸런서 역할
  2. Keepalived: HAProxy가 떠 있는 두 서버(또는 그 이상) 사이에서 VRRP로 상태를 감시하고, 살아있는 서버 쪽으로 가상 IP(VIP)를 붙여주는 이중화 담당

서버 2. 아키텍처와 서버 구성 예시

가장 기본적인 구성은 로드밸런서 2대(LB1, LB2)가 VIP 하나를 공유하고, 그 뒤에 실제 서비스를 처리하는 리얼서버(Real Server)가 여러 대 있는 형태입니다. 클라이언트는 항상 VIP 하나로만 접속하며, 뒤에서 어떤 물리 서버가 응답하는지는 신경 쓸 필요가 없습니다.

  1. VIP (Virtual IP): 예) 192.168.10.100 — 클라이언트가 실제로 접속하는 대표 IP
  2. LB1 (MASTER): 192.168.10.101 — 평소 VIP를 들고 트래픽을 처리
  3. LB2 (BACKUP): 192.168.10.102 — 평소 대기 상태, LB1 장애 시 VIP 인수
  4. Real Server 1, 2, 3...: 192.168.10.201 ~ 203 — 실제 애플리케이션(웹, WAS 등)이 떠 있는 서버

MASTER MASTER (LB1) — 우선순위(priority)를 높게 설정하여 평소 VIP를 점유하고 실제 트래픽을 처리합니다.

BACKUP BACKUP (LB2) — 우선순위를 낮게 설정하고 평소엔 대기하다가, MASTER의 VRRP 광고(advertisement)가 끊기면 즉시 VIP를 가져옵니다.

설정 3. HAProxy 설치 및 설정

LB1, LB2 두 서버 모두에 동일하게 설치하고 설정합니다. (RHEL 계열 기준, Debian/Ubuntu는 apt install haproxy)

dnf install -y haproxy
systemctl enable haproxy

설정 파일은 /etc/haproxy/haproxy.cfg 이며, 핵심은 frontend(클라이언트 요청을 받는 지점)와 backend(실제 서버로 분산하는 지점)입니다. 아래는 TCP(L4) 기준 80번 포트 로드밸런싱 예시입니다.

global
    log         127.0.0.1 local2
    maxconn     20000
    daemon

defaults
    mode        tcp
    log         global
    option      tcplog
    timeout connect 5s
    timeout client  30s
    timeout server  30s

# HAProxy 상태 확인용 통계 페이지
listen stats
    bind *:8404
    mode http
    stats enable
    stats uri /stats
    stats refresh 10s
    stats auth admin:StrongPassword!

frontend fe_web
    bind *:80
    default_backend be_web

backend be_web
    balance roundrobin
    option tcp-check
    server real1 192.168.10.201:80 check
    server real2 192.168.10.202:80 check
    server real3 192.168.10.203:80 check
  1. mode tcp: L4 방식으로 동작 (L7으로 하려면 mode http + option httpchk 사용)
  2. balance roundrobin: 순서대로 분산. 이 외에 leastconn(연결 수가 가장 적은 서버 우선), source(출발지 IP 기준 고정 분산) 등도 자주 씁니다
  3. check: 헬스체크를 활성화해 죽은 리얼서버는 자동으로 분산 대상에서 제외

설정 문법 검증 후 서비스를 시작합니다.

haproxy -c -f /etc/haproxy/haproxy.cfg
systemctl restart haproxy

HA 4. Keepalived 설치 및 설정 (VRRP 이중화)

이제 HAProxy 두 대를 하나의 VIP로 묶는 Keepalived를 설정합니다. 마찬가지로 LB1, LB2 양쪽 모두 설치합니다.

dnf install -y keepalived
systemctl enable keepalived

먼저 HAProxy가 죽었을 때 VRRP 우선순위를 낮춰서 VIP를 넘겨주도록 감시 스크립트를 만듭니다.

# /etc/keepalived/check_haproxy.sh
#!/bin/bash
if ! systemctl is-active --quiet haproxy; then
    exit 1
fi
exit 0
chmod +x /etc/keepalived/check_haproxy.sh

MASTER LB1 (MASTER) 설정 — /etc/keepalived/keepalived.conf

vrrp_script chk_haproxy {
    script "/etc/keepalived/check_haproxy.sh"
    interval 2
    weight -20
    fall 2
    rise 2
}

vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 150
    advert_int 1

    authentication {
        auth_type PASS
        auth_pass MyVrrpSecret
    }

    virtual_ipaddress {
        192.168.10.100/24
    }

    track_script {
        chk_haproxy
    }
}

BACKUP LB2 (BACKUP) 설정 — MASTER와 거의 동일하지만 stateBACKUP으로, priority는 더 낮게 설정합니다. (나머지 virtual_router_id, auth_pass, virtual_ipaddress는 반드시 동일해야 같은 VRRP 그룹으로 묶입니다.)

vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1

    authentication {
        auth_type PASS
        auth_pass MyVrrpSecret
    }

    virtual_ipaddress {
        192.168.10.100/24
    }

    track_script {
        chk_haproxy
    }
}
  1. priority: 숫자가 높은 쪽이 MASTER가 됩니다. track_script로 HAProxy가 죽으면 weight만큼 깎여서 BACKUP보다 낮아지고, 자동으로 상대에게 VIP가 넘어갑니다
  2. virtual_router_id: 같은 네트워크에 다른 VRRP 그룹이 있다면 겹치지 않게 지정 (1~255)
  3. interface: VIP를 붙일 실제 네트워크 인터페이스명 (ip a로 확인)
systemctl restart keepalived

방화벽 5. 커널·방화벽 설정 (놓치기 쉬운 부분)

여기서 막히는 경우가 많아 별도로 짚고 넘어갑니다.

  1. net.ipv4.ip_nonlocal_bind: HAProxy가 아직 VIP를 갖지 않은 BACKUP 상태에서도 미리 바인딩을 시도할 수 있도록 커널 파라미터를 켜줘야 합니다. 안 켜두면 BACKUP → MASTER로 전환된 직후 HAProxy 바인드 에러가 날 수 있습니다.
    echo "net.ipv4.ip_nonlocal_bind = 1" >> /etc/sysctl.conf
    sysctl -p
  2. 방화벽에서 VRRP 프로토콜(112번) 허용: VRRP는 TCP/UDP가 아닌 별도의 IP 프로토콜(112)을 사용하고, 224.0.0.18(멀티캐스트)로 통신합니다. firewalld 기준:
    firewall-cmd --permanent --add-rich-rule='rule protocol value="vrrp" accept'
    firewall-cmd --reload
  3. 서비스 포트 허용: HAProxy가 리스닝하는 포트(80, 8404 등)도 당연히 열어줘야 합니다.
    firewall-cmd --permanent --add-port=80/tcp
    firewall-cmd --permanent --add-port=8404/tcp
    firewall-cmd --reload

테스트 6. 동작 확인 및 장애조치(Failover) 테스트

구성이 끝났다면 반드시 실제로 장애 상황을 만들어서 VIP가 잘 넘어가는지 검증해야 합니다. 검증 없는 이중화 구성은 없는 것과 마찬가지입니다.

  1. LB1에서 ip a로 VIP(192.168.10.100)가 붙어 있는지 확인
  2. 클라이언트에서 VIP로 지속적인 요청을 반복 (예: while true; do curl -s -o /dev/null -w "%{http_code}\n" http://192.168.10.100; sleep 0.5; done)
  3. LB1에서 systemctl stop haproxy 또는 systemctl stop keepalived로 강제 장애 유발
  4. 몇 초 이내에 LB2의 ip a에 VIP가 새로 붙는지 확인하고, 클라이언트 쪽 요청이 끊기지 않고(혹은 순간적인 재시도 정도로) 계속 200이 찍히는지 확인
  5. LB1을 복구(systemctl start haproxy)했을 때 priority가 더 높으므로 VIP를 다시 가져오는지(preempt) 확인 — 운영 환경에서 잦은 전환이 싫다면 nopreempt 옵션으로 자동 회수를 막을 수도 있습니다

모니터링 7. 모니터링

위 설정에 포함한 HAProxy 통계 페이지로 실시간 상태를 확인할 수 있습니다. 브라우저에서 http://VIP:8404/stats로 접속하면 각 백엔드 서버의 연결 수, 상태(UP/DOWN), 응답 시간 등을 바로 볼 수 있습니다. 운영 환경이라면 여기에 Prometheus exporter(haproxy_exporter)를 붙여 Grafana 대시보드로 이어가는 것을 권장합니다.

마무리

HAProxy와 Keepalived 조합은 상용 L4 장비 없이도 리눅스 서버만으로 꽤 견고한 로드밸런싱 + 이중화 구성을 만들 수 있는 실용적인 방법입니다. 정리하면:

  1. HAProxy가 실제 트래픽 분산을 담당
  2. Keepalived(VRRP)가 로드밸런서 자체의 이중화 + VIP 자동 전환을 담당
  3. 커널 파라미터(ip_nonlocal_bind)와 VRRP 프로토콜 방화벽 허용을 빼먹지 않기
  4. 구성 후 반드시 실제 장애 시나리오로 failover 테스트를 해볼 것

여기서는 가장 기본적인 Active-Standby 2대 구성을 다뤘지만, 실제 운영에서는 Keepalived VRRP 인스턴스를 여러 개 만들어 LB1/LB2가 서로 다른 VIP에 대해 MASTER/BACKUP을 나눠 맡는 Active-Active 구성도 가능합니다. 환경과 트래픽 특성에 맞춰 확장해보시기 바랍니다.


댓글 0

로그인 후 댓글을 작성할 수 있습니다.