Балансировщик L4 выбирает бэкенд по четырём полям пакета: IP-адрес источника, IP-адрес назначения, порт источника и порт назначения. Содержимое запроса он не читает, поэтому одинаково работает с MySQL, PostgreSQL, Redis, DNS, SIP, MQTT, игровыми серверами и самописным TCP-протоколом. Если задача формулируется как «разложить TCP или UDP по нескольким серверам, не потеряв сессии», решение стоит искать на транспортном уровне.
L7-балансировщик устроен иначе: он завершает клиентское соединение, разбирает HTTP, находит путь, заголовок или cookie и только потом выбирает бэкенд. Отсюда маршрутизация по /api/v2 и канареечные релизы, но каждый запрос проходит через парсер. Разница в стоимости обработки и определяет выбор: L4 проксирует байты, L7 разбирает и пересобирает прикладной протокол.
Ниже механика решений на транспортном уровне, сравнение L4 и L7 по конкретным признакам, шаблоны конфигураций HAProxy, Nginx stream и IPVS в Kubernetes, разбор режимов DNAT, DR и туннелирования и список ошибок, которые чаще всего ломают продакшен при первом запуске L4-схемы.
Что такое L4-балансировка и как она работает на уровне IP и порта
Транспортный уровень оперирует TCP и UDP. L4-балансировщик видит адресную информацию этих протоколов и ничего выше. Клиент обращается к виртуальному адресу, например 203.0.113.10:3306, балансировщик выбирает реальный сервер 10.0.0.11:3306 и переписывает адрес назначения. Всё, что летит внутри соединения, для него поток байт.
После перезаписи балансировщик ведёт таблицу соединений: по ней возвратный трафик находит нужного клиента. В режимах с прямым ответом таблица нужна только для учёта сессий, потому что ответы уходят от сервера напрямую в сеть.
Виртуальный адрес (VIP) не привязан к одному серверу. Это адрес, который балансировщик принимает на себя, а бэкенды о нём могут даже не знать. Отсюда требования к сети: маршрут до VIP должен вести на активный балансировщик, иначе пакеты уйдут мимо.
Что L4 не умеет: маршрутизировать по URL, читать заголовок Host, учитывать cookie, выбирать сертификат по SNI, повторять отдельный запрос. Раскладка по прикладным признакам требует L7. Что умеет: тратить минимум CPU на одну сессию, работать с протоколами без публичной документации и не портить бинарные данные внутри потока.
Предупреждение. Ошибка в конфигурации L4 рвёт соединения пачками. Неверный таймаут убивает долгие сессии к базе, неверный баланс сваливает весь трафик на один узел, забытая проверка доступности отправляет половину клиентов на мёртвый сервер. Перед правкой сохраните рабочую конфигурацию, проверьте синтаксис утилитой самого балансировщика и прогоните сценарий на стенде.
Ключевые отличия L4 от L7: что и когда выбирать
| Признак | L4 | L7 |
|---|---|---|
| Уровень OSI | Транспортный | Прикладной |
| Что видит балансировщик | IP-адреса, порты, тип протокола TCP или UDP | Метод, путь, заголовки, cookie, TLS SNI |
| Что умеет | Перекидывать поток, держать таблицу соединений, привязывать клиента к серверу по IP | Маршрутизировать по пути и заголовкам, завершать TLS, делать canary-релизы и ретраи |
| Стоимость обработки | Низкая: парсинга нет | Выше: разбор каждого запроса и ответа |
| Типичные задачи | MySQL, PostgreSQL, Redis, DNS, SIP, MQTT, игровые сервера | HTTP API, gRPC, статика, канареечные развёртывания |
| Сохранение сессий | Хеш от IP источника, таблицы соединений, таймауты | Cookie, sticky-сессии на уровне приложения |
Правило простое: нужен прикладной контекст (путь, заголовок, cookie, SNI), берите L7. Нужен сам поток и его пропускная способность, берите L4. На практике роли часто совмещают: L4-балансировщик стоит первым и раздаёт трафик на пул L7-прокси, которые уже разбирают HTTP.
WebSocket относится к прикладному уровню и начинается как обычный HTTP-запрос с предложением сменить протокол. Балансировать его на чистом L4 можно, но задержку маршрутизации это не убирает: практическое руководство по WebSocket прямо оговаривает, что протокол работает поверх TCP и не отменяет задержки шифрования, маршрутизации и обработки данных.
Если нужно освежить, какие устройства и какие данные относятся к каждому уровню, пригодится разбор уровней маршрутизации от L2 до L7 с привязкой к модели OSI.
Преимущества L4-балансировки: производительность и низкие задержки
Выигрыш складывается из трёх факторов. Нет парсинга прикладного протокола, поэтому на соединение уходит меньше инструкций CPU. Нет буферизации тел запросов, поэтому на бэкенд тратится меньше памяти. Нет терминации TLS, если её не добавить специально, поэтому нет двойного шифрования на пути клиент - балансировщик - сервер.
IPVS работает через модуль ядра и использует структуры данных ядра, включая хеш-таблицы, для поиска сервиса, поэтому трафик не поднимается в userspace. Хеш-таблица соединений IPVS применяет схему цепочек (chaining) для обработки коллизий, а большая хеш-таблица существенно снижает конфликты при сотнях тысяч соединений в ней. За счёт этого IPVS даёт преимущество по производительности перед iptables в кластерах с большим числом сервисов: в больших кластерах он обеспечивает более быструю синхронизацию правил и более высокую пропускную способность, чем iptables. Конкретные числа задержек на хвостах распределения и максимум новых соединений в секунду зависят от железа, размера записи conntrack, размера пакета и профиля трафика, поэтому ориентиром должен быть бенчмарк на вашем стенде, а не цифры из рекламных слайдов.
Для UDP альтернатив почти нет. У протокола нет рукопожатия и повторов, прикладной сессии тоже нет, поэтому держать состояние на балансировщике дороже и хрупче, чем раскладывать датаграммы по IP и порту. DNS, VoIP, стриминг, телеметрия и игровые сервера живут именно в этой схеме.
Высокая пропускная способность мониторинг не отменяет. Смотрите число активных сессий, скорость установления соединений, ошибки подключения к бэкендам, счётчики повторных попыток, дропы на интерфейсах и время ответа серверов. Таймауты подбирайте под самый долгий реальный запрос, а не оставляйте по умолчанию.
Практическая настройка L4-балансировки: HAProxy, Nginx stream и IPVS
Шаблоны ниже описывают базовый синтаксис директив. Конкретные версии HAProxy, Nginx, IPVS и Kubernetes в исходных материалах не зафиксированы, поэтому перед применением сверьте директивы с документацией вашей сборки, проверьте конфигурацию штатной утилитой и повторите сценарий на стенде.
Настройка HAProxy для TCP и UDP
Для TCP-трафика достаточно режима mode tcp: HAProxy не станет разбирать прикладной протокол и просто перенаправит поток.
global
maxconn 20000
log /dev/log local0
defaults
mode tcp
option tcplog
timeout connect 5s
timeout client 30m
timeout server 30m
frontend mysql_in
bind 203.0.113.10:3306
default_backend mysql_servers
backend mysql_servers
balance leastconn
server db1 10.0.0.11:3306 check inter 2s rise 2 fall 3
server db2 10.0.0.12:3306 check inter 2s rise 2 fall 3 backup
Разбор параметров. bind задаёт адрес и порт, который слушает балансировщик. balance leastconn отправляет новое соединение на сервер с наименьшим числом активных сессий, для баз данных это обычно ровнее, чем roundrobin. check включает проверку доступности, inter задаёт интервал проверки, rise и fall определяют, сколько успешных или неуспешных попыток нужно для смены статуса. Флаг backup оставляет второй сервер в резерве до отказа основного.
UDP описывается отдельным фронтендом и бэкендом с mode udp.
frontend dns_in
bind 203.0.113.10:53
mode udp
default_backend dns_servers
backend dns_servers
mode udp
balance roundrobin
server dns1 10.0.0.21:53
server dns2 10.0.0.22:53
В режиме UDP возможности проверок ограничены: полноценного TCP-рукопожатия нет. В HAProxy ALOHA для UDP-бэкендов есть директива option udp-check: она отправляет zero-byte UDP-датаграмму на адрес и порт целевого сервера и читает очередь ошибок ядра UDP-сокета. Если ядро доставляет ошибку ICMP Destination Unreachable, сервер помечается как down; если ошибки нет — как up. ICMP echo при этом не используется, но промежуточные файрволы должны пропускать ICMP Unreachable обратно к балансировщику, иначе UDP-модуль, не получив ошибку, будет считать сервер живым, даже если он таковым не является. Если файрвол не может пропускать такой трафик, надёжнее использовать TCP-проверки или внешний монитор, который шлёт реальные запросы к сервису. Проверка конфигурации перед перезагрузкой обязательна: haproxy -c -f /etc/haproxy/haproxy.cfg, затем systemctl reload haproxy, чтобы не рвать активные сессии. Полный пример с терминацией TLS и проверками есть в руководстве по балансировке TCP/UDP для SSH, MySQL, PostgreSQL и DNS.
Использование Nginx stream для L4-балансировки
Модуль ngx_stream_core_module даёт Nginx отдельный блок stream, который живёт на уровне main рядом с http, но не пересекается с ним.
stream {
upstream postgres_backend {
least_conn;
server 10.0.0.31:5432 max_fails=3 fail_timeout=10s;
server 10.0.0.32:5432 max_fails=3 fail_timeout=10s;
}
server {
listen 5432;
proxy_pass postgres_backend;
proxy_connect_timeout 3s;
proxy_timeout 30m;
}
}
Директива listen открывает порт, proxy_pass отправляет поток в upstream, least_conn выбирает сервер с минимумом активных соединений. proxy_timeout задаёт время простоя до закрытия соединения: для репликации и долгих транзакций значение по умолчанию слишком мало, поэтому его увеличивают осознанно.
stream {
upstream dns_udp {
server 10.0.0.21:53;
server 10.0.0.22:53;
}
server {
listen 53 udp;
proxy_pass dns_udp;
proxy_responses 1;
}
}
Проверки доступности различаются по редакциям. NGINX Open Source бесплатен и предоставляет настраиваемые пассивные проверки работоспособности, а NGINX Plus даёт продвинутые активные проверки и коммерческую поддержку. Пассивные проверки доступны в обеих редакциях: в open-source Nginx они работают через директивы max_fails и fail_timeout в блоке upstream — когда число ошибок достигает max_fails за период fail_timeout, сервер помечается как нерабочий на этот же период. Активные проверки — эксклюзивная функция NGINX Plus: балансировщик сам инициирует соединения с бэкендами по расписанию и проверяет их состояние независимо от пользовательского трафика. Перед запуском убедитесь, что модуль собран: nginx -V 2>&1 | grep with-stream. Без него директива stream вызовет ошибку конфигурации. Синтаксис проверяйте командой nginx -t, применяйте через systemctl reload nginx.
IPVS в Kubernetes: L4-балансировка для сервисов
kube-proxy умеет работать в нескольких режимах, и один из них, IPVS, даёт L4-балансировку через ядро Linux с набором планировщиков. Режим задаётся в ConfigMap kube-proxy.
kubectl -n kube-system get configmap kube-proxy -o yaml
# фрагмент конфигурации
mode: "ipvs"
ipvs:
scheduler: "rr"
strictARP: true
Scheduler принимает значения rr, wrr, lc, wlc, sh (хеш по IP источника), mh и другие. Для bare-metal кластеров strictARP помогает корректно отвечать на ARP-запросы к виртуальным адресам.
Посмотреть созданные сервисы и статистику можно через ipvsadm, который читает те же таблицы ядра:
ipvsadm -Ln ipvsadm -Ln --stats
Виртуальный сервис можно создать и вручную, чтобы понять модель целиком. Флаг -m в последней строке включает режим masquerading, то есть DNAT, остальные режимы разобраны ниже.
ipvsadm -A -t 10.96.0.10:80 -s rr ipvsadm -a -t 10.96.0.10:80 -r 10.244.1.5:8080 -m ipvsadm -a -t 10.96.0.10:80 -r 10.244.2.7:8080 -m
Для работы kube-proxy в режиме IPVS требуются модули ядра ip_vs, ip_vs_rr, ip_vs_wrr, ip_vs_sh и nf_conntrack_ipv4 (для ядра Linux 4.19 и новее), скомпилированные в ядро узла. Перед включением режима установите требуемые модули и проверьте их загрузку командой lsmod | grep ip_vs. Если требования не выполнены, kube-proxy откатывается в режим IPTABLES. Смена режима kube-proxy требует перезапуска подов kube-proxy и кратко влияет на обработку новых сервисных соединений, поэтому планируйте её в окно обслуживания. Готовые конфигурации для кластера собраны в материале про балансировку и маршрутизацию в Nginx и Kubernetes.
Режимы L4-балансировки: DNAT, DR и туннелирование
Режим определяет, что именно балансировщик меняет в пакете и как возвращается ответ. От этого зависят требования к сети, влияние на сохранение сессий и устойчивость к отказу.
| Режим | Что меняется в пакете | Путь ответа | Требования |
|---|---|---|---|
| DNAT (в IPVS флаг -m) | IP-адрес и порт назначения | Через балансировщик | Балансировщик видит весь трафик, схема строится при любой топологии |
| DR, direct routing (флаг -g) | MAC-адрес назначения, VIP сохраняется | От сервера напрямую клиенту | Балансировщик и серверы в одном L2-сегменте, VIP на loopback серверов, настройки arp_ignore и arp_announce |
| Туннелирование (флаг -i) | Пакет инкапсулируется в IP-туннель | От сервера напрямую или через туннель | Серверы могут быть в другой подсети, обязательный запас MTU |
DNAT удобен тем, что балансировщик видит обе стороны сессии: он переписывает адрес назначения и без дополнительных настроек возвращает ответ клиенту. Цена: обратный трафик тоже проходит через него, поэтому пропускная способность балансировщика становится потолком, а сам он превращается в единую точку отказа.
DR переписывает только MAC-адрес, а виртуальный IP остаётся в пакете. Сервер видит запрос на свой собственный VIP, настроенный на loopback-интерфейсе, и отвечает клиенту напрямую. Так снимается нагрузка с балансировщика, но появляются требования к сети: один широковещательный домен и параметры ядра, запрещающие серверу отвечать на ARP-запросы за VIP.
Туннелирование (IP-IP) инкапсулирует исходный пакет целиком и отправляет его на сервер в другой подсети. Добавленный заголовок съедает часть MTU, поэтому размер сегмента на серверах и клиентах приходится уменьшать или включать корректное определение MTU, иначе крупные пакеты будут молча теряться.
Выбор типа туннеля в инструментах туннелирования обычно сводится к трём вариантам. В описании CLI fxTunnel при создании туннеля указывают тип http, tcp или udp и локальный порт, то есть транспорт выбирается на этапе конфигурации, а не в момент запроса.
Сохранение сессий при L4-балансировке
L4 не видит cookie, поэтому привязка клиента к конкретному серверу строится на сетевых признаках. Рабочие варианты: хеш от IP источника (balance source в HAProxy, ip_hash в Nginx stream, планировщик sh в IPVS), таблицы соединений с таймаутом, привязка по порту источника для UDP.
У хеширования есть побочный эффект: клиенты за одним NAT попадают на один и тот же бэкенд, и распределение получается неравномерным. Для TCP частично помогает таблица соединений: сессия уже установлена и живёт, пока не истечёт таймаут. Для UDP такой таблицы может не быть вовсе, поэтому датаграммы одного клиента обязаны попадать на один сервер по хешу.
Режим влияет на сложность привязки. В DNAT балансировщик видит все пакеты и может вести точную таблицу сессий. В DR и туннелировании ответы идут мимо него, поэтому привязка опирается только на входящий поток, а синхронизация состояния между балансировщиками требует отдельных механизмов.
Отказоустойчивость L4-балансировщика
Классическая схема: два узла и виртуальный IP, которым управляет VRRP-демон, чаще всего keepalived. Один узел активен, второй держит тот же конфиг и принимает адрес при отказе. Переключение занимает секунды и укладывается в настройки VRRP.
При переключении важна синхронизация таблиц сессий. HAProxy умеет передавать состояние через секцию peers: система синхронизации пиров позволяет нескольким экземплярам HAProxy обмениваться данными stick-table в реальном времени, а при создании, обновлении или истечении записей на одном узле изменения распространяются на всех подключённых пиров. Без этого соединения, установленные до отказа, оборвутся.
В DR и туннелировании ограничение на одну активную точку слабее: несколько балансировщиков могут анонсировать один адрес через ECMP или anycast, потому что ответы всё равно идут от серверов напрямую. Схемы Active/Passive и Active/Active с дорожной картой разобраны в материале про архитектуры развёртывания балансировки.
Предупреждение. При отказе балансировщика в режиме DNAT без синхронизации сессий клиенты получают разрыв там, где соединение должно было жить часами: репликация, долгие транзакции, стриминг.
Типичные ошибки и риски при настройке L4-балансировки
- Режим выбран без учёта топологии. DR требует одного L2-сегмента и настройки ARP на серверах. Если серверы разнесены по подсетям, берите DNAT или туннелирование.
- Нет проверок доступности. Без check в HAProxy или max_fails в Nginx трафик уходит на упавший сервер. Проверки нужны, даже если сервисов два.
- Таймауты по умолчанию. Значения в несколько минут рвут WebSocket-сессии, репликацию и длинные SQL-запросы. Задержку маршрутизации WebSocket не отменяет: разбор протокола отдельно отмечает шифрование, маршрутизацию и обработку как источники задержки, а таймаут балансировщика добавляется сверху.
- Забыт MTU при туннелировании. Инкапсуляция уменьшает полезный размер пакета, крупные ответы теряются без ошибок в логах приложения.
- Асимметричная маршрутизация. В DR ответы уходят от сервера напрямую, и если сеть отправляет их через балансировщик, соединения зависают.
- Одна точка отказа. Один балансировщик без VRRP и без синхронизации сессий превращает плановое обновление конфигурации в простой сервиса.
- Нет наблюдаемости. Без метрик по активным сессиям, ошибкам подключения и переключениям бэкендов деградация становится заметна от клиентов, а не от мониторинга.
- Правка продакшена без проверки синтаксиса. Сначала haproxy -c или nginx -t, потом reload. Для диагностики используйте tcpdump на интерфейсе балансировщика и ipvsadm -Ln на узле.
Отдельно про актуальность: конкретные версии HAProxy, Nginx, IPVS и Kubernetes в предоставленных источниках не указаны, поэтому воспринимайте шаблоны как базовый синтаксис и сверяйте поведение директив с документацией вашей сборки. Смежные темы по фильтрации трафика и маршрутизации на уровне сети собраны в руководстве по маршрутизации 2026 года.
Заключение: как выбрать подходящий L4-инструмент под вашу нагрузку
Критериев четыре: тип трафика, требования к задержке и пропускной способности, нужна ли привязка клиента к серверу и как быстро сервис должен восстанавливаться после отказа.
| Ситуация | Что взять | Почему |
|---|---|---|
| TCP-сервисы с гибкими правилами и проверками: базы данных, брокеры, SSH | HAProxy | Тонкая настройка таймаутов, режимов и проверок доступности в одном конфиге |
| Nginx уже стоит в инфраструктуре, нужен ещё и L4 | Nginx stream | Один бинарник и один стиль конфигурации, общий reload |
| Много коротких соединений и максимум пропускной способности | IPVS | Работа в ядре через хеш-таблицы, набор планировщиков |
| Сервисы в Kubernetes | kube-proxy в режиме IPVS | L4-балансировка сервисов средствами кластера без внешнего прокси |
Порядок действий для первого запуска: определите протокол и режим (DNAT для простой топологии, DR для высокой пропускной способности в одном L2-сегменте, туннелирование для разнесённых серверов), задайте таймауты под самый долгий запрос, включите проверки доступности, соберите метрики по сессиям и переключениям, продумайте второй узел с VRRP и синхронизацией состояния. Проверьте конфигурацию на стенде и только потом переносите на продакшен.