모모팀 인프라 개선기 2편 (로드 밸런싱 도입)

2022년 10월 23일

TOC

1. 로드 밸런싱(Load Balancing)이란?

서비스의 규모가 커지고 이용자 수가 증가하게 된다면 서비스 동작이 원활하게 이루어지지 않을 수 있다. 특히 하나의 WAS 서버만을 이용할 경우 해당 서버가 모든 요청을 감당해야할 것이기에 많은 부하가 걸릴 경우 서비스 전체가 동작을 멈추는 단일 장애점(SPOF)가 생기게 된다.

서버에서 많은 요청을 감당할 수 있게 대처할 수 있는 방법은 Scale-up과 Scale-out방식이 존재한다. 먼저 Scale-up방식은 기존 서버의 성능을 향상하는 방식이다. 하지만 서버의 성능 향상은 하드웨어 상의 한계가 있을 뿐더러 성능을 향상할 수록 기하급수적으로 비용이 증가하게 된다. 또한 여전히 하나의 서버만을 운영하기에 SPOF의 문제가 존재한다.

두번째 방법으로는 Scale-out방식이 있다. 해당 방법은 기존의 서버와 동일하거나 낮은 성능의 서버를 증설하는 방법이며 이것이 바로 로드 밸런싱이다.

Untitled

로드 밸런싱은 말 그대로 부하(Load)를 여러 컴퓨터에 분산(Balancing) 시켜주는 기술이다. 즉, 하나의 서버로 모든 트래픽을 감당하기 어려워 여러대의 서버에 트래픽을 분산시켜주는 방법을 로드 밸런싱이라 한다. 로드 밸런싱을 할 경우 요청을 받을 수 있는 서버가 2개 이상이어서 해당 계층에 대해서는 SPOF의 문제도 해결되게 된다.

2. 로드 밸런싱 종류

로드 밸런싱은 실행되는 네트워크 계층에 따라 L4 로드밸런서와 L7로드 밸런서로 나뉜다. 네트워크 4계층인 전송 계층에서 실행된다면 L4로드밸런서로 불리며 7계층인 애플리케이션 계층에서 실행되면 L7로드밸런서라고 불린다.

L4 로드 밸런싱

  • Layer 4인 전송 계층에서 동작하는 로드 밸런서로 네트워크 계층(IP, IPX)이나 전송 계층(TCP, UDP)의 정보(IP주소, 포트번호, MAC주소, 전송 프로토콜)를 바탕으로 로드를 분산한다.
  • 데이터의 안을 들여다보지 않고 패킷 레벨에서 로드를 분산하기에 속도가 빠르고 효율이 높다.
  • 데이터의 내용을 복호화할 필요가 없기에 안전하다.
  • L7보다 가격이 저렴하다.
  • 패킷의 내용을 살펴볼 수 없기에 섬세한 라우팅이 불가능하고 사용자의 IP가 바뀌면 연속적인 서비스를 제공하기 어렵다는 단점이 있다.

L7 로드 밸런싱

  • Layer 7인 응용 계층에서 동작하는 로드 밸런서로 애플리케이션 계층(HTTP, FTP, SMTP)에서 로드를 분산하기 때문에 HTTP 헤더, 쿠키 등과 같은 사용자의 요청을 기준으로 특정 서버에 트래픽을 분산하는 것이 가능하다.

    • TCP/ UDP정보 뿐만 아니라 HTTP의 URI, FTP의 파일명, 쿠키 정보 등을 바탕으로 한다.
    • 패킷의 내용을 확인하고 해당 내용에 따라 로드를 특정 서버에 분배하는 것이 가능하다.
  • 상위 계층에서 로드를 분산하기에 섬세한 라우팅이 가능하다.

    • URl에 따라 부하를 분산시키거나, HTTP 헤더의 쿠키 값에 따라 부하를 분산하는 등의 클라이언트의 요청을 세분화하여 서버에 전달할 수 있다.
  • 캐싱 기능을 제공한다.
  • 비정상적인 트래픽을 필터링해 서비스의 안정성이 높다.

    • DoS/DDoS와 같은 비정상적인 트래픽을 필터링할 수 있어 네트워크 보안 분야에서도 활용되고 있다.
  • 패킷의 내용을 복호화하기에 L4보다 더 많은 비용을 지불해야하며 클라이언트가 로드 밸런서와 인증서를 공유하기 때문에 공격자가 로드 밸런서를 통해 클라이언트의 데이터에 접근할 위험성이 있다는 단점이 있다.

3. 모모팀이 로드밸런싱을 도입한 이유

모모팀이 로드밸런싱을 초기에 도입했던 이유는 여러 무중단 배포 방법을 진행해보고자 도입하였습니다. 하지만 여러 무중단 배포 방식을 최종적으로 블루-그린 배포 방식을 택하여 로드밸런싱의 필요성이 없어졌으나 이를 유지한 이유는 아래와 같습니다.

  1. ✨ 무중단 배포 도입시 발생하는 자원의 낭비를 효율적으로 사용 ✨ 
  2. 성능 개선
  3. WAS 레벨의 SPOF 제거

