アップストリームの負荷分散と障害隔離
한국어 원문으로 표시합니다.
목표
nginx 업스트림으로 여러 백엔드에 부하를 분산하고, 가중치·세션 고정·장애 격리· Keep-Alive 를 설정하며, 분배 알고리즘을 상황에 맞게 고를 수 있게 됩니다.
왜 중요한가
SI 현장에서 WAS 를 두 대 이상 두는 이유는 성능보다 한 대가 죽어도 서비스가
유지되게 하기 위해서입니다. 그런데 nginx 오픈소스판에는 능동 헬스체크가 없어서,
max_fails/fail_timeout 의 의미를 모르면 "죽은 서버로 계속 요청이 간다"는
상황을 만듭니다. 또 업스트림 Keep-Alive 는 세 가지 설정이 모두 있어야 동작하는데
proxy_set_header Connection "" 를 빠뜨려 매 요청마다 새 커넥션을 만드는 시스템이
정말 많습니다. 그러면 TIME_WAIT 소켓이 쌓여 어느 순간 포트가 고갈됩니다.
단계
- 준비: Tomcat(8080)에
labhub.war를 배포하고,/opt/lab/samples/labhub-boot.jar를 8082 포트로 기동해 둡니다. nginx 는/root/ng를 prefix 로 씁니다. /root/ng/nginx.conf에upstream app블록을 만들어127.0.0.1:8080과127.0.0.1:8082를 넣고, 8088 의/가 이 그룹으로 프록시되게 합니다.log_format에$upstream_addr를 반드시 포함시키고 액세스 로그를/root/ng/logs/access.log로 보냅니다.http://127.0.0.1:8088/version이 200 이어야 합니다.- 요청을 20회 보낸 뒤 액세스 로그를
/root/ng/rr.log로 복사합니다. 서로 다른 업스트림 주소가 2개 이상 기록돼야 합니다. 127.0.0.1:8080에weight=3을 주고 reload 한 뒤, 액세스 로그를 비우고 요청을 40회 보낸 다음/root/ng/weight.log로 복사합니다. 8080 으로 간 요청이 28~32회 사이여야 합니다.- 분배 방식을
ip_hash로 바꾸고 reload 한 뒤, 로그를 비우고 요청을 20회 보낸 다음/root/ng/iphash.log로 복사합니다. 업스트림 주소가 한 종류만 기록돼야 합니다. ip_hash를 제거하고(설정 파일에 남아 있으면 안 됩니다), 두 서버 모두에max_fails=2 fail_timeout=10s를 설정합니다. 그런 다음 8082 프로세스를 정지시키고 요청을 10회 보냅니다. 10회 모두 200 이어야 합니다.- 업스트림 Keep-Alive 를 설정합니다.
upstream블록에keepalive 32;, location 에proxy_http_version 1.1;과proxy_set_header Connection "";. 세 가지가 모두 있어야 합니다. upstream블록에least_conn;을 추가하고 문법 검사를 통과시킵니다./root/ng/lb.md를 작성합니다.라운드로빈,가중치,ip_hash,least_conn네 방식에 대해 각각 언제 쓰는지와 언제 쓰면 안 되는지를 적습니다.세션이라는 단어가 반드시 등장해야 하고, 전체 400자 이상이어야 합니다.
참고
- 로그 비우기:
> /root/ng/logs/access.log(reload 없이 됩니다) - 단계별 스냅샷:
cp /root/ng/logs/access.log /root/ng/rr.log - 업스트림별 건수:
awk '{...}' access.log | sort | uniq -c - 프로세스 정지:
pkill -f labhub-boot.jar - 흔한 실수 1:
ip_hash와weight를 함께 쓰면서 가중 분배를 기대하는 것. - 흔한 실수 2: Keep-Alive 3종 중
proxy_set_header Connection "";를 빠뜨리는 것. 이걸 빠뜨리면 HTTP/1.1 로 올려도 매 요청마다 커넥션이 끊깁니다. - 흔한 실수 3:
least_conn;을 location 에 쓰는 것.upstream블록 안에 넣어야 합니다.
업스트림 그룹 구성
/root/ng/nginx.conf 에 upstream app 블록을 만들어
127.0.0.1:8080 과 127.0.0.1:8082 를 넣고, 8088 의 / 가 이 그룹으로
프록시되게 합니다. log_format 에 $upstream_addr 를 반드시 포함시키고
액세스 로그를 /root/ng/logs/access.log 로 보냅니다.
http://127.0.0.1:8088/version 이 200 이어야 합니다.
upstream 블록은 http 컨텍스트에 둡니다. proxy_pass 에서 그 이름을 URL 처럼 씁니다. 두 백엔드를 모두 기동해 두는 것을 잊지 마세요.
라운드로빈 분배 확인
요청을 20회 보낸 뒤 액세스 로그를 /root/ng/rr.log 로 복사합니다.
서로 다른 업스트림 주소가 2개 이상 기록돼야 합니다.
어느 백엔드로 갔는지는 액세스 로그의 업스트림 주소 변수로 알 수 있습니다. 요청을 충분히 보내고 로그에서 고유 주소 수를 세어 보세요.
가중치 분배
127.0.0.1:8080 에 weight=3 을 주고 reload 한 뒤,
액세스 로그를 비우고 요청을 40회 보낸 다음 /root/ng/weight.log 로 복사합니다.
8080 으로 간 요청이 28~32회 사이여야 합니다.
nginx 의 가중 라운드로빈은 무작위가 아니라 결정적입니다. 가중치 비율이 그대로 분배 비율이 됩니다.
세션 고정
분배 방식을 ip_hash 로 바꾸고 reload 한 뒤, 로그를 비우고 요청을 20회 보낸 다음
/root/ng/iphash.log 로 복사합니다.
업스트림 주소가 한 종류만 기록돼야 합니다.
같은 클라이언트를 같은 백엔드로 보내는 방식입니다. 세션을 WAS 메모리에 두는 레거시 시스템에서 자주 씁니다. 서버가 추가·제거되면 재분배가 일어난다는 단점도 기억하세요.
장애 서버 자동 제외
ip_hash 를 제거하고(설정 파일에 남아 있으면 안 됩니다),
두 서버 모두에 max_fails=2 fail_timeout=10s 를 설정합니다.
그런 다음 8082 프로세스를 정지시키고 요청을 10회 보냅니다.
10회 모두 200 이어야 합니다.
nginx 오픈소스판은 능동 헬스체크가 없고, 실패 횟수 기반의 수동 방식만 있습니다. 백엔드 하나를 실제로 내려 보고 서비스가 유지되는지 확인하세요.
업스트림 Keep-Alive
업스트림 Keep-Alive 를 설정합니다. upstream 블록에 keepalive 32;,
location 에 proxy_http_version 1.1; 과 proxy_set_header Connection "";.
세 가지가 모두 있어야 합니다.
세 가지를 함께 설정해야 동작합니다. 하나만 빠져도 매 요청마다 새 커넥션이 생깁니다. 특히 Connection 헤더를 어떻게 처리해야 하는지가 함정입니다.
최소 연결 방식
upstream 블록에 least_conn; 을 추가하고 문법 검사를 통과시킵니다.
요청 처리 시간 편차가 큰 서비스에서 라운드로빈보다 나은 이유를 생각해 보세요.
분배 알고리즘 선택 기준 정리
/root/ng/lb.md 를 작성합니다. 라운드로빈, 가중치, ip_hash, least_conn
네 방식에 대해 각각 언제 쓰는지와 언제 쓰면 안 되는지를 적습니다.
세션 이라는 단어가 반드시 등장해야 하고, 전체 400자 이상이어야 합니다.
각 방식의 장점만 적으면 문서가 아닙니다. 언제 쓰면 안 되는지를 함께 적어야 나중에 판단에 쓸 수 있습니다.