로드 밸런싱이란 서버가 처리해야 할 요청(Load)을 여러 대의 서버로 나누어(Balancing) 처리하는 것을 의미한다.
여러 사용자의 요청들이 한 대의 서버로 집중되지 않도록 관리해 각각의 서버가 효율적으로 가동되도록 하는 것이 목적이다.
그리고 이를 수행하는 장치를 로드밸런서라고 한다.
대규모 트래픽에 대응할 수 있는 방법은 다음과 같이 두 가지로 나뉜다.
여기서 Scale-out 방식을 통해 증가한 트래픽에 대처하기로 했다면 여러 대의 서버로 트래픽을 균등하게 분산해주는 로드 밸런싱이 필요하게 된다.
로드 밸런싱에는 L4(전송 계층) 로드 밸런싱과 L7(응용 계층) 로드 밸런싱이 가장 많이 활용된다.
AWS는 다양한 유형의 로드밸런서를 제공한다.
주로 사용되는 3가지의 로드밸런서는 다음과 같다.
각 로드밸런서를 살펴보고 서로 어떻게 다른지 알아보자.
NLB와 ALB의 차이점을 다음 표와 같이 요약할 수 있다.
기능 | Network Load Balancer (NLB) | Application Load Balancer (ALB) |
---|---|---|
지원 프로토콜 | TCP, UDP, TLS | HTTP, HTTPS |
네트워크 계층 | Layer 4 (전송 계층) | Layer 7 (응용 계층) |
라우팅 기준 | IP 주소, 포트 | URL 경로, 도메인 이름, HTTP 헤더/메소드 |
성능 | 높은 처리량과 낮은 지연 | HTTP/HTTPS 트래픽에 최적화됨 |
고정 IP | 가능 | 불가능 |
타킷 health check | 가능 | 가능 |
사용 예시 | 실시간 스트리밍 서비스, 고성능 데이터베이스 서버 | MSA, 복잡한 웹 애플리케이션 |
HAProxy는 High Availability Proxy로 말그대로 고가용성 기능을 제공하는 오픈소스 로드 밸런서이다.
기존의 하드웨어 스위치를 대체하는 소프트웨어 로드밸런서로, 네트워크 스위치에서 제공하는 L4, L7 기능 및 로드밸런싱 기능을 제공한다.
HAProxy는 기본적으로 reverse proxy 형태로 동작한다.
우리가 브라우저에서 사용하는 proxy는 클라이언트 앞에서 처리하는 기능으로, forward proxy라 한다.
그와 반대로 reverse proxy는 서버 앞에 있으면서 서버로 들어오는 요청을 대신 받아서 서버에 전달하고 요청한 곳에 그 결과를 다시 전달한다.
'고가용성'은 서버, 네트워크, 프로그램 등 시스템이 계속 정상 운영될 수 있는 특성을 의미한다.
HAProxy에서는 다음과 같은 HAProxy 인스턴스 설정으로 고가용성을 구성한다.
HAProxy의 옵션을 설정하려면 haproxy.cfg
파일을 수정해야 한다. (/usr/local/etc/haproxy/haproxy.cfg
경로에 위치)
이 설정 파일은 다음과 같이 크게 네 부분으로 나뉜다.
global
: HAProxy 인스턴스 전체에 적용되는 전역설정이다. 주로 로그, 프로세스 관리, 보안 관련 설정이 포함된다.
default
: 모든 frontend
및 backend
섹션에 적용될 기본 설정을 지정한다. 주로 연결 타임아웃, 로그 설정, 프로토콜 모드(HTTP, TCP 등)와 같은 기본적인 네트워크를 설정이 포함된다. 기본값을 설정해놓음으로써 설정 중복을 줄인다.
frontend
: 클라이언트로부터의 인바운드 연결을 정의한다. 포트와 IP 주소 바인딩, 사용할 SSL/TLS 설정, HTTP 관련 설정 등 클라이언트 연결을 처리하기 위한 규칙과 조건을 설정한다.
backend
: 프론트엔드로부터 전달받은 요청을 실제로 처리할 서버 그룹을 정의한다. 로드 밸런싱 알고리즘, 서버의 주소 및 포트, health check 설정 등 백엔드 서버의 작동 방식을 설정한다.
다음과 같이 작성할 수 있다.
# HAProxy 인스턴스 전체에 적용되는 설정 정의
global
stats socket /var/run/api.sock user haproxy group haproxy mode 660 level admin expose-fd listeners
log stdout format raw local0 info
# frontend 및 backend 섹션에 적용될 기본 설정을 정의
defaults
mode http
timeout client 10s
timeout connect 5s
timeout server 10s
timeout http-request 10s
log global
# HAProxy 상태페이지 설정
frontend stats
bind *:8404
stats enable
stats uri /
stats refresh 10s
# 실제 트래픽을 처리할 프론트엔드 정의
frontend myfrontend
bind :80
default_backend webservers
# 로드 밸런싱을 수행할 백엔드 서버 그룹을 정의
backend webservers
server web1 web1:8080 check
server web2 web2:8080 check
server web3 web3:8080 check
출처 : https://www.haproxy.com/blog/how-to-run-haproxy-with-docker#the-performance-impact-of-running-docker
뒤에 이 haproxy.cfg
파일을 사용하여 HAProxy를 실행해보려고 한다.
HAProxy는 TCP 또는 HTTP의 두 가지 모드로 실행될 수 있다.
TCP 모드에서 작동할 때 L4(전송계층)모드이고, HTTP 모드에서 작동할 때는 L7(응용계층)모드이다.
haproxy.cfg
파일에서 이 모드를 지정할 수 있다.
다음과 같이 haproxy.cfg
에서 mode
를 tcp
로 설정하여 L4 모드로 지정한다.
defaults
mode tcp
다음과 같은 특징을 가진다.
다음과 같이 haproxy.cfg
에서 mode
를 http
로 설정하여 L7 모드로 지정한다.
defaults
mode http
다음과 같은 특징을 가진다.
L4 모드와 L7 모드 설정은 예시와 같이 default
섹션 뿐만 아니라 frontend
와 backend
섹션에서도 설정 가능하다.
이렇게 되면 default
섹션의 값이 덮어써진다.
단, 연결되어 있는 frontend
와 backend
섹션은 동일한 모드로 설정되어야 한다.
섹션에서 모드를 다르게 설정할 경우 일부는 TCP 모드로, 다른 일부는 HTTP 모드로 작동할 수 있다.
백엔드 서버들의 상태를 모니터링하여, 서버가 정상적으로 작동 중인지 확인한다.
haproxy.cfg
파일의 backend
섹션에서 설정한다.
다음과 같이 서버 뒤에 check
키워드를 입력하여 HAProxy가 해당 서버에 대해 정기적으로 헬스 체크할 것을 지시한다.
backend webservers
server web1 web1:8080 check # health check
server web2 web2:8080 check
server web3 web3:8080 check
HAProxy에서는 다음과 같은 로드밸런싱 알고리즘을 설정할 수 있다. 괄호 안은 HAProxy 설정 파일(haproxy.cfg
)에서 설정할 때 사용하는 키워드이다.
Round Robin(roundrobin
): 각 요청을 서버의 가중치에 따라 분배하면서도, 순차적으로 할당한다. (각 서버에 요청을 순차적으로 분배하는 일반적 의미의 round robin 방식과 다르다.) 설정파일에서 다음과 같이 설정할 수 있다.
Static Round Robin(static-rr
): Round Robin 방식에서 가중치를 설정을 무시하고 모든 서버에 동등하게 분배한다. (일반적 의미의 round robin 방식)
Least Connections(leastconn
): 현재 활성 연결이 가장 적은 서버에 새 연결을 할당한다.
Source(source
): 클라이언트의 IP 주소를 기반으로 서버를 선택하여, 동일한 클라이언트의 요청은 항상 같은 서버로 전달된다.
URI(uri
): 들어오는 각 HTTP 요청의 URI(Uniform Resource Identifier)를 기반으로 해시값을 계산하고, 이 해시값을 사용하여 요청을 처리할 서버를 결정한다. 이에 따라 동일한 URI의 요청은 같은 서버로 라우팅되게 한다.
URL Parameter(url_param
): URL 내의 특정 파라미터를 기반으로 로드 밸런싱을 수행한다.
이러한 로드밸런싱 알고리즘을 설정파일의 backend
섹션에서 정의할 수 있다.
balance <로드밸런스 알고리즘>
키워드를 사용하여 정의한다.
다음과 같이 작성할 수 있다.
backend webservers
balance roundrobin # 로드밸런싱 알고리즘 지정
server web1 web1:8080 check weight 1 # 가중치 지정
server web2 web2:8080 check weight 2
server web3 web3:8080 check weight 3
roundrobin
방식을 지정했고, 각 서버에 weight
키워드를 사용하여 가중치를 부여하였다.
따로 로드밸런싱 알고리즘을 지정하지 않을 시엔 roundrobin
이 기본값이다.
https://www.haproxy.com/blog/how-to-run-haproxy-with-docker#the-performance-impact-of-running-docker 를 참고하여 실습해보았다.
먼저 docker-compose.yaml 파일에 컨테이너들(haproxy
, web1
, web2
, web3
)과 그 컨테이너들을 묶는 네트워크 mynetwork
를 정의한다.
서버 이미지는 들어오는 요청을 받아 요청에 담긴 정보를 그대로 응답으로 반환하는 에코서버 jmalloc/echo-server
를 사용했다. (네트워킹, 로드 밸런싱, 리버스 프록시 설정 등을 테스트하고 검증할 때 사용된다고 한다.)
# haproxy 실행을 위한 docker-compose.yaml 파일
version: '3.8'
services:
web1:
image: jmalloc/echo-server:latest
networks:
- mynetwork
web2:
image: jmalloc/echo-server:latest
networks:
- mynetwork
web3:
image: jmalloc/echo-server:latest
networks:
- mynetwork
haproxy:
image: haproxytech/haproxy-alpine:2.4
volumes:
- ./haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro
ports:
- "80:80"
- "8404:8404"
networks:
- mynetwork
networks:
mynetwork:
driver: bridge
이어서 위에서 설명했던 설정파일 haproxy.cfg
도 docker를 실행하는 디렉토리에 생성하여 다음과 같이 작성한다.
global
stats socket /var/run/api.sock user haproxy group haproxy mode 660 level admin expose-fd listeners
log stdout format raw local0 info
defaults
mode http
timeout client 10s
timeout connect 5s
timeout server 10s
timeout http-request 10s
log global
frontend stats
bind *:8404
stats enable
stats uri /
stats refresh 10s
frontend myfrontend
bind :80
default_backend webservers
backend webservers
server web1 web1:8080 check
server web2 web2:8080 check
server web3 web3:8080 check
이렇게 두개의 파일을 작성하면 다음과 같은 파일구조가 된다.
.
├── docker-compose.yaml
└── haproxy.cfg
다음 그림과 같이 구성된다.
이제 docker compose up
명령어를 실행하여 정의된 서비스를 실행한다.
설정파일에 정의한대로
http://localhost 에서는 다음과 같이 에코 서버의 기본 페이지가 보여진다.
Request served by aa69a0060770
에서 aa69a0060770
는 컨테이너 ID로, 현재 어떤 서버가 요청을 처리하는지 이를 통해 확인할 수 있다.
위의 설정에서는 따로 로드밸런싱 알고리즘을 지정하지 않아 기본값인 Round robin 방식이 적용되었고, 가중치도 지정하지 않아 모두 1이므로 새로고침할 때마다 로드밸런싱에 의해 서버가 변경되는 것을 확인할 수 있었다.
http://localhost:8404 에서는 다음과 같이 HAProxy 상태페이지를 볼 수 있다.
이 화면에서는 현재 HAProxy 인스턴스의 상태와 성능에 대한 다양한 실시간 정보를 확인할 수 있다. HAProxy에 연결된 서버 web1
, web2
, web3
가 보여진다. 이 외에도 다음과 같은 주요 정보들을 보여준다.
https://tecoble.techcourse.co.kr/post/2021-11-07-load-balancing/
https://avinetworks.com/glossary/round-robin-load-balancing/
https://velog.io/@pu1etproof/%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EC%8A%A4%ED%84%B0%EB%94%94-1%EC%A3%BC%EC%B0%A8-%EB%A1%9C%EB%93%9C%EB%B0%B8%EB%9F%B0%EC%8B%B1
https://www.site24x7.com/learn/clb-vs-alb-vs-nlb.html
https://odaily.tistory.com/entry/AWS-Elastic-Load-Balancing-%EC%82%AC%EC%9A%A9-ALB-NLB-GLB-CLB
HAProxy
https://d2.naver.com/helloworld/284659
https://www.haproxy.com/blog/how-to-run-haproxy-with-docker#the-performance-impact-of-running-docker
https://blog.naver.com/ghdalswl77/222283886497
https://www.haproxy.com/blog/the-four-essential-sections-of-an-haproxy-configuration
https://www.haproxy.com/blog/layer-4-and-layer-7-proxy-mode