로드밸런서 (Load Balancer)

ohyujeong·2023년 12월 24일
0

network

목록 보기
7/8

로드밸런싱과 로드밸런서 (Load Balancer)

로드 밸런싱이란 서버가 처리해야 할 요청(Load)을 여러 대의 서버로 나누어(Balancing) 처리하는 것을 의미한다.
여러 사용자의 요청들이 한 대의 서버로 집중되지 않도록 관리해 각각의 서버가 효율적으로 가동되도록 하는 것이 목적이다.
그리고 이를 수행하는 장치를 로드밸런서라고 한다.

대규모 트래픽에 대응할 수 있는 방법은 다음과 같이 두 가지로 나뉜다.

  • Scale-up 방식 : 기존의 서버 성능을 확장
  • Scale-out 방식 : 기존의 서버와 동일하거나 낮은 성능의 서버를 증설

여기서 Scale-out 방식을 통해 증가한 트래픽에 대처하기로 했다면 여러 대의 서버로 트래픽을 균등하게 분산해주는 로드 밸런싱이 필요하게 된다.

로드 밸런싱 알고리즘

라운드로빈(Round Robin)

  • 트래픽을 서버들에게 순차적으로 서버를 순환하면서 할당한다.
    예를 들어 서버가 A, B, C가 있다면 첫번째 요청은 A, 두번째 요청은 B, 세번째 요청은 C에 할당되고 네번째 요청은 다시 A에 할당되는 방식이다.
  • 각 서버에 공평하게 트래픽을 분산시킬 수 있고 각 서버가 균등한 부하를 받게 된다.
    이러한 특성때문에 각 서버의 컴퓨팅 기능과 스토리지 용량이 거의 동일할 때 가장 잘 작동한다.

가중 라운드로빈 (Weighted Round Robin)

  • 각각의 서버마다 가중치를 부여하고, 가중치가 높은 서버에 더 많은 요청을 라운드 로빈으로(차례대로 순환하면서) 배분한다.
  • 주로 서버의 트래픽 처리 능력이 상이한 경우 사용되는 방식이다.
    예를 들어 A라는 서버가 5라는 가중치를 갖고 B라는 서버가 2라는 가중치를 갖는다면, 로드 밸런서는 라운드로빈 방식으로 A 서버에 5개 B 서버에 2개의 요청을 전달한다.
  • 라운드로빈 방식에서는 할 수 없었던 서버의 성능 차이를 고려한 로드 분산을 가능하게 한다.

최소 연결 (Least Connection)

  • 요청이 들어온 시점에 가장 적은 연결을 가진 서버에 우선적으로 트래픽을 배분한다.
  • 각 서버의 현재 부하 상태를 실시간으로 반영하기 때문에, 더 빠르게 요청을 처리할 수 있는 서버에 트래픽이 갈 확률이 높아진다.
    예) 어떤 서버가 장기간 지속되는 세션(연결)을 많이 처리하고 있다면 신규 요청은 다른 서버로 보내 부하를 분산한다.
  • 트래픽 처리 성능에 차이가 있는 서버가 있다면 현재 연결 수를 기준으로 부하를 분산하기 때문에 상대적으로 트래픽 처리 성능이 더 좋은 서버가 요청을 많이 가져가게 된다.

IP 해시 (IP Hash)

  • 클라이언트의 IP 주소를 특정 서버로 매핑하여 트래픽을 처리하는 방식이다.
  • 사용자의 IP를 해싱하여(Hashing, 임의의 길이를 지닌 데이터를 고정된 길이의 데이터로 매핑하는 것, 또는 그러한 함수) 로드를 분배하기 때문에 특정 클라이언트의 모든 요청이 항상 동일한 서버로 연결되는 것을 보장한다.
  • 사용자별 세션 유지가 중요할 때 유리하다.

최소 응답 시간 (Least Response Time)

  • 서버의 현재 연결 상태와 응답 시간(Response Time, 서버에 요청을 보내고 최초 응답을 받을 때까지 소요되는 시간)을 모두 고려하여 트래픽을 배분한다.
  • 응답 시간은 로드밸런서가 서버로부터 응답을 받을 때의 시간을 지속적으로 모니터링하여 각 서버의 평균 응답 시간을 계산하여 산출한다.
  • 각 서버의 부하 상태와 성능을 실시간으로 파악하여, 가장 빠른 응답을 제공할 수 있는 서버에 요청을 보낸다.
  • 서버의 응답 속도가 중요한 실시간 애플리케이션에 적합한 방식이다.

L4 vs L7 로드밸런싱 비교

로드 밸런싱에는 L4(전송 계층) 로드 밸런싱과 L7(응용 계층) 로드 밸런싱이 가장 많이 활용된다.

L4 로드 밸런싱

  • 네트워크의 전송 계층에서 작동하며, IP 주소와 포트 번호를 기반으로 트래픽을 관리한다.
  • 패킷의 헤더에 있는 정보를 사용하고 데이터는 보지 않기 때문에 속도가 빠르다는 장점이 있다.
  • 애플리케이션 레벨의 데이터(HTTP 헤더/본문)를 해석하지 못하기 때문에 세세한 정보에 따른 로드밸런싱은 수행하지 못한다.

