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

devkev00·2025년 3월 11일

🔥 What I've Learned

목록 보기
9/9
post-thumbnail

1. 로드밸런싱 (부하 분산)

말 그대로 서버에 걸리는 부하(Load)를 알맞게 잘 분배하여(Balancing) 시스템의 성능을 최적화하고, 장애를 방지하며, 안정적인 서비스를 제공하는 기술이다.

좀 더 자세히 정리해보면

  1. 성능 향상: 요청을 여러 서버에 분산하여 빠르고 효율적인 응답을 제공.
  2. 가용성 증가: 일부 서버에 장애가 발생해도 다른 서버가 서비스 유지.
  3. 확장성 제공: 서버를 유연하게 추가하거나 제거하여 트래픽을 효율적으로 관리.
  4. 장애 복구: 비정상 서버를 자동으로 제외하고 정상 서버로만 트래픽 분산.

이렇게 크게 4가지의 이점이 존재한다.

2. 종류?!

로드밸런싱은 크게 3가지 종류로 나뉜다.

  1. 하드웨어적인 로드밸런싱
  • 전용 장비(하드웨어)를 사용하여 로드밸런싱을 수행하는 것을 말한다.
  • F5, Citrix NetScaler 등이 그 예시이다.
  1. 소프트웨어적인 로드밸런싱
  • 소프트웨어 설정을 통해 로드밸런싱을 수행하는 것을 말한다.
  • NGINX, HAProxy, Apache HTTP Server 등이 있다.
    (필자는 이번에 NGINX 로드 밸런서를 이용했다)
  1. 클라우드 기반 로드밸런싱
  • 클라우드 서비스에서 제공하는 로드밸런서를 이용하는 것을 말한다.
  • AWS ELB, Azure Load Balancer, Google Cloud Load Balancer 등이 있다.

3. 로드밸런싱, 직접 해보기!!

저번 해커톤에서 구현했던 MVP의 시스템 아키텍쳐이다. AWS Cloud 섹션 내부의 Docker Compose 섹션을 보면 Backend 컨테이너 3개가 존재하고, Nginx 로드 밸런서가 클라이언트 요청을 이 3개의 서버 컨테이너들에 분산 처리하고 있음을 알 수 있다.

그렇다면 실제로 컨테이너를 3개 띄우는 건 어떻게 하는 지 알아보자!

이번 프로젝트에서는 redis, certbot, nginx 등 여러 개의 이미지 컨테이너를 한번에 관리하기 때문에, docker-compose를 사용했다. 때문에 docker-compose.yml 파일에 설정된 서버 컨테이너를 기준으로 설정을 시작한다.

3-1: 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 옵션을 통해 컨테이너가 중지될 시 무조건 다시 시작하도록 해 두었다.

3-2 nginx.conf 파일 설정

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 명령어로 컨테이너 실행 및 확인

설정을 모두 마쳤으니 서버 컨테이너를 실행해보자.

필자는 이번에 3개의 컨테이너를 두기로 했으므로 3개의 컨테이너를 가동한다.

docker-compose up --scale backend=3 -d

이렇게 하면 backend 컨테이너가 3개 실행되고, Docker 내부 DNS가 자동으로 로드밸런싱을 수행하게 된다.

로드밸런싱 방식은 라운드로빈(Round Robin) 방식이 default값이고, 필요에 따라 다양한 방식을 정의하여 사용할 수 있다.

3개의 컨테이너가 잘 실행되고 있음을 알 수 있다.

컨테이너 이름이 ubuntu_backend_1인 것은 Docker Compose가 자동으로 설정해준 것이다.
Docker Compose는 기본적으로

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

profile
Focusing on what I can change

0개의 댓글