Load Balancer (로드 밸런서)란?
다중 서버 문제
단일 서버 환경에서, 서버 성능에 의해 병목을 겪는다면, Scale up 또는 Scale out을 고려해야 한다. Scale up은 단일 서버 환경은 유지하는 대신, 서버 자체 성능을 올려 병목을 해결하는 방법이고, Scale out은 서버 개수를 늘려 처리량을 늘려서 병목을 해결하는 방법이다.
Scale up을 하더라도, 서버가 SPOF(단일 장애점, Single Point Of Failure)가 될 가능성이 있기 때문에 우리는 Scale Out을 고려하는 상황이라고 해보자. 즉, 단순하게 서버가 한대에서 두대로 늘어난 상황이다.
클라이언트가 우리 서버를 접근하려면 도메인 네임을 통해 접근해야 한다. 그런데 도메인 네임은 IP와 1:1로 매칭될 것인데, 우리는 서버가 두대니까 IP도 두개이다.
상식적으로 같은 서비스를 이용하는 데 서로 다른 도메인으로 들어가는 것은 클라이언트의 편의상 이상할 것 같다. 설령 클라이언트가 선택하게 하더라도, 클라이언트 트래픽이 양 서버에 공평하게 분배되어 들어올 것이라는 보장이 없다. 이 문제를 어떻게 해결해야 할까?
로드 밸런서의 역할
이런 상황에서 고려할 수 있는 것이 바로 Load Balancer이다. 한국어로 직역하면 부하 분산기인데, 로드 밸런서는 의미에 알맞게 부하 분산이 주 역할이다.
상기한 상황처럼, 인프라에서 여러 인스턴스 간에 트래픽을 분산할 필요가 있을 경우에 로드 밸런서가 꼭 필요하다. 트래픽을 공평하게 분산하고 싶다면 Round Robin 등의 알고리즘이 쓰일 수도 있고, 특정 IP, 또는 엔드포인트를 특정 서버로만 연결짓는 것도 가능하다.
로드 밸런서 (이하 LB) 의 종류
로드 밸런서에는 대표적으로 두가지 종류가 있는데, L4 LB와 L7 LB이다.
L4 LB
L4 LB는 OSI 7계층의 L4 (Transport Layer) 에서 동작한다. 따라서 L4 LB는 아래 계층 정보를 포함한, 즉 L3, L4의 헤더가 포함하는 내용을 볼 수 있다.
5-tuple
5-tuple은 L4 LB가 로드 밸런싱을 수행할 때 기준으로 삼는 정보이다.
- Source IP (L3 IP Datagram 헤더)
- Dest IP (L3 IP Datagram 헤더)
- Source Port (L4 TCP/UDP 헤더)
- Dest Port (L4 TCP/UDP 헤더)
- Protocol (L3 IP Datagram 헤더의 upper layer 필드)
우리가 REST API를 통해 HTTP message를 보낸다고 하자. message는 TCP를 통해 여러 segment로 나뉘어 보내질 것이다. 만약 LB가 해당 message를 해석하려면 여러 segment를 재조립하여 HTTP message를 해석하여야 한다.
그러나 L4 LB는 로드 밸런싱 기준에 L7 message 정보, 즉 HTTP 헤더 정보가 필요하지 않다. 따라서 L4 LB는 segment들을 재조립 할 필요 없이, 그저 헤더 정보만 보고 Dest IP/Port를 수정하여 흘려보내면 된다.
HTTP message를 해석하기 위해 segment를 재조립할 필요가 없다는 것은, 클라이언트와 L4 LB가 직접 TCP 연결을 맺지 않아도 된다는 말과 같다. L4 LB는 그저 목적지 서버만 밸런싱해주어 segment를 흘려보내고, 그렇게 온 segments를 재조립하는 것은 서버의 역할이 될 것이다. 따라서 논리적으로 TCP 연결은 1회만 발생한다.
L7 LB
L7 LB는 OSI 7계층의 L7 (Application Layer) 에서 동작한다. 따라서 L7 LB는 아래 계층 정보를 포함한, 즉 L3, L4, L7의 헤더가 포함하는 내용을 볼 수 있다.
L7 LB는 HTTP message 헤더까지 로드 밸런싱 수행 기준으로 삼을 수 있다. 예를 들면 다음과 같다.
- URL host
- URL path
- Query String
- HTTP header
마찬가지로, 우리가 REST API를 통해 HTTP message를 보낸다고 하자. message는 TCP를 통해 여러 segment로 나뉘어 보내질 것이다. LB가 해당 message를 해석하려면 여러 segment를 재조립하여 HTTP message를 해석하여야 한다.
L7 LB는 L4 LB와는 다르게 로드 밸런싱 기준에 L7 정보, 즉 HTTP 헤더 정보가 필요하다. 따라서 L7 LB는 segment들을 재조립 하여 HTTP message를 알아내야 하고, Dest IP/Port, HTTP Header, 그리고 필요하다면 URL 등을 수정하여 밸런싱하면 된다.
HTTP message를 해석하기 위해 segment를 재조립해야 한다는 것은, 클라이언트와 L7 LB가 직접 TCP 연결을 맺어야한다는 말과 같다. L7 LB는 클라이언트와의 TCP 연결을 통해 segments를 재조립하여 HTTP message를 알아내고, 수정한 HTTP message를 밸런싱한 서버에 전송하기 위해 서버와도 TCP 연결을 맺을 것이다. 따라서 논리적으로 TCP 연결은 2회 발생한다.
L4 LB vs L7 LB
| L4 Load Balancer | L7 Load Balancer | |
| 동작 위치 | L4 (Transport Layer) | L7 (Application Layer) |
| 밸런싱 기준 | 5-tuple 기반 연결 정보 | HTTP request |
| 유연성 | 낮음 | 높음 |
| TCP 연결 | 1회 | 2회 |
| 속도 | 빠름 | 느림 |
| AWS service | NLB (Network Load Balancer) | ALB (Application Load Balancer) |
AWS에서 Elastic Load Balancing으로 ALB, NLB를 사용하는 경우에는 Auto Scaling Group과 연결하여 트래픽 부하에 따른 부하 분산을 더욱 효과적으로 할 수 있다. 만약 인스턴스 그룹이 감당 불가능한 부하가 들어오면, Auto Scaling이 발생하여 인스턴스 수를 늘리고, 이를 ALB, NLB가 로드 밸런싱에 포함하는 방식으로 작동한다.
TCP 3-way handshake
TCP 연결 상황에서, 로드 밸런서가 중간에 끼어 있으면 어떻게 작용할까 한번 그림으로 나타내보았다.
Client - Server model Only
다음 상황에서는 클라이언트와 서버만 존재한다고 가정하자.

Client - Server model with L4 LB
이제 클라이언트와 서버 사이에 L4 LB를 두어보자.

Client - Server model with L7 LB
이번에는 클라이언트와 서버 사이에 L7 LB를 두어보자.
