Learning Platform
Глоссарий Troubleshooting
Урок 14.02 · 18 мин
Начальный
L4L7Load BalancerTCPHTTP

L4 vs L7 load balancing — transport против application

В первом уроке мы говорили о LB абстрактно — что он распределяет запросы. Пора углубиться: load balancer бывает двух принципиально разных уровней, и это меняет всё — от производительности до возможностей маршрутизации. Это L4 (Layer 4, transport-уровень) и L7 (Layer 7, application-уровень) балансировка.

Разница не в маркетинге, а в том, что LB видит и понимает про трафик. L4 видит только TCP-пакеты и IP-адреса. L7 разбирает HTTP, читает заголовки, понимает URL. Из этого вытекает всё остальное: скорость, гибкость, цена, типичные use cases. Давайте разберёмся, когда какой нужен — и почему в большой инфраструктуре обычно используют оба.


Что значит «уровень» — ставим в контекст OSI

Вернёмся к OSI-модели. Layer 4 — transport (TCP, UDP). Layer 7 — application (HTTP, gRPC, WebSocket). LB на уровне N знает протокол этого уровня и всех ниже, но не знает про уровни выше.

Что видит LB на разных уровнях
L7 LBРазбирает HTTP-протокол. Видит метод, путь, заголовки, тело. Может роутить по URL, по host header, по user-agent. Делает TLS termination -- расшифровывает трафик, чтобы его прочитать
HTTP
L4 LBРаботает с TCP/UDP. Не разбирает payload, видит только IP-адреса и порты. Прозрачный туннель: пакеты транзитом
TCP/UDP
IP layerУровень роутинга пакетов. Любой LB обязательно работает поверх IP -- это базовый транспорт

Главный практический вывод: L4 LB можно использовать для любого TCP/UDP-трафика, не только для HTTP. Это и MySQL, и Postgres, и Redis, и SMTP, и WebSocket, и gRPC, и игровые сервера. L7 LB — только для HTTP (и протоколов поверх HTTP — gRPC, WebSocket).

Второй вывод: L4 LB не может смотреть внутрь трафика. Если контент зашифрован TLS — L4 видит только зашифрованный поток байт и может его лишь перенаправить, не более.


L4 LB: тупой и быстрый

L4 LB работает на уровне TCP-соединения. Когда клиент устанавливает TCP-соединение с LB, LB:

  1. Принимает SYN, выбирает backend по своему алгоритму (round-robin, least-connections и т.п.).
  2. Устанавливает TCP-соединение с выбранным backend-ом.
  3. Дальше — пересылает байты в обе стороны без разбора. Что в этих байтах — HTTP, gRPC, MySQL-протокол, кто угодно — LB пофиг.

В терминах OSI это работа на L4 (transport): LB понимает TCP/UDP, но не знает, какой протокол поверх.

Жизненный цикл L4-соединения
ClientКлиент подключается к публичному IP LB на порту 443. Видит обычный TCP-сервер
SYN
L4 LBПринимает SYN, выбирает backend (например, Backend 2), сразу же открывает TCP к Backend 2
SYN
Backend 2Принимает TCP-соединение от LB. Не знает про реального клиента, видит IP LB как источник
ClientПосле handshake шлёт application data (HTTP/MySQL/что угодно)
bytes
L4 LBПересылает байты как есть, не парсит их. Просто copy from one socket to another
bytes
Backend 2Получает байты, обрабатывает по своему протоколу

Плюсы L4:

  • Скорость. Не нужно парсить HTTP, не нужно расшифровывать TLS. Просто перекидываем байты с одного сокета на другой. Производительность измеряется миллионами пакетов в секунду на скромном железе.
  • Любой протокол. MySQL, Redis, MQTT, custom binary — работает всё. Если у вас сервис на нестандартном TCP-протоколе — L4 единственный вариант.
  • Прозрачность для TLS. Если хотите end-to-end шифрование от клиента до backend без расшифровки на LB — L4 это позволяет. TLS-handshake происходит между клиентом и backend, LB просто пересылает зашифрованный поток.
  • Низкая нагрузка на CPU. LB не делает дорогих операций, поэтому держится на дешёвом железе.

