SLB — это балансировщик нагрузки без сеансов для UDP-трафика, который решает проблемы, связанные с использованием традиционных (многофункциональных) балансировщиков нагрузки для такого трафика.
Для простых протоколов UDP без сохранения состояния нет смысла пытаться поддерживать «сходство» (также известное как «сеансы») между клиентами и серверными экземплярами. Традиционные балансировщики нагрузки предполагают, что сходство полезно, и поэтому пытаются маршрутизировать пакеты от клиента к согласованному внутреннему серверу. Напротив, SLB равномерно (случайно) распределяет пакеты один за другим по всем доступным серверным узлам. Это приводит к равномерной загрузке серверных частей и повышению устойчивости при сбое одного экземпляра серверной части (будет увеличиваться потеря пакетов для всех клиентов, а не полная потеря трафика для некоторых клиентов).
По умолчанию SLB будет прослушивать порты 1812
и 1813
на предмет входящих пакетов UDP и ретранслировать их случайным известным ему внутренним целям. Порты, которые он прослушивает, могут иметь параметр --server-port-range
, который принимает один порт (например, 541
) или диапазон портов (например, 4000-5000
).
Чтобы SLB знал о бэкэндах, необходимо отправлять пакеты «сторожевого таймера» (также известные как «поддерживать активность») на порт администратора (подробнее об этом ниже). По умолчанию порт администратора — 1111
, но его можно настроить с помощью опции --admin-port
. Если в вашей системе присутствует несколько сетевых карт, вы можете указать IP-адрес с помощью опции --admin-ip
. Если IP-адрес, указанный с помощью --admin-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
Серверные части не настраиваются в командной строке. Скорее, они динамически регистрируются и отменяются с помощью периодических пакетов UDP, отправляемых на порт администратора ( --admin-port
). Содержимое этих пакетов может отличаться в зависимости от того, как вы используете SLB в своей среде.
Если вы используете один сервер SLB, серверные части можно настроить для отправки пакетов на этот один IP-адрес и на порт администратора. Это самый простой сценарий. Каждый бэкэнд будет отправлять сообщения с двумя «магическими байтами», обозначающими «регистрацию бэкэнда» для контента:
0x11 0x11
SLB интерпретирует такой пакет как «зарегистрируйте отправителя как серверную часть». Опционально сообщения могут содержать один или два дополнительных байта (вес и идентификатор группы), назначение которых будет более подробно рассмотрено ниже.
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
Опять же, опционально могут быть добавлены байты веса и идентификатора группы.
Когда требуется более надежное развертывание высокой доступности с несколькими SLB, связь между серверными модулями и SLB можно упростить с помощью IP-адреса группы многоадресной рассылки. Это полезно, поскольку каждый SLB должен знать о каждом бэкэнде. В таком случае серверы SLB должны использовать опцию --admin-ip
для указания адреса многоадресной рассылки, который приведет к тому, что SLB присоединятся к группе многоадресной рассылки и, следовательно, все получат любое сообщение, отправленное на этот IP. Серверные части можно настроить с использованием этого одного IP-адреса, что минимизирует их рабочую нагрузку и упрощает настройку (особенно, когда SLB включаются и выключаются из-за автоматического масштабирования и/или использования спотовых экземпляров).
Обратите внимание, что для использования многоадресного IP-адреса требуется либо коммутатор, поддерживающий многоадресную рассылку, либо (что более вероятно) работа в AWS VPC, настроенном с многоадресным доменом.
Начиная с версии 2.0 форматы пакетов администратора очень просты. В простейшем случае использования одного SLB регистрационный пакет от серверной части может состоять не более чем из двух магических байтов ( 0x11
0x11
). При желании пакеты могут исходить из другого источника (например, сервера управления) и содержать четыре байта для указания IPv4-адреса серверной части. В любом случае могут быть добавлены два дополнительных необязательных байта для «веса» трафика относительно других серверных частей и для «группы», назначаемой серверной части (подробнее о группах ниже). В ASCII-искусстве:
0x11 0x11 [X X X X] [X] [X]
^ ^ ^
| | |
| | one byte for group id
| |
| one byte for weight
|
four bytes for ip to add
Чтобы немедленно удалить цель, отправьте пакет с 0x86
в качестве первого байта вместо 0x11
(если он отправлен с сервера управления, добавьте IP-адрес удаляемого бэкэнда):
0x86 0x11 [X X X X]
^
|
four bytes for ip to remove
Веса используются для управления относительным объемом трафика, доставляемого на каждый сервер. Если вес не указан, к серверной части будет применено значение по умолчанию 100 (настраиваемое с помощью --default-target-weight
), и каждый из них получит одинаковый объем пакетов. Тем не менее, ожидается (и желательно), чтобы бэкэнды настраивали значение веса в своих административных пакетах в зависимости от их способности обрабатывать трафик (возможно, снижается при высокой загрузке ЦП, применении обновлений и т. д.). Например:
100
, 50
и 50
соответственно, то первый получит 50% трафика, а второй и третий получат по 25%.31
и 31
соответственно, то каждый получит 50% трафика.При использовании групп относительные веса оцениваются по сравнению с другими серверными модулями в той же группе (не по всем группам).
Важно отправлять административные пакеты надежно и с достаточной частотой. Каждый раз, когда SLB получает пакет, время последнего посещения серверной части обновляется. Если в течение 30 секунд (настраиваемых с помощью
--target-timeout
) бэкэнд не будет виден, он будет удален, и дальнейший трафик на него отправляться не будет.
По умолчанию все серверные части будут использоваться для обслуживания всех портов, обслуживаемых балансировщиком нагрузки.
Однако можно назначить отдельные порты подмножествам серверных частей, используя сообщения о назначении портов SLB и предоставляя идентификаторы групп в регистрационных сообщениях. Предположим, например, что вы хотели бы иметь трафик балансировки нагрузки SLB для портов 1812–1813, но назначать трафик, поступающий на каждый порт, другому набору серверов. Для этого:
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
Вероятно, вы захотите создать собственный двоичный исполняемый файл, который удобен и обеспечивает некоторые преимущества в производительности.
Для Linux:
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, с вопросами и отчетами об ошибках. Шаблон или требования не предоставляются, но, пожалуйста, постарайтесь быть как можно более описательными — это поможет нам гарантировать, что мы сможем ответить разумным образом. См. также «Внесение вклада».
Наслаждаться!