네트워크

[네트워크] 로드밸런서의 기본 (L4 로드밸런서 L7 로드밸런서) (AWS ELB, NLB, ALB)

quokkalover 2022. 5. 3. 22:03

 

로드밸런서는 네트워크 공부의 꽃이다. 필자는 현재 일하고 있는 회사에서 직접 L7 로드밸런서를 구현해보면서 로드밸런서에 대해 공부를 했는데  L4스위치와 L7스위치가 무엇인지에 대한 개념을 하나의 글에서 다루는 것을 찾지 못해 필자가 나중에 기억이 안나면 참고하기 위해 글을 쓴다.

 

로드밸런서는 정말 광범위하고 복잡한 주제다. 사실 이 글이 끝이 아니고 이 글을 이해했으면 이해해야 할 개념들이 점점 더  많이 보여 고통스럽다. 그래도 개발자가 알아두어야할 지식이기 때문에 앞으로도 이 글 말고도 더 깊은 주제를 다뤄보고자 한다. 

 

 

로드밸런서란?

서버나 장비의 트래픽을 분산하기 위해 사용하는 장비를 로드 밸런서라고 부른다. 이렇게 부하 분산이 필요한 이유는 갑작스런 이용자의 증가, 사업 확장 등의 이유로 더 많은 서버 용량과 성능이 필요할 때 서버를 여러 대 추가하여 시스템을 확장하는 스케일 아웃 방법을 활용하기 위해서다. 물론 서버의 CPU나 RAM을 추가해 고성능의 부품으로 교환하는 스케일 업 방법도 있지만 비용과 안정성 측면에서 효율적이지 않다. 웹서버를 운영할 때는 서버 한 대에 장애가 발생하더라도 다른 서버로 서비스를 제공할 수 있는 등의 장점을 가진 스케일 아웃 방법이 자주 활용된다.

 

로드밸런싱의 목표

로드밸런싱은 트래픽을 받아 여러 대의 서버에 분산시키는 기법을 의미한다. 네트워크 뿐 아니라 OS, 쿠버네티스와 같은 container orchestrator 등에서 다음과 같은 공통적인 목표를 가지고 활용되고 있다.

 

1) 자원사용 최적화

2) throughput증가

3) 응답속도 감소

4) 특정 서버의 과부하 방지

5) 안정성, 가용성 제고

 

로드밸런서가 하는 일

로드 밸런서를 활용하면 실제로는 여러 대의 백엔드 서버가 동작하더라도 사용자에게는 하나의 서비스처럼 보이게 할 수 있다. 비법은 로드밸런서가 서비스에서 사용되는 대표 IP주소를 갖고 클라이언트의 요청을 받되, 자신과 연결된 백엔드 서버의 실제 IP로 요청을 보내는 것이다.

 

로드밸런서는 이와 같이 동작하기 위해 아래 3가지 중요한 업무를 수행하고 있다.

 

1) Service discovery : 현재 available한 서버의 목록을 유지하고, 그들의 IP주소를 관리

2) Health checking : 현재 어떤 backend 서버가 healthy한지 확인 (healthy=클라이언트의 요청을 처리할 수 있는 상태를 의미)
3) Load balancing : 각 유저의 요청을 특정 알고리즘을 활용해 healthy한 백엔드 서버들에게 네트워크 부하를 분산

 

 

또한 로드밸런싱을 분산시스템에서 적절히 활용하면 다음과 같은 장점이 있다.

 

1) Naming abstraction : 여러 백엔드 서버가 동작하고 있을 때, 클라이언트가 모든 백엔드 서버를 discover할 필요 없이, 로드밸런서만 알고 있으면 로드밸런서가 name resolution을 대신 수행해준다.

2) Fault tolerance : 주기적으로 백엔드 서버들의 health를 체크하고 특정 서버에 장애가 발생할 경우 다른 백엔드 서버에 요청을 전달하거나, 알고리즘을 적절히 활용해 공평하게 부하를 분산시킨다.

