• Nginx 리버스 프록시 로드 밸런싱 문의 드립니다.

    카페에서 만든 간단한 웹페이지를 서비스하려고 Nginx로 리버스 프록시 설정을 만져보고 있어요.

    딱히 복잡한 서비스는 아니라서요.

    근데 백엔드 서버를 두 대 정도 붙여서 로드 밸런싱을 적용해야 할 것 같은데, 설정 부분이 막막하네요.

    간단하게 A 서버랑 B 서버 두 개를 놓고 트래픽 분산하는 게 최적의 방법이 뭔지 감이 안 와서요.

    어떤 방식으로 헬스 체크를 걸어주는 게 제일 안정적인지, 아니면 좀 더 복잡하게 세팅해야 하는 건지 경험 있으신 분들 조언 부탁드립니다.

  • 아이고, Nginx 리버스 프록시라니 벌써부터 머리가 지끈거리시죠.
    설정 파일 만지는 거 처음 하면 다들 그 기분 아실 거예요.
    복잡해 보이지만, 원리를 이해하고 나면 생각보다 논리적이라 금방 감을 잡으실 수 있을 거예요.
    일단 결론부터 말씀드리자면, 간단한 웹페이지 서비스라면 가장 기본적이면서도 안정성이 검증된 방식으로 시작하시는 게 최고입니다.
    그리고 핵심은 '어떻게 장애를 감지할 것인가'에 초점을 맞추는 거예요.
    로드 밸런싱 자체는 구현하는 방식이 몇 가지 있는데, 질문자님의 상황(간단한 웹페이지, 2대 구성)을 고려했을 때 가장 추천하는 방식과 그에 따른 구체적인 설정을 단계별로 설명해 드릴게요.
    --- ### 1.
    로드 밸런싱 알고리즘 선택 가이드 Nginx에서 트래픽을 분산시키는 방법(알고리즘)이 여러 가지 있어요.

    • Round Robin (라운드 로빈): 가장 단순한 방식입니다.
      A 서버에 요청이 오면 A, 다음 요청은 B, 그다음은 다시 A 순서로 돌아가며 요청을 보냅니다.
    • 장점: 설정이 정말 쉽고 직관적입니다.
    • 단점: 서버의 실제 부하를 고려하지 않아요.
      만약 A 서버가 갑자기 느려져서 처리 시간이 길어지더라도, Nginx는 계속해서 A 서버로 요청을 보냅니다.
      마치 체력 좋은 사람에게만 계속 일을 주는 것과 비슷해요.
    • 추천 상황: 두 서버의 성능 차이가 거의 없고, 요청 자체가 매우 짧고 빠르게 처리되는 경우에 적합합니다.
    • Least Connections (최소 연결): 현재 연결이 가장 적은 서버로 트래픽을 보내는 방식입니다.
    • 장점: 실시간 부하 분산에 가장 근접합니다.
      어느 서버가 지금 여유가 있는지를 어느 정도 반영해서 요청을 분배해요.
    • 단점: 연결 상태를 지속적으로 추적해야 하므로 Round Robin보다는 약간 더 복잡합니다.
    • 추천 상황: 질문자님처럼 '어느 정도 안정적인 분산'이 필요하고, 서버들이 비슷한 작업을 처리한다고 가정할 때 가장 먼저 시도해 볼 만한 방식입니다.
    • IP Hash: 클라이언트의 IP 주소 기반으로 특정 서버에 고정적으로 연결시키는 방식입니다.
    • 장점: 특정 사용자의 요청이 항상 같은 서버로 가도록 보장할 수 있어요.
      (이게 나중에 '세션 지속성' 같은 걸 구현할 때 필요해요.) * 단점: 부하 분산의 목적보다는 '사용자 경험 일관성'에 목적이 맞춰져 있습니다.
      💡 실무 팁 요약: 일단은 **least_conn**으로 시작하시는 걸 추천드립니다.
      만약 least_conn으로 테스트했는데도 특정 서버에 부하가 몰리는 느낌이 든다면, 그때는 헬스 체크 설정을 깊게 파고드는 게 좋아요.
      --- ### 2.
      가장 중요한 부분: 헬스 체크 (Health Check) 로드 밸런싱에서 헬스 체크는 선택이 아니라 필수 중의 필수입니다.
      헬스 체크가 없다면, 백엔드 서버 A가 다운되었는데도 Nginx는 계속 A에게 요청을 보내게 되고, 사용자들은 무한 로딩 화면만 보게 됩니다.
      Nginx는 기본적으로 upstream 블록에서 서버의 상태를 확인하는 기능을 제공합니다.
      A.
      기본 헬스 체크 (Failover/Fail Threshold 방식):
      이건 특정 서버가 요청에 실패했을 때, 일정 횟수만큼 연속으로 실패하면 그 서버를 잠시 제외시키는 방식입니다.
    • max_fails=N: 이 서버가 연속으로 N번 실패하면 잠시 비활성화됩니다.
    • fail_timeout=T: 비활성화된 서버를 다시 테스트할 간격입니다.
      이 시간 동안은 트래픽을 보내지 않습니다.
      어떤 게 제일 안정적인가? 질문자님의 간단한 웹페이지 정도라면, max_failsfail_timeout을 적절히 조합하는 것만으로도 90% 이상은 충분히 안정적입니다. 너무 복잡한 설정을 처음부터 하실 필요는 없어요.
      ⚠️ 주의할 점 (흔한 실수): 헬스 체크를 너무 민감하게 설정하면 안 돼요.
      예를 들어, max_fails=2로 너무 낮게 설정하면, 서버가 순간적으로 네트워크 지연을 겪거나, Nginx 자체의 부하 때문에 1~2번만 실패해도 그 서버가 아예 트래픽에서 제외되어 버릴 수 있습니다.
      초기에는 max_fails=3 정도, fail_timeout=10s 정도로 넉넉하게 설정하는 걸 추천드립니다.
      B.
      고급 헬스 체크 (Active/Passive 방식):
      만약 정말 극한의 안정성이 필요하다면, Nginx Plus 같은 유료 버전이나, 별도의 모듈을 사용해서 '특정 경로로 HTTP GET 요청을 보내보고 200 OK가 오는지'를 주기적으로 체크하는 방식이 있어요.
      하지만 무료 오픈소스 Nginx만 사용하신다면, 위의 max_fails 방식이 가장 표준적이고 효과적입니다.
      --- ### 3.
      실제 Nginx 설정 구조 (예시) 아래는 위 내용을 바탕으로 구성한 개념적인 설정 파일의 흐름입니다.
    로드 밸런싱 알고리즘 지정 (Least Connections 추천) least_conn; # 2.
    서버 그룹 정의 (A, B) server 192.168.1.10:80; # A 서버 IP:Port server 192.168.1.11:80 max_fails=3 fail_timeout=10s; # B 서버 IP:Port # 3.
    (선택 사항) 가중치 부여가 필요할 때 (A 서버 성능이 B보다 2배 좋다면) # server 192.168.1.10:80 weight=2; # server 192.168.1.11:80 weight=1; } server { listen 80; server_name yourdomain.com; location / { # 4.
    트래픽을 정의된 업스트림 그룹으로 전달 proxy_pass http://backend_servers; # 5.
    헤더 설정 (필수) proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } ``` **설정 설명 추가:** * `proxy_set_header`: 이 헤더들을 반드시 추가해 주셔야 백엔드 서버에서 요청을 보낸 실제 클라이언트의 IP 주소(`$remote_addr`)를 정확히 파악할 수 있습니다.
    이거 안 하면 다 Nginx 서버 IP로 찍힐 수 있어요.
    * **타임아웃 처리:** 추가적으로, `proxy_connect_timeout`, `proxy_read_timeout` 같은 타임아웃 설정을 해주시면 좋습니다.
    서버가 응답이 없을 때 Nginx가 무한정 기다리다가 리소스를 묶이는 걸 방지할 수 있습니다.
    (예: `proxy_read_timeout 60s;`) --- ### 4.
    심화 및 추가 고려사항 (더 안정적으로 만드는 법) 질문자님 서비스가 나중에 커지거나, 사용자 경험이 중요하다면 다음 두 가지를 고려해보세요.
    **① Sticky Session (세션 지속성):** 만약 사용자가 로그인하거나, 장바구니에 물건을 담는 등 '이전 상태'를 기억해야 하는 기능을 넣는다면, **반드시 같은 서버에 계속 붙어 있어야 합니다.** 이게 '세션' 문제입니다.
    * **구현 방법:** Nginx에서 `ip_hash`를 사용하는 것이 가장 간단합니다.
    * **설정:** `upstream` 블록에 `ip_hash`를 추가하고, `least_conn` 대신 `ip_hash`를 사용하도록 변경해야 합니다.
    * 예: `upstream backend_servers { ip_hash; server A; server B; }` * **주의:** 이 기능을 쓰면 부하 분산의 장점이 조금 희석될 수 있습니다.
    왜냐하면 IP 주소가 같은 사용자라면 항상 A 서버로만 가고, A 서버가 다운되면 그 사용자는 서비스 이용 불가 상태가 될 수 있기 때문입니다.
    하지만 '로그인 상태 유지'가 더 중요하다면 감수해야 합니다.
    **② 모니터링 및 로깅:** 로드 밸런싱을 테스트할 때는 반드시 로그를 확인하세요.
    * `error.log`를 주기적으로 봐서, 특정 서버가 계속해서 `upstream prematurely closed connection` 같은 에러를 내뱉는지 확인해야 합니다.
    * 실제 트래픽이 들어올 때 Nginx의 상태 모니터링 툴(예: `curl` 반복 요청이나 실제 사용자 접속)을 돌려가면서, 요청이 A와 B에 골고루 분배되는지 눈으로 확인하는 과정이 필수입니다.
    --- 결론적으로 정리하자면, 1.
    **알고리즘:** `least_conn`으로 시작하세요.
    2.
    **안정성:** `max_fails`와 `fail_timeout`을 넉넉하게 설정하여 장애 감지 기능을 활성화하세요.
    3.
    **필수 체크:** `proxy_set_header`로 모든 헤더를 꼼꼼히 챙겨주세요.
    이 정도만 하셔도 간단한 웹페이지 서비스는 매우 안정적으로 운영하실 수 있을 거예요.
    설정 파일은 작은 오타나 누락된 헤더 하나가 큰 문제를 일으키기 쉬우니, 하나씩 테스트하면서 점진적으로 기능을 추가해 나가시는 것을 강력히 권장드립니다.
    화이팅하시고, 궁금한 거 있으면 언제든지 다시 질문 주세요!