L7 로드 밸런싱

  • 응용 계층(프로토콜:HTTP, FTP, SMTP)에서 로드를 분산하기 때문에 HTTP 헤더, 쿠키 등과 같은 사용자의 요청을 기준으로 특정 서버에 부하를 분산할 수 있다.
    예를 들어 URL에 따라 부하를 분산시키거나, HTTP 헤더의 쿠키 값에 따라 부하를 분산하는 등 클라이언트의 요청을 보다 세분화하여 서버에 분배한다.
  • L4와 같이 IP와 port를 사용하여 로드밸런싱을 하는 것은 같으나, 애플리케이션 계층의 프로토콜을 통해 사용자 정의 로드밸런싱을 하거나 프로토콜 헤더를 조작/활용한다.
  • 특정한 패턴을 지닌 바이러스를 감지해 네트워크를 보호할 수 있으며, DoS/DDoS와 같은 비정상적인 트래픽을 필터링할 수 있다.

AWS의 로드밸런서

AWS는 다양한 유형의 로드밸런서를 제공한다.
주로 사용되는 3가지의 로드밸런서는 다음과 같다.

  • Classic Load Balancer (CLB)
  • Network Load Balancer (NLB)
  • Application Load Balancer (ALB)

각 로드밸런서를 살펴보고 서로 어떻게 다른지 알아보자.

Classic Load Balancer (CLB)

  • AWS의 초기 로드 밸런싱 서비스로, L4(전송 계층)와 L7(응용 계층) 모두에서 작동한다.
  • 트래픽의 분산, 오류 발생 시 자동 재시도, 헬스 체크 등의 기본적인 로드 밸런싱 기능을 제공한다.
  • 현재 AWS는 두 개 이상의 계층에서 동시에 작동하는 로드 밸런서를 생성하는 것이 이상적이지 않다고 판단하여 deprecated 된 상태이다.

Network Load Balancer (NLB)

  • L4(전송 계층)에서 작동하는 로드밸런서로, TCP, UDP, TLS 트래픽을 처리하는 데 최적화되어 있다.
  • NLB는 높은 트래픽 처리량낮은 지연 시간을 제공하기 때문에 대규모 및 고성능 로드 밸런싱에 적합하다.
  • 고정 IP 주소를 할당할 수 있어서 DNS 이름 대신 IP 주소를 사용해 로드밸런서에 접근할 수 있다.

Application Load Balancer (ALB)

  • L7(응용 계층)에서 작동하는 로드밸런서로, AWS에서 가장 보편적으로 많이 사용된다.
  • HTTP, HTTPS 트래픽을 처리하며, 요청의 내용(예: URL, HTTP 헤더, 쿠키)을 기반으로 로드 밸런싱을 수행한다.
  • 경로 기반 라우팅, 호스트 기반 라우팅, HTTP 헤더, 쿼리 문자열 및 쿠키를 기반으로 한 라우팅을 지원하기 때문에 MSA 환경에서 마이크로 서비스의 트래픽을 관리하는데 사용된다.
  • Docker, Kubernetes와 같은 컨테이너 오케스트레이션 기술과 통합하여 사용할 수 있다.

NLB와 ALB의 차이점을 다음 표와 같이 요약할 수 있다.

기능Network Load Balancer (NLB)Application Load Balancer (ALB)
지원 프로토콜TCP, UDP, TLSHTTP, HTTPS
네트워크 계층Layer 4 (전송 계층)Layer 7 (응용 계층)
라우팅 기준IP 주소, 포트URL 경로, 도메인 이름, HTTP 헤더/메소드
성능높은 처리량과 낮은 지연HTTP/HTTPS 트래픽에 최적화됨
고정 IP가능불가능
타킷 health check가능가능
사용 예시실시간 스트리밍 서비스, 고성능 데이터베이스 서버MSA, 복잡한 웹 애플리케이션

HAProxy

HAProxy는 High Availability Proxy로 말그대로 고가용성 기능을 제공하는 오픈소스 로드 밸런서이다.
기존의 하드웨어 스위치를 대체하는 소프트웨어 로드밸런서로, 네트워크 스위치에서 제공하는 L4, L7 기능 및 로드밸런싱 기능을 제공한다.

작동 방식


HAProxy는 기본적으로 reverse proxy 형태로 동작한다.
우리가 브라우저에서 사용하는 proxy는 클라이언트 앞에서 처리하는 기능으로, forward proxy라 한다.
그와 반대로 reverse proxy는 서버 앞에 있으면서 서버로 들어오는 요청을 대신 받아서 서버에 전달하고 요청한 곳에 그 결과를 다시 전달한다.

고가용성(High Availability, HA) 구성

'고가용성'은 서버, 네트워크, 프로그램 등 시스템이 계속 정상 운영될 수 있는 특성을 의미한다.
HAProxy에서는 다음과 같은 HAProxy 인스턴스 설정으로 고가용성을 구성한다.