3) 성능 개선 : 여러대의 서버가 분산해서 요청을 처리하기 때문에 latency를 줄일 수 있다.


로드밸런서는 OSI 7 Layer를 기준으로 L4계층의 로드밸런서와 L7계층의 로드밸런서로 구분할 수 있다. 이제 L4로드밸런서가 무엇인지, L7로드 밸런서가 무엇인지 살펴볼 시간이다.

L4 로드밸런서

L4 로드밸런서는 이름에서 알 수 있듯이 4계층인 TCP헤더에 있는 정보(IP, port)를 이해하고 이 정보를 기반으로 동작한다. 즉 4계층에 대한 정보로만 분산 처리하는 기기를 L4 로드밸런서 혹은 L4 스위치라고 한다. AWS ELB의 Network Load Banacer가 L4스위치의 역할을 한다.

L4 로드밸런서는 내부 동작은 4계층 로드밸런싱이지만 외형은 스위치처럼 여러개의 포트를 가지고 있다. L4 스위치가 동작하려면 가상 서버, 가상 IP, 리얼 서버, 리얼 IP를 설정해야 한다. 여기서 가상 서버와 가상 IP란 클라이언트가 바라보는 서버와 IP주소를 의미하고 리얼 서버와 리얼 IP는 실제 서비스를 수행하는 서버와 실제 서버의 IP를 의미한다. 즉 L4 로드밸런서는 가상 IP를 리얼 IP로 변경해주는 역할을 수행한다.

L4 로드밸런서의 기본 동작

위 그림에서 보이듯 클라이언트가 서버에 서비스를 요청할 때 서버에 직접 TCP connection을 맺는 것이 아니라 로드밸런서를 통해 connection이 맺어진다. 즉 사용자가 L4 로드밸런서의 IP로 서비스를 요청하면 클라이언트의 목적지로 설정된 가상 IP를 리얼 IP(upstream server)로 다시 변경해 보내주는데, 이 과정에서 어떤 알고리즘을 활용하냐에 따라 부하를 분산하는 방식이 결정된다. 또한 위 그림에서 보이듯 L4 로드밸런서에서는 클라이언트와 하나의 upstream server와 매칭된다.

 

위와 같이 패킷의 source, destination IP address를 변경하는 NAT(Network Address Translation)을 수행해야 하는데, 한번 아래 NAT의 예시를 통해 살펴보자.

 

Client로부터 요청이 전달되게되면, 아래처럼 LB에서 서버에 Source, Dest IP를 변경하고

Source                 Dest         Source              Dest
 ----------- ---------- -------        ------- --------  --------
| Client IP | Segment  | LB IP |  --> | LB IP | Segment | Server |  
 ----------- ---------- -------        ------- --------  --------
    Changing source an destination IP for every request packet

서버가 응답하게 되면, 아래처럼 똑같이 로드밸런서에 의해 Source, Dest IP가 변경된다.

Source                 Dest         Source              Dest
 ----------- ---------- -------        ------- --------  ---------
| Server IP | Segment  | LB IP |  --> | LB IP | Segment | ClientIP |  
 ----------- ---------- -------        ------- --------  ---------
    Changing source an destination IP for every response packet

위 예시에서도 보이듯 L4 로드밸런서는 어플리케이션 레벨의 데이터(byte)가 무엇인지에 알지 못한다. 오직 L4의 정보인 IP와 Port만으로 로드밸런싱을 수행한다. 정리하면 L4 로드밸런서의 주요 업무는 네트워크를 통해 자신에게 넘어온 데이터를 누구에게 전달할지 결정하고, 동일한 session에서 동작하는 것처럼 connection을 구성하여 목적지에 전달하는데 있다. 실제로는 서버와 클라이언트가 직접적으로 연결된게 아니지만 클라이언트와 서버는 직접적으로 연결된 것처럼 데이터(byte)를 주고받게 하는 것이다. 참고로 여기서 말하는 데이터(byte)는 HTTP, Redis, MongoDB나 다른 application에서 생성된 데이터(byte)를 의미한다.

 