무중단 배포 도입시 발생하는 자원의 낭비를 효율적으로 사용

적용하기로 한 블루그린 배포는 배포를 하기 위해서 2N개의 인스턴스가 필요하며, 평상시에는 N개의 인스턴스가 사용되지 않고 방치된다는 단점이 존재한다. 우리는 이를 어떻게 효율적으로 해결할 수 있을지 생각해본 결과, 쉬게 되는 인스턴스에도 WAS 서버를 올려 로드 밸런싱을 하며 부하의 분산과 WAS 레벨에서의 SPOF의 제거라는 이점을 얻고 블루그린 배포는 컨테이너 기반의 포트바인딩으로 진행하자는 계획을 세우게 됐다. 즉, 블루그린 배포를 포트바인딩으로 구현하며 평상시 사용되지 않는 서버를 로드밸런싱으로 활용하기로 결정하였다.

📌 포트바인딩으로 배포 진행 중 한 개의 인스턴스에 2개의 WAS Container가 실행될 때 발생할 수 있는 부하 문제는 컨테이너의 자원 사용량 제한으로 해결하였다. 이는 1개의 인스턴스를 사용하지 않고 방치하는 것보다 컨테이너의 자원 사용량을 제한하더라도 2개의 인스턴스에서 부하를 나눠 받는 것이 자원을 더욱 효율적으로 많이 사용하는 방법이라 판단하였기에 이러한 방법을 택했다.

  • 사용하는 CPU 사용량만을 비교해봐도 1개의 인스턴스에서 2개의 Core를 사용하는 것과 2개의 인스턴스에서 각각 1.8개의 Core를 사용해 총 3.6개의 Core를 가용하는 것을 비교해보면 후자의 선택이 더 좋다 생각됐다.

성능 개선

Untitled

모모팀의 인프라는 웹 서버인 Nginx는 하나의 WAS 서버를 가르키고 있다. 이러한 구조는 많은 요청이 몰릴 경우, 하나의 WAS서버에서 모든 요청을 처리해야 하여 부담이 커진다. 부하를 주며 WAS서버의 CPU사용량을 모니터링 해본 결과 User Thread의 수가 많아 CPU의 사용은 거의 항상 100%를 사용하고 있었으며, LoadAverage도 계속 증가하는 것을 확인할 수 있었다.

📌 Load Average란?

  • Waiting Queue에서 CPU의 자원을 기다리는 지연되는 테스크의 수이다.

Untitled

Untitled

만약 더 많은 유저가 서비스를 이용할 경우 WAS서버가 버티지 못할 수 있다. WAS에서 더 많은 요청을 처리하도록 하는 가장 간단한 방법은 Scale-up방식이다. 하지만 Scale-up의 경우 현재 우아한형제들에서 제공받는 EC2는 t4g.micro로 한정되어있기에 진행할 수 없었다. 그래서 서버를 증설하는 Scale-out방식인 로드 밸런싱을 고려하게 되었다.

📌 서비스의 전반적인 성능으로만 생각하면 WAS레벨에서 로드밸런싱을 도입하면 WAS 서버의 부하는 줄어들지만, 데이터베이스 부분에서 병목 현상이 발생하여 서비스 성능의 큰 향상은 일어나지 않을 것이다. 이를 해결할 수 있는 방법으로는 데이터베이스 이중화와 캐시를 도입하는 방법이 존재한다. 둘 다 도입하는 것이 물론 좋지만…학습 비용과 적용 시간을 고려하며 추후 도입을 결정해보려 한다.

WAS 레벨의 SPOF 제거

현재의 WAS서버는 중단되었을 때, 모든 서비스가 이용할 수 없어지는 SPOF(single point of failure, 단일 장애점)이 된다. 물론 현재의 구조에는 웹서버와 DB서버도 SPOF이다. 로드 밸런싱을 구축하면 WAS레벨에서의 SPOF가 제거할 수 있다.

4. NGINX를 통한 로드밸런싱

NGINX는 로드 밸런싱을 쉽게 구축하는 기능을 제공하고 있다. Nginx의 초기설정부터 로드 밸런싱을 설정하기기까지의 과정을 간단히 살펴보겠다.

4.1. Nginx 기본 설정하기

Nginx설정은 /etc/nginx/ 경로에 위치한 nginx.conf 파일의 http안에서 할 수 있다. 먼저 해당 파일에 접속해보겠다.

$ vi /etc/nginx/nginx.conf

nginx.conf 파일의 기본 값은 아래와 같다.

Untitled

