NGINX MSA 디지털 트레이닝 - 3강 : Load Balancing
강의 동영상 : https://www.youtube.com/watch?v=sLoBvXNPTmk
원본 동영상 : https://www.youtube.com/watch?v=a41jxGP9Ic8
1. What is Load Balancing
1.1 Definition
Load Balancing is defined as the methodical and efficient distribution of network and application traffic across multiple servers in a server farm.
그림과 같이 Load Balancer는 클라이언트와 백엔드 서비스 사이에 위치해서 클라이언트로부터 Request를 받아 해당 Request를 수행할 수 있는 upstream 서비스 또는 Instance로 전달하는 역할을 수행한다
1.2 HTTP Load Balancing in NGINX
- Client Request를 처리할 Server pool 혹은 group을 설정
- proxy_pass 명령어를 통해 Client Request가 전달될 Server Pool이나 group을 지정.
- Server는 IP address + Port number, Domain Name 또는 Unix Socket 으로 정의됨.
2. Load Balancing Configuration
2.1 주요 Directives
upstream
- Server pool 설정
- HTTP Context 내에 위치
proxy_pass
- request를 정의된 upstream으로 전달.
Ex)
upstream backend_servers { server 192.168.10.1:9001; server 192.168.10.2:9001; } server { listen 80; location / { proxy_pass http://backend_servers; } }
- Line 1~4 : 10.1.1.4:9001, 10.1.1.5:9001 두 대의 Backend Server를 backend_servers라는 이름의 pool로 정의.
- Line 5~10 : 80 port의 root path로 요청된 request를 backend_servers로 정의된 pool로 전달.
2.2 Load Balancing 방식
- Round Robin
- Default 방식. 각각의 Request들이 Server Group에 속한 개별 서버로 고르게 전달된다.
- Ex) 192.168.10.1~3 3개의 서버에 차례대로 Request가 전달되게 된다.
upstream backend_servers { server 192.168.10.1:9001; server 192.168.10.2:9001; server 192.168.10.3:9001; }
- Server Weights
- 각각의 서버들이 가진 가중치를 더한 후에 (각 서버의 가중치) / (총 가중치) 만큼 개별 서버로 Request들이 분산 전달된다.
- Ex) 각각 5,3,2의 가중치가 있고 20번의 Request가 오면 192.168.10.1에게 10개(=20 * 5 / (5+3+2))의 Request가 전달되고 192.168.10.2에게 6개(=20 * 3 / (5+3+2)), 192.168.10.3에게 4개(=20 * 2 / (5+3+2))의 Request가 전달되게 된다.
upstream backend_servers { server 192.168.10.1:9001 weight=5; server 192.168.10.2:9001 weight=3; server 192.168.10.3:9001 weight=2; }
2.3 Load Balancing 중 Fail 처리
Server Pool에 포함된 서버들 중에서 응답하지 않는 것으로 확인되는 서버를 제외할 수 있다.
max_fails : 최대 연결 시도 횟수를 저정.. 이 횟수만큼 서버가 응답이 없으면 죽은 것으로 가정해서 Request 전달에서 제외된다.
fail_timeout : 최대 연결 실패에 대한 시간 제한 지정 및 다시 재시도 하기까지 Request를 전달하지 않는 시간 지정
Ex) 192.168.10.1은 최대 90초 내에 10번의 연결 시도가 실패하게 되면 해당 서버는 죽은 것으로 가정하고 90초 동안은 다시 연결 시도를 하지 않게 된다.
upstream backend_servers { server 192.168.10.1:9001 weight=5 max_fails=10 fail_timeout=90s; server 192.168.10.2:9001 weight=3 max_fails=4 fail_timeout=60s; server 192.168.10.3:9001 weight=2 max_fails=2 fail_timeout=30s; }
2.4 Advanced Load Balancing in NGINX
hash
MD5 hash algorithm을 사용해서 Client request 중 하나를 key로 해서 Hash 겂을 계산 하고 그 값에 따라 특정한 서버로 Request전달.
Frontend 요청 보다는 backend나 Firewall 뒤에서 사용.
Remark : 세션 정보를 유지할 수 있기 때문에 새로운 Server가 추가되거나 기존 서버가 제거될 때는 Hash값이 손상되면서 세션 정보가 손실된다.
Ex) Request URI를 기반으로 한 경우 : target URI가 /api/a면 Request가 모두 1번 서버로 전달되고, target URI가 /api/b면 모두 3번 서버로 전달된다.
upstream backend_servers { hash $request_uri; server 192.168.10.1:9001; server 192.168.10.2:9001; server 192.168.10.3:9001; }
ip_hash
위의 hash와 동일. 단 Client IP를 key로 해서 Hash 값을 생성.
Client IP를 key로 사용하기 때문에 특정 Client에서 오는 요청을 특정 Server가 다 처리하게 된다.
Remark : 앞단에 Reverse Proxy와 같은 것이 있을 경우 모든 요청이 하나의 서버로만 전달되는 문제가 발생할 수 있음.
Ex) 아래와 같이 설정할 경우, 그 아래 그림처럼 A,D 사용자가 보낸 Request는 모두 1번 서버로, B가 보낸 Request는 모두 2번 서버로, C가 보낸 Reques는 모두 3번 서버로 전달하는 식으로 동작한다.
upstream backend_servers { ip_hash; server 192.168.10.1:9001; server 192.168.10.2:9001; server 192.168.10.3:9001; }
least_conn
consecutive connection의 수가 가장 적은 서버로 Request를 전달
연결 수가 동일한 경우 round robin 방식에 의해 서버가 선택됨.
Remark. weight가 설정되었을 경우 weight 값을 고려해서 최소 연결수를 계산함. 가중치 1인 1번 서버에 5개의 연결이 있고, 가중치 2인 2번 서버에 8개의 연결이 있으면 (5 / 1) > (8 / 2) 이기 떄문에 2번 서버로 Request가 전달된다.
Ex)
upstream backend_servers { least_conn; server 192.168.10.1:9001; server 192.168.10.2:9001; server 192.168.10.3:9001; }
least_time (NGINX Plus 만 지원)
평균 Response Time이 가장 빠르고 Active Connection 수가 가장 적은 서버로 Request를 전달.
평균 Response Time을 측정할 때 사용하는 인자들에는 다음과 같은 것들이 있다.
- header : Server에서 첫번째 Byte가 도착하는 시간
- last_byte : Server에서 전체 Response가 도착하는 시간
- last_byte inflight : 불완전한 request를 고려해서 Server에서 전체 Response가 도착하는 시간
Ex) least_time을 header로 설정한 경우
upstream backend_servers { least_time header; server 192.168.10.1:9001; server 192.168.10.2:9001; server 192.168.10.3:9001; }
random (NGINX Plus 만 지원)
- Server를 Random하게 선택해서 Request를 전달.
2.5 Session Persistence
- NGINX plus에서 제공되는 기능으로 사용자 Session을 식별하고 해당 Session의 요청을 동일한 Server로 라우팅 하는 것을 의미
- Session Persistence는 'sticky'명령어를 사용해서 3가지 방법으로 제공된다
2.5.1 sticky cookie
- 맨처음 upstream group response에 대해 Cookie를 추가해서 특정 서버를 식별하고, Client의 다음 Request에서 이 Cookie를 사용할 때 응답을 보낸 Server로 다시 전달될 수 있게 한다.
- Ex) srv_id라는 Cookie를 설정하고 1시간동안 유지되며, 쿠키를 설정한 Domain과 Path를 정의한 예
upstream backend_servers { server 192.168.10.1:9001; server 192.168.10.2:9001; server 192.168.10.3:9001; sticky cookie srv_id expires=1h domain=.abc.com path=/; }
- Demo에서 lb_example로 정의된 Cookie를 설정해서 Client로 보낸 경우
2.5.2 sticky route
클라이언트로부터의 첫 요청에 대해 "Route"를 할당하고, 이후 요청을 route 인자의 paramter와 비교해서 서버를 식별한다.
Route 정보는 cookie나 request URI로부터 가져온다.
Ex)
upstream backend_servers { server 192.168.10.1:9001; server 192.168.10.2:9001; server 192.168.10.3:9001; sticky route $route_cookie $route_uri; }
2.5.3 sticky learn (?)
Request와 Response를 검사해 Session Identifier를 찾고, 이게 어떤 Server와 관련있는 지 "학습"하게 된다.
일반적으로 이런 identifier가 HTTP cookie로 전달되고, 이 값을 통해 해당 Server로 Request가 전달됨.
Ex)
upstream backend_servers { server 192.168.10.1:9001; server 192.168.10.2:9001; server 192.168.10.3:9001; sticky learn create=$upstream_cookie_examplecookie lookup=$cookie_examplecookie zone=client_sessions:1m timeout=1h }
2.6 기타
- max_conns : 서버가 처리할 수 있는 최대 동시 연결 수를 설정
- queue : max_conns로 설정한 최대 동시 연결 수를 넘어서 처리되지 않은 요청을 대기 시키는 Queue.
- Ex)
- 192.168.10.1은 최대 300개의 연결을 지원하고, 그 이상의 Request중 100개를 queue에 대기시킴.
- Queue에 대기 상태로 있는 Request 중 70초를 넘는 Request는 HTTPS Status Code 503이 Client에 전달되게 됨.
upstream backend_servers { server 192.168.10.1:9001 max_conn=300; server 192.168.10.2:9001; server 192.168.10.3:9001; queue 100 timeout=70; }
3. Demo에서 기록할만한 사항들
HTTP Custom Header 추가 : 해당 서버의 ID (Application 1) 정보를 포함한 Response Header 추가
server { listen 9001; index index.html; add_header Custom-Header "Applicaion 1"; ... }
curl -sI [ip-address:port | domain name] : Http Response Data를 제외한 Header 부분만 확인
반복 Request 예제
while true; do curl -sI <load-balancer-ip:port> | tr -d '\r' | sed -En 's/^Custom-Header: (.*)/\1/p'; sleep 1; done