안녕하세요, 수요일에 뜬금포 한번 날립니다.

오늘 upstream 기능 관련하여 테스트를 해야 할 일이 있어서 테스트를 진행하다가 알게 된 내용입니다.

 

upstream의 기본적인 LoadBalancing 알고리즘이 round robin 이라는 것!!!

일말의 여지도 없이 round robin 이라는 것!!!

 

어찌 생각하면 당연한 일이지만,

upstream과 proxy_pass를 설정한 후 원하는 결과가 나오지 않으니 조금 당황스럽더군요...

아래와 같은 테스트 환경에서,

저는 1번 pc에서 요청하면 www.a.com 페이지가 표시되고,

2번 pc에서 요청하면 www.b.com 페이지가 표시될 줄 알았습니다.

순진한 생각이었나요??

 

결과는 뒤죽박죽이었습니다. 

해당 페이지에 로딩되는 content의 수(turn 수) 만큼 backend 서버 간에 round robin 이 이루어지고 있었습니다.

응답코드로 보면 200 과 404 의 아비규환

 

 

 

  • 테스트 환경

http {

  upstream backend {
    server www.a.com;
    server www.b.com;
  }


  server {
    listen 80:
    sever_name localhost;

    location / {
      proxy_pass http://backend;
    }
  }
}

 

  • 특정 request에 대응하는 backend 서버 확인 (access_log 설정)

log_format main ' $remote_addr - $remote_user [$time_local] "$request" '
                        ' $status $body_bytes_sent "$http_referer" '
                        ' "$http_user_agent" "$http_x_forwarded_for" "$upstream_addr" ';

 

우리는 Apache/Jboss 연동이나, Apache/Tomcat 또는 iPlanet/WebLogic 연동을 통해서

학습과 경험한 바와 같이, WEB과 WAS가 2:2 이상으로 연결되어 있는 환경이라도

(장애가 없는 상황이라면) 동일 사용자의 request는 동일한 WEB과 동일한 WAS에서 처리되는 것으로

알고 있습니다.

이런 이유는 mod_jk 나 wl_proxy와 같이 WAS에서 제공하는 plugin 모듈에서는 StickySession 기능을

기본적으로 제공하기 때문입니다.

 

이 외에, Apache 자체적으로도 mod_proxy_balancer 를 통하여 proxy 서버들 간에 StickySession 기능을 제공 하더군요.

 

하지만, nginx의 proxy_pass는 StickySession을 지원하지 않네요. (적어도 1.4.2 버전에서는)

저는 적어도 동일한 사용자의 요청에 대해서는 기본적으로 StickySession이 적용될 줄로 알았습니다.

o 관련 내용은 미할님의 글 "Advanced load balancing" 게시물 참고

o http://sarc.io/index.php/nginx/98-advanced-load-balancing

 

 

오늘의 Lessons Learned 입니다.

o upstream을 이용한 load balancing 구성 시 주의사항

   - nginx 버전이 plus 이상이 아닌 경우 (걍 nginx 버전 사용 시)

   - session을 이용 하지만, backend 서버들이 session cluster가 되어 있지 않은 경우

   - backend 서버들이 session cluster가 되어 있어도 session replication 지연이 있는 경우

o 위와 같은 경우에는 반드시 ip_hash 지시어을 사용해야 함

o 그렇지 않은 경우, 서비스가 비정상이라는 end-user의 claim을 받을 수 있음

 

  • 개선 환경

http {

  upstream backend {

    ip_hash;
    server www.a.com;
    server www.b.com;
  }


  server {
    listen 80:
    sever_name localhost;

    location / {
      proxy_pass http://backend;
      } 
    } 
}