Nginx에서 제공하는 upstream 설정을 활용하여 웹 서버에 가해지는 부하를 분산하는 방법을 알아보겠습니다.
로드 밸런싱은 애플리케이션을 지원하는 리소스 풀 전체에 네트워크 트래픽을 균등하게 배포하는 방법입니다. - AWS(로드 밸런싱이란 무엇인가요?)
웹 서비스를 이용하는 사용자가 늘어날 수록 서버에 가해지는 트래픽이 증가하게됩니다. 서버가 감당할 수 없는 과도한 트래픽이 몰리게 된다면 장애가 발생하여 서비스 이용이 불가능하게 될 것입니다.
서버를 재부팅하게 된다면 인입되던 트래픽이 초기화되어 잠시나마 정상적으로 서비스가 이용 가능한 것처럼 보이겠지만, 이내 트래픽이 증가하면 동일한 장애가 발생하게 됩니다. 결국 장애를 해결하기 위해서는 인입되는 트래픽이 수용 가능한 정도의 PC자원을 증설하는 방식을 고려해보아야 합니다.
사용 가능한 PC자원을 증설하는 방법은 Scale-out 과 Scale-up 두 가지 방식을 고려해 볼 수 있습니다. 그림과 함께 두 방식이 어떻게 차이가 나는지 알아보겠습니다.
Scale-out은 기존 서버와 동일한 스펙의 새로운 컴퓨팅 자원을 추가하는 방식입니다. 클라우드 컴퓨팅 서비스를 이용할 경우 사용 가능한 비용 안에서 무한대로 자원을 증설 할 수 있다는 장점이 있습니다. 하지만 새로운 PC 자원이 추가되는 방식인 만큼 서비스로 인입되는 트래픽을 어떤 방식으로 분산시켜줄 지에 대한 추가적인 작업이 필요합니다.
Scale-up은 기존 서버의 스펙을 상향시켜 적용하는 방식입니다. 이 방식의 경우 기존 단일 서버로 설계되었을 때와 구조상 차이는 존재하지 않기 때문에 자원 운영 측면에서는 out방식보다 간단하지만 컴퓨팅 자원을 무한대로 추가할 수 없는 한계점이 존재하며, 이후 트래픽이 줄어든 상황이 올 경우 필요 이상의 자원 사용료를 지불해야 한다는 문제점이 있습니다.
때문에 PC자원을 증설할 때에는 트래픽의 변화에 유동적으로 대응할 필요가 있다면 scale-out방식이 더욱 적절한 선택지가 될 수 있습니다. 그렇다면 scale-out으로 자원이 증설하였을 때 고려해야하는 사항에 대해 추가적으로 알아보겠습니다.
물리적으로 서버 자원을 추가하였기 때문에 기존과 동일한 트래픽에 대하여 처리 능력이 향상되었습니다. 하지만 서버 자원이 추가되며 각각의 서버는 고유의 네트워크 인터페이스를 갖게됩니다.
이 경우 사용자 단말과 서버 사이에서 요청된 트래픽을 적절한 서버로 분배시켜줄 필요가 있습니다.(만약 트래픽이 분배되지 않으면, 기존 구조와 동일하게 단일 서버로 트래픽이 몰리기 때문에 scale-out의 효과를 볼 수 없게됩니다.)
이러한 트래픽 분산의 역할을 하는 하드웨어 혹은 소프트웨어를 LB(Load Balancer, 로드 밸런서)라고 합니다.
네트워크 계층을 이야기할 때 거론되는 대표적인 모델인 OSI 7계층 모델이 있다. 로드벨런서는 L2(데이터링크), L3(네트워크), L4(전송), L7(애플리케이션) 계층에 적용할 수 있습니다. 이중 가장 범용으로 적용되는 L4계층과 L7계층의 로드밸런서에 대하여 알아보겠습니다.
L4 Layer (Transport Layer, 전송 계층)는 TCP / UDP 프로토콜을 사용하여 종단간 통신을 제어합니다.
TCP 프로토콜의 IP 주소와 Header의 Port 정보를 활용하여 목적지를 확정하여 로드 밸런싱 역할을 수행할 수 있습니다.
예)
- 192.168.10.201:8080 --> 192.168.17.221
- 192.168.10.201:9090 --> 192.168.17.222
L7 Layer (Application Layer, 응용 계층)는 HTTP / HTTPS 프로토콜을 사용하여 통신을 제아할 수 있습니다.
L4 Layer에서 참조 가능한 정보에 비하여 보다 세밀한 로드밸런싱이 가능합니다.
예)
- 192.168.10.201/service-a --> 192.168.17.221
- 192.168.10.201/service-b --> 192.168.17.222
앞서 알아본 바와 같이 TCP/IP 정보만을 활용하여 nginx L4 로드 밸런서를 설정해보도록 하겠습니다. 실습 환경은 다음과 같이 virtualBox를 활용하여 구성하였습니다.
Host PC는 Load Balancer 역할을 하는 192.168.137.143으로만 요청을 전송하게됩니다. 요청을 받은 LB는 upstream으로 설정된 server 01과 server 02에 RR(Round Robin, 라운드로빈) 방식으로 응답을 받아 보여줍니다.
virtualBox로 로드밸런싱의 대상이 되는 두 개의 인스턴스를 생성하였습니다. 각자 고유의 내부 IP (192.168.137.141~142)를 할당 받았습니다.
또한 각각 nginx를 설치/실행하였고 index page 응답 시 각각 서버의 정보를 응답하게 됩니다.
load balancer(192.168.137.143) 역할을 하게 될 서버에서 각각의 웹 서버로 curl request에 대한 결과입니다. 응답 내용을 통하여 VM간 내부 IP를 통하여 정상적으로 통신하는 것을 확인하였습니다.
이제 앞서 137.143주소의 Load balancer 서버에 nginx를 설치하여 들어오는 요청을 RR방식으로 각각 137.141, 137.142서버로 트래픽이 분배되도록 하여봅시다.
virtual BOX의 포트포워딩 설정으로 127.0.0.1:11080으로 접속 시 load balancer서버의 80포트로 포워딩되도록 설정하였습니다.
nginx는 간단한 설정 파일 수정으로 로드밸런싱 설정을 할 수 있습니다.
/etc/nginx/conf.d 디렉토리 하위에 default.conf 파일을 새로 만들어(기존에 존재하는 경우 텍스트 추가) 아래와 같이 작성하였습니다.
upstream <alias> {
server {target IP or Domain}:{port};
....
}
이제 모든 VM을 실행하고 Host PC의 브라우저를 통해 localhost(127.0.0.1):11080/ 으로 요청을 보내겠습니다. 로드 밸런싱 방식은 default(Round Robin 방식)으로 설정되어있기 때문에 매 요청바다 서로 다른 서버의 응답을 확인할 수 있습니다.
정상적으로 동작하는 것을 확인할 수 있었습니다.
로드 밸런싱을 적용하기 위해서는 타겟이 되는 서버들의 health-check가 필수적입니다. 고가용성과 성능을 얻기 위해 적용하는 방식인 만큼, 타겟 서버가 응답하지 않아 서비스 이용이 어려워지는 사태를 방지해야하기 때문입니다.
다만 기본 nginx에서 제공하는 로드 밸런싱 기능에서는 타겟 서버의 health-check기능을 지원하지 않습니다.(유료 기능)
때문에 nginx 무료 버젼을 사용하여 로드 밸런싱 설정을 생각하고 있을 경우 오픈 소스 nginx health check 모듈의 적용 혹은 health-check기능을 제공하는 다른 오픈소스 로드 밸런서를 고려할 필요가 있습니다.