Минусы:

  • Нет понимания контекста. Не можете роутить по URL, по host header, по user-agent.
  • Sticky sessions только по IP клиента. Если у клиента поменялся IP (mobile network) — сессия порвётся.
  • Не видит ошибки приложения. Backend может возвращать 500 на каждый запрос — L4 LB не заметит (TCP-соединение-то здоровое).
# Простейший L4 LB на HAProxy для MySQL
frontend mysql_in
    bind *:3306
    mode tcp
    default_backend mysql_pool

backend mysql_pool
    mode tcp
    balance roundrobin
    server db1 10.0.0.1:3306 check
    server db2 10.0.0.2:3306 check

mode tcp — ключевая директива. Она говорит HAProxy: не парси протокол, не пытайся понять, что там, просто туннелируй TCP.


L7 LB: умный и универсальный (для HTTP)

L7 LB разбирает HTTP-протокол. Каждый запрос для него — это набор смысловых единиц: метод (GET/POST), путь (/api/users), заголовки (Host: api.example.com), тело. На основе этого можно делать гораздо больше:

  • Path-based routing. /api/* -> один пул, /static/* -> другой пул (с большим кэшем).
  • Host-based routing. api.example.com и www.example.com могут идти на разные backend-ы, хотя у LB один IP.
  • Header-based routing. Canary deploy: запросы с X-Canary: true идут на новую версию, остальные — на старую.
  • TLS termination. LB сам расшифровывает HTTPS, backend получает чистый HTTP внутри сети. Меньше нагрузки на backend, проще управлять сертификатами централизованно.
  • Кэширование. Если ответ кэшируем (Cache-Control), LB может отдавать его без обращения к backend.
  • Application-aware health checks. Не «TCP-соединение открыто», а «GET /healthz вернул 200».
  • Compression. LB может сжимать ответы gzip/brotli, backend отдаёт без сжатия.
  • WAF (Web Application Firewall). Парсит запросы, блокирует SQL-инъекции и XSS-попытки.
L7 LB разбирает HTTP и делает решения
ClientДелает HTTPS-запрос GET https://api.example.com/v2/users
HTTPS
L7 LB1. Принимает TLS. 2. Расшифровывает. 3. Парсит HTTP. 4. Видит Host=api.example.com, path=/v2/users, header X-Region=EU. 5. Применяет правила маршрутизации
Routing rulesСписок правил: host + path + headers -> upstream pool. Сверху вниз, первое совпадение побеждает
Backend v1Старая версия API на /v1/*. Сюда L7 LB не направит этот запрос -- путь /v2/users не подходит
Backend v2Новая версия. Получает уже расшифрованный HTTP-запрос на /v2/users. Шлёт ответ обратно через LB

Минусы L7:

  • Медленнее, чем L4. Парсинг HTTP и TLS — это работа. Хотя «медленнее» относительно — современный NGINX легко тянет десятки тысяч RPS на одном CPU.
  • Только HTTP-семейство. MySQL, Redis и кастомные TCP-протоколы L7 LB не понимает.
  • TLS termination требует управления сертификатами. Сертификат должен лежать на LB.
  • Сложнее настраивать. Конфиг толще, правил больше, нюансов больше.

Сравнение в цифрах и фичах

СвойствоL4 LBL7 LB
Что видитTCP/UDP, IP, портыHTTP-метод, URL, заголовки
СкоростьОчень высокая, миллионы PPSВысокая, десятки тысяч RPS
Поддерживаемые протоколыЛюбой TCP/UDPТолько HTTP-семейство (включая gRPC, WebSocket)
TLS terminationНет (passthrough)Да
Routing по URL/headersНетДа
Sticky sessionsПо IP клиентаПо cookie, по header, по URL
Health checksTCP connect или TCP+простой pingHTTP-запрос с проверкой статуса/тела
Application logsТолько IP и портПолный HTTP request/response
Типичные продуктыAWS NLB, HAProxy TCP, IPVSAWS ALB, NGINX, Envoy, Traefik

Когда какой использовать

Правило большого пальца:

  • HTTP-API/веб-приложение — L7. Вам нужны path-based routing, TLS termination, application-level health checks.
  • База данных (MySQL/Postgres) или Redis — L4. Эти протоколы не HTTP, L7 LB их не понимает.
  • Long-lived TCP-соединения (game servers, message brokers) — L4. L7 LB не оптимален для соединений на часы.
  • Очень высокая нагрузка на edge (миллионы PPS) — L4 быстрее. Часто комбинируют: L4 на самом краю для скорости, L7 внутри для интеллекта.
  • Microservices с разными endpoint-ами на одном домене — L7. Без него никак: /users/* -> users-service, /orders/* -> orders-service.

В реальной production-системе крупного сервиса часто используют и L4, и L7 одновременно. Самый внешний слой — L4 (для скорости и DDoS-фильтрации), за ним — L7 (для умной маршрутизации).

Internet
  |
  v
+-------------------+
| L4 LB (AWS NLB)   | <- очень быстрый, фильтрует SYN-флуд
+-------------------+
  |
  v
+-------------------+
| L7 LB (NGINX/ALB) | <- TLS termination, routing
+-------------------+
  |
  v
+-------------------+
| Application       |
+-------------------+

TLS passthrough vs TLS termination

Тут важный момент. L4 LB не может расшифровать TLS, поэтому работает в режиме passthrough: клиент устанавливает TLS-соединение напрямую с backend, LB просто пересылает зашифрованные байты. Сертификат должен быть на backend.

L7 LB обычно работает в режиме TLS termination: TLS расшифровывается на LB, дальше до backend идёт plain HTTP (или новый TLS, который дешифруется заново — этот вариант называется TLS bridging).

TLS termination vs passthrough
Mode: terminationКлиент -- TLS --> LB --(plain HTTP)--> Backend. LB видит расшифрованный запрос, backend в защищённой сети
ClientДелает TLS-handshake с LB, шлёт зашифрованный запрос
TLS
LBРасшифровывает, парсит, может модифицировать (добавить X-Forwarded-For), шлёт plain HTTP
HTTP
BackendПолучает чистый HTTP. Доверяет LB как edge -- TLS уже произошёл
Mode: passthroughКлиент -- TLS --> Backend, LB только пересылает байты. LB не видит payload
ClientУстанавливает TLS-handshake с backend через LB. Сертификат -- на backend
TLS
LBНе видит содержимое, просто туннель. Не может роутить по host header (он зашифрован)
TLS
BackendИмеет приватный ключ и сертификат, расшифровывает запрос сам

Какой выбрать?

  • Termination — стандарт. Удобно, централизованное управление сертификатами, дешевле для backend-а. Используют 95% веб-сервисов.
  • Passthrough — когда нужна end-to-end защита (compliance), или когда LB не должен видеть содержимое (банки, медицина), или когда содержимое не HTTP (MySQL over TLS).
TIP

Есть третий вариант — SNI-based routing на L4. SNI (Server Name Indication) — расширение TLS, в котором клиент в открытом виде объявляет, к какому домену он подключается, до самого handshake. L4 LB может прочитать SNI (он в первом TLS-сообщении и не зашифрован) и роутить по нему — хотя при этом сам трафик остаётся зашифрованным. Это компромисс: получаем host-based routing без TLS termination.


Sticky sessions на L4 и L7

Sticky session (или session affinity) — это когда LB старается отправить все запросы одного пользователя на один и тот же backend. Зачем: если у вас приложение хранит state в памяти (sessions in memory, локальный кэш) — запросы должны идти на тот же инстанс. На самом деле это антипаттерн в современной архитектуре (stateless backends + external session store), но иногда быстрее наклеить sticky, чем переписать приложение.

Реализация на L4: по IP клиента. LB ведёт таблицу client_ip -> backend и пока IP тот же, направляет туда же. Минус: если у клиента поменялся IP (mobile network, NAT), он попадёт на другой backend — сессия теряется. Плюс: работает для любого TCP-протокола.

Реализация на L7: по cookie. LB добавляет в ответ свой cookie (например, LB_BACKEND=server2), а на следующих запросах читает его и направляет туда же. Не зависит от IP — работает корректно при смене сети. Минус: только для HTTP.

# L7 sticky на NGINX (требует commercial NGINX Plus или модуль sticky)
upstream app {
    sticky cookie srv_id expires=1h domain=.example.com;
    server 10.0.0.1;
    server 10.0.0.2;
    server 10.0.0.3;
}
# L4 sticky на HAProxy (по IP-source)
backend tcp_pool
    mode tcp
    balance source
    server srv1 10.0.0.1:5432 check
    server srv2 10.0.0.2:5432 check

Попробуй сам

Давайте попробуем оба режима на одной HAProxy-конфиге. Установите HAProxy (brew install haproxy или apt install haproxy) и создайте конфиг:

global
    log stdout local0

defaults
    log     global
    timeout connect 5s
    timeout client  30s
    timeout server  30s

# L4 (TCP) -- для любого TCP-сервиса, например, для MySQL
frontend mysql_in
    bind *:13306
    mode tcp
    default_backend mysql_pool

backend mysql_pool
    mode tcp
    balance roundrobin
    server db1 127.0.0.1:3306 check
    server db2 127.0.0.1:3307 check

# L7 (HTTP) -- понимает HTTP, может роутить
frontend http_in
    bind *:18080
    mode http
    use_backend api_v2 if { path_beg /v2/ }
    default_backend api_v1

backend api_v1
    mode http
    balance roundrobin
    server app1 127.0.0.1:8001 check
    server app2 127.0.0.1:8002 check

backend api_v2
    mode http
    balance roundrobin
    server app3 127.0.0.1:8003 check
    server app4 127.0.0.1:8004 check

Заметьте отличия:

  • В L4-секции mode tcp — HAProxy просто туннелирует.
  • В L7-секции mode http, и есть use_backend ... if { path_beg /v2/ } — это правило path-based routing. Запросы на /v2/* идут на пул v2, остальные — на v1.

Запустите четыре Python-сервера на портах 8001-8004 (python3 -m http.server 8001 и т.д.), запустите HAProxy, и проверьте:

haproxy -f /path/to/haproxy.cfg

# Запрос на v1 (попадёт в api_v1 pool):
curl http://localhost:18080/some/path

# Запрос на v2 (попадёт в api_v2 pool):
curl http://localhost:18080/v2/users

Поднимите stats-страницу HAProxy (она встроена), чтобы посмотреть статистику по backend-ам:

frontend stats
    bind *:8404
    mode http
    stats enable
    stats uri /

Откройте http://localhost:8404/ — увидите таблицу со всеми backend-ами, их статусом и метриками.


Kubernetes Service: ClusterIP это L4 LB, Ingress это L7 LB
Проверка знанийKnowledge check
Junior спрашивает: 'Если L7 LB круче и умнее, почему вообще используют L4? Не проще ли везде ставить L7 и забыть про L4?'
ОтветAnswer
L4 не 'хуже' -- он решает другие задачи. Три ключевые причины, почему он жив и нужен. Первая -- скорость. L7 LB должен парсить каждый HTTP-запрос: разобрать строки, выделить заголовки, понять путь. Это съедает CPU и добавляет латентности (десятки микросекунд). L4 LB просто пересылает байты с одного сокета на другой -- латентность близка к нулю, throughput измеряется миллионами пакетов в секунду на одном ядре. Для edge-балансировки на больших объёмах (фильтрация DDoS, входная точка SaaS на миллионы клиентов) L4 даёт большой выигрыш. Вторая -- L7 LB понимает только HTTP. Если ваше приложение -- MySQL, Postgres, Redis, MQTT, какой-нибудь свой бинарный протокол -- L7 LB вас не балансит, точка. Любая база за LB -- это L4 LB. Третья -- end-to-end шифрование. Если регуляторно или политически вы не хотите, чтобы LB видел расшифрованные данные (банки, медицинские записи, HIPAA, PCI-DSS Strict mode) -- L7 termination отпадает. L4 passthrough оставляет шифрование от клиента до backend нетронутым. В крупных архитектурах обычно используют оба: L4 на edge (за DDoS-фильтрацией), L7 ближе к приложению (для path-routing). Это не выбор, а специализация инструментов.

Проверьте понимание

Результат: 0 из 0
Концептуальный
Вопрос 1 из 6. Что фундаментально отличает L4 LB от L7 LB в плане 'видимости' трафика?

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс

Войдите чтобы оценить урок

Прогресс модуля
0 из 4