따라서 L4 Layer 로드밸런서는 데이터를 보지 않고, L4 정보인 IP와 Port번호만으로 로드밸런싱을 수행한다. 그래서 Authorization header가 없는 경우에는 라우팅을 하지 않거나, URL의 path를 기반으로 라우팅을 할 수 없다. 이게 왜 문제가 되는지 살펴보자.

 

L4 스위치의 한계

1) Mega Proxy 문제

Mega Proxy란, Client의 IP만으로 요청을 분산할 경우 아래 사진과 같이 요청 양의 불균형이 발생하는 것을 의미한다.

사진에서 보이듯, 그냥 L4정보만으로 라우팅을 수행하기 때문에 부하에 관련된 정보를 고려하지 않아 특정 서버에 요청이 집중되는 문제가 발생한다. 위의 Mega Proxy문제를 해결하기 위해 L7 스위칭을 사용하게 되면 쿠키를 이용해서 같은 IP를 가진 클라이언트에 대해 HTTP헤더에 서로 다른 쿠키값을 할당하여 서로 다른 서버로 로드밸런싱을 하더라도, 세션의 연결지속성을 유지할 수 있다.

 

2) Multiplexing, Keep-alive 사용 불가능

L4 로드밸런서 만으로는 multiplexing이나 keep-alive 프로토콜을 사용할 수 없다. payload의 정보를 보지 않기 때문에, 상위 프로토콜의 정보를 활용할 수 없기 때문이다. multiplexing이란 하나의 connection으로 여러개의 request를 보내는 것을 의미한다. keep-alive는 일정 시간 동안 connection을 끊지 않는 것을 의미한다.

3) 불가능한 기능들

1) Dos/SYN Attack에 대한 방어

2) L7 패킷 분석을 통한 바이러스 감염 패킷 필터링

3) 자원 독점 방지 등을 통한 시스템 보안 강화

 


L7 로드밸런서

L7 로드밸런서는 Layer4를 넘어 Layer7의 프로토콜 헤더를 분석할 수 있는 L4로드밸런서보다 더 intelligent한 로드밸런서다. IP port외에도 URI, payload, HTTP header, 쿠키 등의 내용을 활용해 부하를 분산하기 때문에 콘텐츠 기반 스위칭이라고도 한다. L4 로드밸런서는 단지 부하를 분산시키는데 집중한다면 L7 로드밸런서는 패킷의 내용을 확인할 수 있기 때문에 보안 지점(바이러스 감지 e.g.)을 구축하거나 사용자의 요청을 기준(HTTP헤더 쿠키 e.g.)으로 트래픽을 특정 서버에 분산하는 것이 가능하다. 참고로 모든 proxy서버가 로드밸런서는 아니지만 대부분의 proxy서버가 로드밸런서의 역할을 수행하고 있다. 또한 AWS에서 Application Load Balancer가 L7 스위치의 역할을 하고 있다.

 

L7 로드밸런서 기본 동작

L7 로드밸런서의 기본동작은 위 사진에서 보이듯 client가 요청을 보냈을 때 로드밸런서와 TCP connection을 맺고, 로드밸런서는 upstream server 중 하나와 새로운 TCP connection을 맺는다. 또한 L7는 최상위 계층이기 때문에, 패킷의 데이터를 모두 확인할 수 있어 아래와 같은 기능들을 수행할 수 있다.

1) Authentication - Authorization header가 없으면 에러 리턴

2) Smart Routing - 특정 upstream 서버에 라우팅하는 등 intelligence 라우팅 가능

3) TLS termination 가능

 

keep-alive / pipelining / multiplexing 지원

또한 L7 로드밸런서는 클라이언트에서 요청이 왔을 때 keep-alive, pipelining, multiplexing을 지원한다.

 

HTTP/1.1 pipelining

