프로젝트 링크: https://github.com/f-lab-edu/Soccer-Friend
지난 포스팅에서 대규모 트래픽을 감당하기 위해 Scale Up방식을 통해 서버를 확장하기로 했다. 여러대의 서버로 트래픽을 분산시키기 위해서 로드밸런서를 구축해야한다. NCP와 AWS를 포함한 클라우드 서비스에서는 자체적으로 로드밸런서 서비스를 제공한다. 실제로 이들을 사용하면 편하게 로드밸런싱 환경을 구축할 수 있지만 클라우드 서비스에 구애받지 않는 웹서버를 구축하여 로드밸런싱을 구현해보도록 하자.
웹 서버는 HTTP 프로토콜을 통해 클라이언트 측에서 요청이 오면 정적컨텐츠를 제공하는 서버이다. 여기서 정적 컨텐츠는 HTML, 이미지, 파일 과 같은 다른 복잡한 비즈니스 로직 처리가 필요하지 않은 단순한 컨텐츠이다. 만약 웹서버가 정적 컨텐츠가 아닌 동적 컨텐츠를 요청받으면 해당 작업을 WAS에 전달하고 응답받아 WAS에서 처리한 결과물을 클라이언트로 전송해준다. 이런 웹서버에는 Apache와 Nginx가 있고 이 프로젝트에서는 Nginx를 사용하고자 한다.
WAS는 단순한 컨텐츠 전송 목적이 아닌 DB 조회와 같은 복잡한 비즈니스 로직을 수행하는 동적 컨텐츠를 제공하는 서버이다. WAS를 여러대 두어 서로 다른 비즈니스 로직을 처리하고 개발의 유지보수성을 높여주는 MSA 환경을 구축할 수도 있다. 이 프로젝트는 스프링 부트를 기반으로 서버프로그램을 제작하므로 기본적으로 TomCat을 WAS로 사용한다.
과거에는 Apache HTTP Server(이하 Apache)를 이용하여 웹서버를 구축했다. 하나의 요청에 하나의 프로세스가 대응하는 blocking I/O 방식으로 요청을 처리했고 이를 위해 fork와 kill을 통해 적절한 프로세스 개수를 조절한다. 하지만 세월이 흐르고 기술이 발전하면서 동시접속하는 사용자의 수가 늘어나고 처리해야할 데이터의 크기도 커진다. blocking 방식으로 모든 사용자의 요청을 처리하기 위해서 필요한 프로세스의 개수가 너무 많아진다. 프로세스를 생성할 때마다 메모리의 공간을 요구하고 결국 동시처리 성능이 떨어지게된다.
이를 개선하기 위해 Nginx는 비동기 이벤트 기반 구조를 통해 너무 많은 프로세스를 생성하지 않아도 다수의 요청을 처리할 수 있다. 이전 작업이 처리될 때까지 무한정 대기하는 것이 아닌 큐에 작업들을 저장해 두고 이전 작업이 끝날 때 마다 큐에서 가져와 작업을 처리하는 방식이다. 이를 통해 Apache처럼 불필요하게 프로세스를 많이 생성할 필요도 없고 낭비되는 프로세스 자원도 줄어든다.
이 프로젝트에서는 웹서버가 로드밸런서의 역할만 수행하기 때문에 Nginx로 웹서버로 두어 로드밸런서를 구축하고자한다. 추가적으로 WebServer에 대해 알아보았는데 LiteSpeed라는 제품도 성능이 좋아보여서 기회가 되면 알아보고싶다.
$ sudo apt update
$ sudo atp upgrade
apt 패키지 목록을 업데이트한다.
$ sudo apt install nginx
nginx를 설치한다.
지금 상태로 Nginx를 실행하면 오류가 발생한다. 그 이유는 Nginx는 기본적으로 80번 포트를 할당받아 외부와 통신하는데 우분투에서 80번 포트는 Apache가 사용하고 있기 때문이다.
$ netstat -nap | grep 80
위 명령어로 확인해보면 80번 포트를 Apache가 사용중인 것을 확인할 수 있다.
$ fuser -k -n tcp 80
80번 포트를 사용하는 프로세서를 kill 해줍시다. 물론 정상적으로 Apache의 stop 명령어를 사용하는 것이 권장되지만 운영체제마다 명령어가 다르니 kill 하는 방법으로 대체한다.
$ sudo service start nginx
위 명령어로 Nginx를 실행해준다. 혹시나 오류가 발생한다면
$ sudo service status nginx
해당 명령어로 Nginx의 상태를 확인하고 오류메시지를 확인해서 처리하면 됩니다.
$ vi etc/nginx/nginx.conf
nginx 설정파일을 vim 에디터로 수정해보자. 이 때는 공식문서를 참고하면 도움이 된다.
다음과 같이 nginx.conf 파일을 수정해주면 된다. 각 키워드에 대한 설명은 공식문서에 자세하게 나와있고 간략하게 설명하고 넘어가자. http 블록은 http와 관련된 설정들을 작성해주면 된다. 대부분의 설정이 http 블록에서 작성된다.myapp1이라는 upstream 블록을 생성해준다. 여기서 upstream 블록은 Nginx가 요청을 보낼 서버들의 주소를 작성해준다.
server <WAS 공인IP>/<포트번호>;
형식으로 추가해주면된다. 로드밸런싱 알고리즘도 작성해줄 수 있는데 작성해주지 않으면 default로 라운드로빈 알고리즘이 적용된다.
server 블록은 외부와 통신하기 위한 정보를 작성해주면 됩니다. listen 80;
은 80번 포트로 외부에서 접속할 수 있다는 의미이며 location /
은 http 요청이 오면 해당 upstream 블록에 존재하는 server로 요청을 보내라는 의미입니다.
nginx의 공인ip의 80번 포트로 접속해보면 정상적으로 WAS와 통신할 수 있음을 확인할 수 있습니다.
이 프로젝트는 모놀리식 아키텍처로 설계되어 모든 사용자의 요청을 아무 WAS에 보내도 상관이 없지만 마이크로서비스 아키텍처로 구현한다면 특정 URL에 따라 해당 비즈니스로직을 처리할 수 있는 WAS로 요청을 보낼 수 있다. 추후에 MSA 아키텍처로 프로젝트를 진행할 기회가 생긴다면 이런 방식으로 트래픽을 분산시켜 유지보수와 트래픽 대응에 유연한 아키텍처를 설계해보고 싶다.
참고 문헌
https://code-lab1.tistory.com/199
https://nginx.org/en/docs/http/load_balancing.html
https://bentist.tistory.com/80