Primary-Secondary 모드 (Active-Passive 모드)

  • 하나의 HAProxy Primary 인스턴스활성 상태로 트래픽을 처리하고, Secondary 인스턴스대기 상태로 있다.
  • Primary 인스턴스에 장애가 발생하면, Secondary 인스턴스가 자동으로 활성화되어 트래픽을 처리한다.
  • 심작박동(Heartbeat)를 체크하기 위한 도구(예:Keepalived)와 함께 사용한다.
  • Keepalived는 HAProxy 인스턴스 간의 상태를 모니터링하고, Primary 인스턴스에 장애가 발생할 경우 자동으로 Secondary 인스턴스를 액티브 상태로 전환한다.

Primary-Primary 모드 (Active-Active 모드)

  • 두개 이상의 HAProxy 인스턴스가 동시에 활성 상태로 있으면서 트래픽을 처리한다.
  • 높은 처리량을 가지고, 더 나은 자원 활용을 할 수 있다.

Sticky Sessions

  • 사용자의 세션 정보를 기반으로 특정 서버에 지속적으로 트래픽을 할당한다.
  • 사용자의 요청이 같은 서버로 보내지기 때문에 데이터의 일관성이 유지된다.

HAProxy 옵션 설정

HAProxy의 옵션을 설정하려면 haproxy.cfg 파일을 수정해야 한다. (/usr/local/etc/haproxy/haproxy.cfg 경로에 위치)
이 설정 파일은 다음과 같이 크게 네 부분으로 나뉜다.

  • global : HAProxy 인스턴스 전체에 적용되는 전역설정이다. 주로 로그, 프로세스 관리, 보안 관련 설정이 포함된다.

  • default : 모든 frontendbackend 섹션에 적용될 기본 설정을 지정한다. 주로 연결 타임아웃, 로그 설정, 프로토콜 모드(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를 실행해보려고 한다.

L4 모드와 L7 모드

HAProxy는 TCP 또는 HTTP의 두 가지 모드로 실행될 수 있다.
TCP 모드에서 작동할 때 L4(전송계층)모드이고, HTTP 모드에서 작동할 때는 L7(응용계층)모드이다.
haproxy.cfg 파일에서 이 모드를 지정할 수 있다.

L4 모드

다음과 같이 haproxy.cfg 에서 modetcp 로 설정하여 L4 모드로 지정한다.

defaults
    mode tcp

다음과 같은 특징을 가진다.

  • 전송계층에서 작동하고 TCP 프로토콜을 사용한다.
  • 전송에만 관여하기 때문에 트래픽 전달이 가볍고 빠르다.
  • 클라이언트가 연결을 시도한 원래의 IP 주소와 포트가 아닌, HAProxy 자체의 설정에 따라 다른 IP 주소와 포트로 요청을 전달할 수 있다.
  • MySQL, Postgres와 같이 TCP 통신을 사용하는 서비스에 적합하다.
  • 서버의 health check, 내부 네트워크 보호, 서버 과부하를 방지하기 위한 연결 대기열, 연결 속도 제한 등의 옵션을 추가할 수 있다.

L7 모드

다음과 같이 haproxy.cfg 에서 modehttp 로 설정하여 L7 모드로 지정한다.

defaults
    mode http

다음과 같은 특징을 가진다.

  • 응용계층에서 작동하고 HTTP, HTTPS 프로토콜을 사용한다.
  • L4부터 L7까지 정의된 모든 세부 정보들을 기반으로 라우팅을 할 수 있다.
  • 요청된 URL 경로에 따라 특정 서버로 라우팅하거나, 수신된 HTTP 헤더를 기반으로 라우팅할 수도 있다.
  • 들어오는 요청이나 나가는 응답의 HTTP 헤더를 추가, 수정, 삭제할 수 있다.
  • 쿠키를 설정하거나 수정하여 특정 사용자를 특정 서버에 지속적으로 연결하게 할 수 있다.

L4 모드와 L7 모드 설정은 예시와 같이 default 섹션 뿐만 아니라 frontendbackend 섹션에서도 설정 가능하다.
이렇게 되면 default 섹션의 값이 덮어써진다.
단, 연결되어 있는 frontendbackend 섹션은 동일한 모드로 설정되어야 한다.
섹션에서 모드를 다르게 설정할 경우 일부는 TCP 모드로, 다른 일부는 HTTP 모드로 작동할 수 있다.

헬스체크(Health Check)

백엔드 서버들의 상태를 모니터링하여, 서버가 정상적으로 작동 중인지 확인한다.
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 설정 파일(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 이 기본값이다.

Docker로 HAProxy 실행해보기

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 가 보여진다. 이 외에도 다음과 같은 주요 정보들을 보여준다.

  • 각 서버의 이름과 상태
  • 세션 정보
  • 전송된 byte 양
  • 처리된 요청 수

참고

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

profile
거친 돌이 다듬어져 조각이 되듯

0개의 댓글