SLB는 UDP 트래픽을 위한 세션 없는 로드 밸런서이며, 이러한 트래픽에 대해 기존(풍부한 기능) 로드 밸런서를 사용할 때 발생하는 고유한 문제를 해결합니다.
단순한 상태 비저장 UDP 프로토콜의 경우 클라이언트와 백엔드 인스턴스 간의 "친화성"(일명 "세션")을 유지하려고 해도 이점이 없습니다. 기존 로드 밸런서는 선호도가 도움이 된다고 가정하므로 클라이언트에서 일관된 백엔드 서버로 패킷을 라우팅하려고 시도합니다. 이와 대조적으로 SLB는 사용 가능한 모든 백엔드에 패킷을 하나씩 균등하게(임의로) 배포합니다. 이로 인해 백엔드가 균일하게 로드되고 하나의 백엔드 인스턴스가 실패할 때 견고성이 향상됩니다(일부 클라이언트의 전체 트래픽 손실이 아닌 모든 클라이언트의 패킷 손실이 증가함).
기본적으로 SLB는 포트 1812
및 1813
에서 들어오는 UDP 패킷을 수신하고 이를 알고 있는 임의의 백엔드 대상으로 중계합니다. 수신 대기하는 포트는 단일 포트(예: 541
) 또는 포트 범위(예: 4000-5000
)를 허용하는 --server-port-range
옵션을 사용할 수 있습니다.
SLB가 백엔드를 인식하도록 하려면 "watchdog"(일명 "keep Alive") 패킷을 관리 포트로 보내야 합니다(자세한 내용은 아래 참조). 기본적으로 관리 포트는 1111
이지만 --admin-port
옵션을 사용하여 구성할 수 있습니다. 시스템에 여러 네트워크 카드가 있는 경우 --admin-ip
옵션을 사용하여 IP를 지정할 수 있습니다. --admin-ip
로 지정된 IP가 멀티캐스트 CIDR 범위( 244.0.0.0/4
)에 있는 경우 SLB는 자동으로 해당 멀티캐스트 그룹에 참여합니다(자세한 내용은 아래 참조).
다른 옵션은 명령 도움말에 설명되어 있습니다.
SimplestLoadBalancer:
Sessionless UDP Load Balancer sends packets to backends without session affinity.
Usage:
SimplestLoadBalancer [options]
Options:
--server-port-range <server-port-range> Set the ports to listen to and forward to backend targets
(default "1812-1813") [default: 1812-1813]
--admin-ip <admin-ip> Set the IP to listen on for watchdog events [default is first private IP]
--admin-port <admin-port> Set the port that targets will send watchdog events [default: 1111]
--client-timeout <client-timeout> Seconds to allow before cleaning-up idle clients [default: 30]
--target-timeout <target-timeout> Seconds to allow before removing target missing watchdog events [default: 30]
--default-target-weight <default-target-weight> Weight to apply to targets when not specified [default: 100]
--unwise Allows public IP addresses for targets [default: False]
--stats-period-ms <stats-period-ms> Sets the number of milliseconds between statistics messages printed to the
console (disable: 0, max: 65535) [default: 1000]
--default-group-id <default-group-id> Sets the group ID to assign to backends that when a registration packet doesn't
include one, and when port isn't assigned a group [default: 0]
--version Show version information
-?, -h, --help Show help and usage information
백엔드는 명령줄에서 구성되지 않습니다. 대신 관리 포트( --admin-port
)로 전송되는 주기적인 UDP 패킷을 사용하여 동적으로 등록 및 등록 취소됩니다. 해당 패킷의 내용은 환경에서 SLB를 사용하는 방법에 따라 다를 수 있습니다.
단일 SLB 서버를 실행하는 경우 해당 IP와 관리 포트로 패킷을 보내도록 백엔드를 구성할 수 있습니다. 이것은 가장 간단한 시나리오입니다. 각 백엔드는 콘텐츠에 대한 "백엔드 등록"을 나타내기 위해 두 개의 "매직 바이트"가 포함된 메시지를 보냅니다.
0x11 0x11
SLB는 이러한 패킷을 "발신자를 백엔드로 등록"하는 것으로 해석합니다. 선택적으로 메시지에는 하나 또는 두 개의 추가 바이트(가중치 및 그룹 ID)가 포함될 수 있으며 그 목적은 아래에서 자세히 설명합니다.
0x11 0x11 [X] [X]
^ ^
| |
| one byte for group id
|
one byte for weight
일부 환경에서는 등록 패킷이 백엔드 자체에서 전송되지 않으며 SLB는 이러한 사용 사례를 지원합니다. 등록 패킷이 "타사"에서 전송되는 경우 콘텐츠에는 등록되는 백엔드의 IP 주소가 포함되어야 합니다.
0x11 0x11 X X X X [X] [X]
^ ^ ^
| | |
| | one byte for group id
| |
| one byte for weight
|
four bytes for ip to add
다시, 가중치 및 그룹 ID 바이트가 선택적으로 추가될 수 있습니다.
여러 SLB를 사용하여 보다 강력한 HA 배포가 필요한 경우 멀티캐스트 그룹 IP를 사용하여 백엔드와 SLB 간의 통신을 단순화할 수 있습니다. 이는 각 SLB가 각 백엔드를 인식해야 하므로 유용합니다. 이러한 경우 SLB 서버는 --admin-ip
옵션을 사용하여 멀티캐스트 주소를 지정해야 합니다. 그러면 SLB가 멀티캐스트 그룹에 참여하게 되어 모두가 해당 IP로 전송된 메시지를 받게 됩니다. 백엔드는 해당 단일 IP로 구성될 수 있어 작업 부하를 최소화하고 구성을 단순화합니다(특히 자동 크기 조정 및/또는 스팟 인스턴스 사용으로 인해 SLB가 서비스 안팎으로 순환되는 경우).
멀티캐스트 IP를 사용하려면 멀티캐스트를 지원하는 스위치가 필요하거나 (아마도) 멀티캐스트 도메인으로 구성된 AWS VPC에서 실행되어야 합니다.
관리 패킷 형식은 버전 2.0부터 매우 간단합니다. 가장 간단한 단일 SLB 사용 사례에서 백엔드의 등록 패킷은 2개의 매직 바이트( 0x11
0x11
)만으로 구성될 수 있습니다. 선택적으로 패킷은 다른 소스(예: 관리 서버)에서 제공될 수 있으며 백엔드의 ipv4 주소를 지정하기 위해 4바이트를 포함할 수 있습니다. 두 경우 모두 다른 백엔드와 관련된 트래픽 "가중치" 및 백엔드에 할당할 "그룹"에 대한 두 개의 추가 선택적 바이트가 추가될 수 있습니다(그룹에 대한 자세한 내용은 아래 참조). ASCII 아트에서:
0x11 0x11 [X X X X] [X] [X]
^ ^ ^
| | |
| | one byte for group id
| |
| one byte for weight
|
four bytes for ip to add
대상을 즉시 제거하려면 첫 번째 바이트로 0x11
대신 0x86
이 포함된 패킷을 보냅니다(관리 서버에서 보낸 경우 제거할 백엔드의 IP를 추가하세요).
0x86 0x11 [X X X X]
^
|
four bytes for ip to remove
가중치는 각 백엔드에 전달되는 상대적인 트래픽 양을 제어하는 데 사용됩니다. 가중치를 지정하지 않으면 기본값 100( --default-target-weight
로 구성 가능)이 백엔드에 적용되고 각각은 동일한 양의 패킷을 수신합니다. 즉, 백엔드는 트래픽 처리 능력(CPU가 높을 때 감소, 업데이트 적용 등)을 기반으로 관리 패킷의 가중치 값을 조정하는 것이 예상됩니다(그리고 권장됩니다). 예를 들어:
100
, 50
및 50
인 SLB에 3개의 백엔드가 알려진 경우 첫 번째 백엔드는 트래픽의 50%를 수신하고 두 번째와 세 번째 백엔드는 각각 25%를 수신합니다.31
및 31
인 SLB에 두 개의 백엔드가 알려진 경우 각각은 트래픽의 50%를 수신합니다.그룹을 사용할 때 상대 가중치는 동일한 그룹(모든 그룹에 걸쳐 있지는 않음)의 다른 백엔드와 비교하여 평가됩니다.
관리 패킷을 안정적이고 충분한 속도로 보내는 것이 중요합니다. SLB가 패킷을 수신할 때마다 백엔드의 "마지막 확인" 시간이 업데이트됩니다. 백엔드가 표시되지 않고 30초(
--target-timeout
으로 구성 가능)가 경과하면 백엔드가 제거되고 더 이상 트래픽이 전송되지 않습니다.
기본적으로 모든 백엔드는 로드 밸런서가 제공하는 모든 포트를 서비스하는 데 사용됩니다.
그러나 SLB 포트 할당 메시지를 사용하고 등록 메시지에 그룹 ID를 제공하여 백엔드 하위 집합에 개별 포트를 할당할 수 있습니다. 예를 들어, 포트 1812-1813에 대한 SLB 로드 밸런싱 트래픽을 갖고 싶지만 각 포트에 도달하는 트래픽을 다른 서버 세트에 할당한다고 가정해 보겠습니다. 그렇게 하려면:
x66 x11
)를 보냅니다. 이러한 메시지는 반복할 필요가 없으며 포트 그룹 할당을 변경해야 할 때 전송될 수 있습니다. 그러나 반복해도 문제가 없으며 서비스를 다시 시작한 후 포트가 그룹에 올바르게 할당되었는지 확인하는 것이 편리할 수 있습니다. 0x66 0x11 X X X
^ ^
| |
| one byte for group ID
|
two bytes for port number, litten endian
Linux bash
사용하면 관리 패킷을 보내는 것이 간단합니다. 이는 netcat
( nc
) 명령이나 /dev/udp
파일 시스템을 사용하여 수행할 수 있습니다. 예를 들어, 로드 밸런서가 기본 관리 포트 1111
에서 수신 대기 중이고 IP 192.168.1.22
사용하여 대상을 추가하려는 경우:
$ echo -e $( echo " x11x11 $( echo " 192.168.1.22 " | tr " . " " n " | xargs printf ' \x%02X ' ) " ) > /dev/udp/127.0.0.1/1111
등록된 대상 세트를 유지하기 위해 해당 패킷을 수동으로 보내는 것은 지루할 수 있으므로 lb.sh
와 같은 작은 쉘 스크립트를 작성할 수 있습니다.
#! /bin/bash
echo -ne $( echo " x11x11 $( echo " 192.168.1.22 " | tr " . " " n " | xargs printf ' \x%02X ' ) " ) > /dev/udp/127.1.1.1/1111
echo -ne $( echo " x11x11 $( echo " 192.168.1.23 " | tr " . " " n " | xargs printf ' \x%02X ' ) " ) > /dev/udp/127.1.1.1/1111
echo -ne $( echo " x11x11 $( echo " 192.168.1.24 " | tr " . " " n " | xargs printf ' \x%02X ' ) " ) > /dev/udp/127.1.1.1/1111
echo -ne $( echo " x11x11 $( echo " 192.168.1.25 " | tr " . " " n " | xargs printf ' \x%02X ' ) " ) > /dev/udp/127.1.1.1/1111
echo -ne $( echo " x11x11 $( echo " 192.168.1.26 " | tr " . " " n " | xargs printf ' \x%02X ' ) " ) > /dev/udp/127.1.1.1/1111
echo -ne $( echo " x11x11 $( echo " 192.168.1.27 " | tr " . " " n " | xargs printf ' \x%02X ' ) " ) > /dev/udp/127.1.1.1/1111
그런 다음 watch
명령을 사용하여 몇 초마다 해당 스크립트를 호출합니다.
$ watch -n10 ./lb.sh
Linux, Windows x64 및 Linux ARM용으로 사전 구축된 바이너리는 GitHub "릴리스"로 제공됩니다. 이것은 매우 간단한 .Net 8.0 프로젝트이므로 빌드하려면 실행하세요(dotnet-sdk-8.0이 설치되어 있다고 가정).
dotnet build
편리하고 성능상의 이점을 제공하는 기본 바이너리 실행 파일을 생성하고 싶을 수도 있습니다.
리눅스의 경우:
dotnet publish -o ./ -c Release -r linux-x64 /p:PublishSingleFile=true /p:PublishTrimmed=true --self-contained
Windows의 경우:
dotnet publish -o ./ -c Release -r win10-x64 /p:PublishSingleFile=true /p:PublishTrimmed=true --self-contained
마찬가지로 프로젝트 디렉터리에서 dotnet run
사용하여 실행하는 것도 간단합니다.
$ dotnet run
또는 기본 실행 파일을 빌드한 경우:
$ ./SimplestLoadBalancer
질문이나 버그 보고서가 필요하면 여기 GitHub에서 자유롭게 문제를 작성해 주세요. 제공된 템플릿이나 요구 사항은 없지만 최대한 설명적으로 작성해 주시면 합리적인 방식으로 대응하는 데 도움이 됩니다. 기여하기를 참조하세요.
즐기다!