Nginx의 설정은 직접 http 블록에 넣어줘도 되지만 include를 통해 파일을 가져오도록 할 수 있다. 별다른 설정을 하지 않았다면 nginx는 기본적으로 위와 같이 include /etc/nginx/site-enabled/*; 설정을 갖고 있을 것이다. 만약 해당 설정이 되어있지 않다면 아래의 코드를 추가하면 된다.

http {
	include /etc/nginx/site-enabled/*;
}

include를 통해 /etc/nginx/site-enabled/ 경로의 설정을 읽어오도록 하였으니 해당 경로에 추가 설정 파일을 생성하면 된다.

파일의 이름은 중요하지 않다. 하지만 다른 설정 파일과 충돌이 발생할 수 있기에 기존 것을 없애고 한가지 파일을 만드는 것이 좋다.

4.2. 설정 파일 세팅하기

설정 파일은 기존의 모모팀의 Nginx설정 파일을 통해 설명하겠다. 기존에 모모팀의 Nginx설정 파일은 아래와 같았다.

server {
	listen 443 ssl;
	server_name api.moyeora.site;

	// https인증을 진행 코드
	ssl_certificate /home/ubuntu/momokeys/fullchain.pem;
	ssl_certificate_key /home/ubuntu/momokeys/privkey.pem;

	location / {
		proxy_pass {요청을 보낼 WAS 서버 주소};
	}
}

위의 설정 파일의 동작을 간단히 설명하면 api.moyeora.site 도메인 주소의 요청이 443포트로 요청이 들어왔을 때 https ssl인증을 진행 후, location인 / 경로의 proxy_pass 주소로 요청을 전달하는 설정이 되어있다.

자세한 설정은 Nginx의 홈페이지를 참고하길 바란다.

Beginner's Guide

이제 해당 파일에 로드 밸런싱 코드를 추가해보겠다.

4.3. 로드 밸런싱 코드 추가하기

로드 밸런싱을 구축하는 방법은 간단하다. 설정 파일에 upstream을 설정 후 proxy_pass에 세팅해둔 upstream으로 설정해두기만하면 된다.

upstream <업스트림 이름> {
	<로드밸런스 타입: defulat는 round-robin>
	server <host1>:<port1>
	...
	server <host2>:<port2>
}

server {
	...
	location <url>{
		proxy_pass http://<업스트림 이름>
	}
	...
}

upstream에는 로드밸런싱을 하기 위해 분배해줄 서버와 부하를 분산해줄 알고리즘을 세팅해줘야 한다. 위의 예시 코드와 같이 첫 라인에는 로드 밸런스 타입을 적어주고 그 아래 줄 부터는 부하를 분산해줄 WAS서버의 주소를 작성해주면 된다.

Nginx에서 제공하는 로드 밸런스 알고리즘은 아래와 같다. 아무런 설정을 하지 않는다면 기본 설정값인 라운드 로빈으로 설정된다.

  • round-robin(디폴트) - 요청을 순서대로 돌아가면서 분배한다.
  • hash - 해시한 값으로 분배한다 쓰려면 hash <키> 형태로 쓴다. ex)hash $remoteaddr <- 이는 iphash와 같다.
  • ip_hash - 요청이 클라이언트 IP주소로 해싱을 진행한 후, 한번 요청 받은 서버가 있을 때 해당 서버에만 요청을 분배한다.
  • random - 랜덤으로 분배한다.
  • least_conn - 연결수가 가장 적은 서버를 선택해서 분배, 근데 가중치를 고려함
  • least_time - 연결 수가 가장 적으면서 평균 응답시간이 가장 적은 쪽을 선택해서 분배한다. (Nginx Plus에서만 가능)

이제 로드밸런싱 설정을 모모팀의 Nginx설정에 추가해보겠다. 모모팀에서 사용하는 WAS서버는 2개이기에 2개의 서버만을 추가하였으며 로드밸런스 알고리즘의 경우 디폴트인 라운드로빈으로 설정하였다.

server {
	listen 443 ssl;
	server_name api.moyeora.site;

	upstream momo_server {
		server {server1_ip}:{port}
		server {server2_ip}:{port}
	}

	// https인증을 진행 코드
	ssl_certificate /home/ubuntu/momokeys/fullchain.pem;
	ssl_certificate_key /home/ubuntu/momokeys/privkey.pem;

	location / {
		proxy_pass momo_server;
	}
}

5. 마치며

이번 포스트에서는 로드밸런싱에 대해 알아본 후, 모모팀 서비스에 적용한 과정에 대해 살펴보았다. 적용을 완료한 후의 모모팀의 인프라 구조는 아래와 같이 변경되었다.

Untitled

서비스에 로드 밸런싱을 구축하며 기존에 WAS 레벨에서 존재하였던 SPOF문제도 해결하였고 WAS서버의 부하를 분산시켜 애플리케이션이 기존보다 더 많은 부하도 버틸 수 있게 된 것을 확인하였다.

이렇게 프로젝트의 로드 밸런싱 구축은 끝이 났다. 다음 포스트에서는 프로젝트에 무중단 배포를 진행한 과정에 대해 정리해보겠다.

📚 Reference

Buy me a coffeeBuy me a coffee
Written by

@Seongwon

기술공유를 통해 새로운 가치 창조을 추구하는 백엔드 개발자 오성원입니다.
©SeongwonOh