Что такое L7-балансировщик нагрузки и в чем его отличие от L4?

Ответ

L7-балансировщик — это балансировщик нагрузки, работающий на седьмом, прикладном уровне модели OSI (Application Layer). В отличие от L4-балансировщика, который оперирует на уровне транспортных протоколов (TCP/UDP) и видит только IP-адреса и порты, L7-балансировщик "понимает" протоколы прикладного уровня, такие как HTTP, HTTPS, gRPC.

Ключевые отличия от L4

  • L4 (Транспортный уровень): Маршрутизирует трафик на основе IP-адреса и порта источника/назначения. Он не анализирует содержимое пакетов. Работает быстро, но с ограниченной гибкостью.
  • L7 (Прикладной уровень): Анализирует содержимое запроса (URL, HTTP-заголовки, cookies, тело запроса) и принимает решение о маршрутизации на основе этих данных. Это позволяет реализовать более сложную логику.

Основные возможности и преимущества L7

  1. Content-Based Routing: Маршрутизация на разные группы серверов в зависимости от пути (/api/v1, /users) или поддомена (api.example.com).
  2. Sticky Sessions (Прилипчивые сессии): Возможность направлять все запросы от одного клиента на один и тот же бэкенд-сервер, используя cookies.
  3. SSL/TLS Termination: L7-балансировщик может расшифровывать HTTPS-трафик, снимая эту нагрузку с бэкенд-серверов. Сервера за балансировщиком могут общаться по обычному HTTP.
  4. Перезапись URL и заголовков: Модификация запросов "на лету" перед отправкой на бэкенд.

Пример на Go (Reverse Proxy)

В Go L7-балансировщик можно реализовать с помощью httputil.ReverseProxy. В этом примере трафик, идущий на /api, направляется на API-сервис, а весь остальной — на веб-сервис.

package main

import (
    "log"
    "net/http"
    "net/http/httputil"
    "net/url"
    "strings"
)

// director определяет, на какой бэкенд отправить запрос
func director(req *http.Request) {
    // Парсим URL целевых сервисов
    apiBackend, _ := url.Parse("http://api-backend:8080")
    webBackend, _ := url.Parse("http://web-backend:8081")

    // Если путь начинается с /api, отправляем на API-сервис
    if strings.HasPrefix(req.URL.Path, "/api") {
        req.URL.Scheme = apiBackend.Scheme
        req.URL.Host = apiBackend.Host
    } else {
        // Иначе — на веб-сервис
        req.URL.Scheme = webBackend.Scheme
        req.URL.Host = webBackend.Host
    }
}

func main() {
    proxy := &httputil.ReverseProxy{Director: director}
    log.Println("Starting L7 reverse proxy on :80")
    if err := http.ListenAndServe(":80", proxy); err != nil {
        log.Fatal(err)
    }
}