

말 그대로 서버에 걸리는 부하(Load)를 알맞게 잘 분배하여(Balancing) 시스템의 성능을 최적화하고, 장애를 방지하며, 안정적인 서비스를 제공하는 기술이다.
좀 더 자세히 정리해보면
이렇게 크게 4가지의 이점이 존재한다.
로드밸런싱은 크게 3가지 종류로 나뉜다.

저번 해커톤에서 구현했던 MVP의 시스템 아키텍쳐이다. AWS Cloud 섹션 내부의 Docker Compose 섹션을 보면 Backend 컨테이너 3개가 존재하고, Nginx 로드 밸런서가 클라이언트 요청을 이 3개의 서버 컨테이너들에 분산 처리하고 있음을 알 수 있다.
그렇다면 실제로 컨테이너를 3개 띄우는 건 어떻게 하는 지 알아보자!
이번 프로젝트에서는 redis, certbot, nginx 등 여러 개의 이미지 컨테이너를 한번에 관리하기 때문에, docker-compose를 사용했다. 때문에 docker-compose.yml 파일에 설정된 서버 컨테이너를 기준으로 설정을 시작한다.
services:
nginx:
image: nginx:latest
container_name: nginx
ports:
- "80:80"
- "443:443"
volumes:
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
- ./nginx.conf:/etc/nginx/nginx.conf
networks:
- backend
depends_on:
- certbot
- backend
command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"
certbot:
image: certbot/certbot
container_name: certbot
volumes:
- ./data/certbot/conf:/etc/letsencrypt
- ./data/certbot/www:/var/www/certbot
entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
redis:
image: redis:latest
container_name: redis-container
ports:
- "6379:6379"
volumes:
- redis_data:/data
networks:
- backend
backend:
image: blaybus3team/blaybus-backend:latest
expose:
- "8080"
networks:
- backend
environment:
- SPRING_PROFILES_ACTIVE=prod
restart: always
networks:
backend:
driver: bridge
volumes:
redis_data:
필자는 현재 서버 컨테이너를 'backend' 라는 이름으로 정의해두었다. 포트는 8080으로 설정해두었고(Docker 네트워크 내부 통신용), 컨테이너가 연결되는 네트워크도 똑같이 'backend'로 지정해두었다. 또한 restart: always 옵션을 통해 컨테이너가 중지될 시 무조건 다시 시작하도록 해 두었다.
events {
worker_connections 1024;
}
http {
server {
listen 80;
server_name blarybus.seunghooo.p-e.kr;
location /.well-known/acme-challenge/ {
allow all;
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
upstream backend_servers {
server ubuntu_backend_1:8080 max_fails=3 fail_timeout=30s;
server ubuntu_backend_2:8080 max_fails=3 fail_timeout=30s;
server ubuntu_backend_3:8080 max_fails=3 fail_timeout=30s;
}
server {
listen 443 ssl;
server_name blarybus.seunghooo.p-e.kr;
ssl_certificate /etc/letsencrypt/live/blarybus.seunghooo.p-e.kr/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/blarybus.seunghooo.p-e.kr/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1h;
chunked_transfer_encoding on;
location /api {
proxy_pass http://backend_servers;
proxy_connect_timeout 300;
proxy_send_timeout 300;
proxy_read_timeout 300;
send_timeout 300;
proxy_buffering off;
proxy_request_buffering off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
}
upstream backend_servers {
server ubuntu_backend_1:8080 max_fails=3 fail_timeout=30s;
server ubuntu_backend_2:8080 max_fails=3 fail_timeout=30s;
server ubuntu_backend_3:8080 max_fails=3 fail_timeout=30s;
}
설정 파일에서 로드밸런싱 과정의 장애 처리 부분을 정의해둔다.
먼저 backend_servers라는 업스트림 그룹을 정의한다.
(upstream이란 강의 상류를 뜻한다. 즉 위에서 아래로 '뿌려주는' 것이다.)
요청은 backend의 8080 포트로 보내고, max_fails는 최대 실패 횟수를 정의하는 것으로 여기서는 3번 연속 요청 실패 시 해당 서버를 사용하지 않도록 한다. fail_timeouts는 서버 실패 판정 후 쿨타임으로, 30초 동안 해당 서버로 요청을 보내지 않도록 한다.
설정을 모두 마쳤으니 서버 컨테이너를 실행해보자.
필자는 이번에 3개의 컨테이너를 두기로 했으므로 3개의 컨테이너를 가동한다.
docker-compose up --scale backend=3 -d
이렇게 하면 backend 컨테이너가 3개 실행되고, Docker 내부 DNS가 자동으로 로드밸런싱을 수행하게 된다.
로드밸런싱 방식은 라운드로빈(Round Robin) 방식이 default값이고, 필요에 따라 다양한 방식을 정의하여 사용할 수 있다.

3개의 컨테이너가 잘 실행되고 있음을 알 수 있다.
컨테이너 이름이 ubuntu_backend_1인 것은 Docker Compose가 자동으로 설정해준 것이다.
Docker Compose는 기본적으로

의 방식으로 컨테이너 이름을 생성한다.