Как проксировать запросы определенного клиента на конкретный бэкенд

«Как проксировать запросы определенного клиента на конкретный бэкенд» — вопрос из категории Веб-серверы и балансировка, который задают на 23% собеседований Devops Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Для маршрутизации трафика от конкретного клиента к выделенному бэкенду я настраиваю условное проксирование в Nginx. Чаще всего это требуется для канареечных развертываний, тестирования новых версий или обслуживания VIP-клиентов.

Основной подход — использование директивы map и переменных:

# Определяем правило маршрутизации на основе IP-адреса клиента
map $remote_addr $backend_pool {
    "192.168.1.100" "backend_special";
    "10.20.30.40"   "backend_canary";
    default          "backend_default";
}

upstream backend_special {
    server 10.0.0.1:8080;
}

upstream backend_canary {
    server 10.0.0.2:8080;
}

upstream backend_default {
    server 10.0.0.3:8080;
    server 10.0.0.4:8080;
}

server {
    listen 80;
    server_name api.example.com;

    location / {
        # Динамическое проксирование на основе вычисленной переменной
        proxy_pass http://$backend_pool;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Альтернативные критерии маршрутизации, которые я использовал:

  1. По заголовку User-Agent или кастомному заголовку:

    map $http_user_agent $backend_pool {
        ~*mobile  "backend_mobile_optimized";
        default   "backend_default";
    }
  2. По cookie (например, для A/B-тестирования):

    map $cookie_experiment_group $backend_pool {
        "group_b" "backend_experiment";
        default    "backend_default";
    }
  3. По части пути URL:

    location ~ ^/api/v2/(.*)$ {
        # Все запросы к v2 API идут на новый бэкенд
        proxy_pass http://backend_v2/$1;
    }

Ключевые моменты:

  • Использование map предпочтительнее цепочки if, так как оно эффективнее и безопаснее.
  • Для сложной логики можно использовать переменную $request_id или вычислять хэш от определенных параметров запроса.
  • Важно настроить корректную передачу заголовков (особенно X-Forwarded-For) и таймауты (proxy_connect_timeout, proxy_read_timeout).