HTTP/1.1부터는 기본값으로 persistent connection과 HTTP pipelining을 지원하기 때문에 위 그림처럼 한번 connection을 맺고나면 한동안 connection을 종료하지 않고 여러개의 요청을 연속적으로 보낸 뒤 동일한 순서로 response를 받을 수 다. 이것도 놀랍지만 HTTP/2부터는 multiplexing이 지원된다! 한번 아래를 보자.

 

HTTP/2 multiplexing

multiplexing이란 여러개의 request를 하나의 TCP connection을 사용해 전달하는 것을 의미한다. 다시 말해 multiplexing은 HTTP/2부터 지원하는 방식으로 동일한 TCP연결을 사용하여 서로 다른 클라이언트의 TCP연결에서 온 요청을 queue와 같은 기술을 통해서 비동기적으로 요청을 할 수 있다. 이에 따라 웹 서버는 클라이언트 요청마다 connection을 맺거나 idle session을 유지하기 위해 필요한 자원 사용을 줄일 수 있기 때문에 더 효율적인 서버 운영이 가능해진다.


AWS를 통해 알아보는 L4 로드밸런서와 L7 로드밸런서의 차이

AWS에서는 Elastic Load Balancer라고 아마존 내 EC2인스턴스, 컨테이너 및 IP주소와 같은 여러 대상에 대해 네트워크 트래픽을 분산시켜주는 서비스다. 대표적으로 L4스위치인 Network Load Balancer와 L7스위치인 Application Load Balancer가 있는데, L4스위치와 L7스위치의 차이를 이해하기 위해서는 NLB와 ALB의 차이를 이해하는게 큰 도움이 된다.

 

ALB

 

ALB의 특징은 다음과 같다.

1) L7 로드밸런서를 지원한다

2) IP주소 + 포트 번호 + 패킷 내용(HTTP/HTTPS의 헤더)을 보고 스위칭한다.

3) ALB는 IP주소가 변동되기 때문에 Client에서 접근할 ELB의 DNS Name을 이용해야 한다.

4) SSL 적용이 가능하다

NLB

NLB의 특징은 아래와 같다

1) L4 로드밸런서를 지원한다

2) TCP/IP 프로토콜의 헤더를 보고 패킷을 스위칭한다.

3) Elastic IP를 할당가능하고, DNS Name이나 IP주소 모두 사용이 가능하다.

4) SSL 적용이 인프라 단에서 설정이 되지 않기 때문에 어플리케이션에 따로 적용해주어야 한다.

5) ALB보다 대기시간이 낮고 처리량이 높다. (당연함, 4계층 까지만 확인하니까)

 

ALB와 NLB 비교표

사실 지금까지 다룬 내용은 완전 기초적인 내용이다. 실제 L7 로드밸런서의 구현체와 동작 방식은 훨씬더 복잡하고 어렵다. 필자도 아직 제대로 이해하지 못했고, 추후에 하나씩 다뤄보도록 하겠다.

 

 

 

참고자료

https://aws-hyoh.tistory.com/133

https://www.haproxy.com/blog/http-keep-alive-pipelining-multiplexing-and-connection-pooling/

https://no-easy-dev.tistory.com/entry/AWS-ALB와-NLB-차이점

https://levelup.gitconnected.com/l4-vs-l7-load-balancing-d2012e271f56

https://blog.envoyproxy.io/introduction-to-modern-network-load-balancing-and-proxying-a57f6ff80236

https://www.snapt.net/glossary/layer-4-vs-layer-7-load-balancing-explained

https://medium.com/martinomburajr/distributed-computing-tcp-vs-http-s-load-balancing-7b3e9efc6167

https://www.computerworld.com/article/2590907/explainer--tcp-ip-multiplexing-boosts-sites.html

https://www.fortinetguru.com/2016/11/http-and-https-load-balancing-multiplexing-and-persistence/

https://www.haproxy.com/blog/http-keep-alive-pipelining-multiplexing-and-connection-pooling/

http://qnimate.com/what-is-multiplexing-in-http2/

https://stackoverflow.com/questions/34478967/what-is-the-difference-between-http-1-1-pipelining-and-http-2-multiplexing