Как разделить трафик
По умолчанию все прокси в кластере имеют роль default. Это создаёт проблему «шумных соседей»: один пользователь, запустивший тяжёлую операцию чтения, может перегрузить прокси и замедлить работу всех остальных, включая запросы веб-интерфейса.
Решение — разбить прокси на группы с помощью ролей. Это позволит разделить нагрузку между лёгкими и тяжёлыми запросами, а также изолировать ресурсы разных проектов и команд.
В этой статье показано, как:
Разделение лёгкого и тяжёлого трафика (для HTTP)
На практике HTTP-прокси обычно делят на две функциональные группы:
- Control-прокси (обычно с ролью
control) — обслуживают «лёгкие» запросы: просмотр веб-интерфейса, листинг директорий, создание/удаление таблиц, работа с метаинформацией. - Data-прокси (обычно с ролью
default) — обслуживают «тяжёлые» запросы: чтение и запись таблиц или файлов.
Для отказоустойчивости рекомендуется, чтобы каждой роли соответствовало несколько реплик прокси.
Задать роли можно в спецификации Ytsaurus:
spec:
httpProxies:
# Тяжёлая группа (по умолчанию принимает Data-трафик)
- role: default
instanceCount: 5
serviceType: NodePort
# Контрольная группа (UI и метаданные)
- role: control
instanceCount: 2
serviceType: LoadBalancer # Удобно для Ingress
Примечание
Имя роли становится частью имени K8s-пода (например, hp-control-0). Поэтому используйте только DNS-совместимые имена (строчные буквы, цифры и дефисы). Символ подчеркивания (_) использовать нельзя.
Как это работает:
- Оператор создаёт две независимые группы подов (StatefulSet) с лейблами
controlиdefault. - Оператор автоматически создаёт Kubernetes-сервис (Service) для каждой группы. В селекторе сервиса
http-proxies-controlпрописан фильтр: «обслуживать только поды с меткой control». - Вы настраиваете Ingress/DNS на сервис группы
control. Клиенты будут автоматически получать адреса Data-прокси через механизм Discovery и отправлять тяжёлые запросы напрямую на них.
Примечание
При создании Service или Ingress вручную (без участия оператора) убедитесь, что в Label Selector сервиса прописан правильный фильтр по метке роли. Проверить лейблы на запущенных подах можно командой kubectl get pods --show-labels. Без этого фильтра балансировщик будет отправлять лёгкие запросы на все прокси подряд, включая Data-прокси.
Особенности HTTP доступа и Ingress
Для HTTP-прокси часто используют Ingress-контроллеры для терминации SSL и маршрутизации. Если Ingress используется только для Control-прокси, а Data-прокси выставлены через NodePort (как описано выше), схема работает эффективно.
Если же весь трафик требуется направить через Ingress (включая Data), придётся решить несколько проблем:
- Двойная балансировка и потеря эффективности.
- Сложные правила Ingress для каждого пода data-прокси отдельно (для прямой адресуемости).
- Настройка липких сессий для корректной работы с транзакциями.
Проблема липких сессий
При использовании Ingress для data-прокси важно учитывать особенности работы с транзакциями. Транзакции в YTsaurus создаются на конкретном прокси, и все последующие запросы в рамках одной транзакции должны попадать на тот же самый прокси. Вызов через Ingress-контроллер случайным образом может привести к ошибкам вида "Transaction not found" или "Invalid transaction state". Чтобы избежать этого, настройте липкие сессии в вашем Ingress-контроллере.
Настройка липких сессий зависит от используемого Ingress-контроллера:
- NGINX Ingress: используйте аннотацию
nginx.ingress.kubernetes.io/affinity: "cookie" - Traefik: настройте
stickinessв конфигурации сервиса - HAProxy Ingress: используйте
haproxy.org/cookie-persistence
Пример для NGINX Ingress с липкими сессиями
Этот Ingress настраивает NGINX, чтобы он помечал клиента специальной cookie и всегда отправлял его на один и тот же под прокси.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: yt-data-proxies
annotations:
# Включаем липкие сессии: NGINX запомнит, на какой под отправить клиента
nginx.ingress.kubernetes.io/affinity: "cookie"
nginx.ingress.kubernetes.io/session-cookie-name: "yt-proxy-id"
nginx.ingress.kubernetes.io/session-cookie-max-age: "14400"
spec:
rules:
- host: yt-data.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: http-proxies-default
port:
number: 80
Про TLS
Важно
При выставлении Data-прокси напрямую (через NodePort) трафик не проходит через Ingress, а значит, передается без TLS-шифрования.
Для высоконагруженных инсталляций, если нет жёстких требований к шифрованию, оптимальной остаётся раздельная схема:
- используйте Ingress только для Control-трафика (для удобного доступа к UI, лёгким API-запросам и HTTPS);
- Data-прокси публикуйте напрямую через NodePort или LoadBalancer с настроенным механизмом Discovery (трафик пойдёт открыто, но максимально производительно).
Если требования безопасности диктуют обязательное использование шифрования для внешних клиентов, есть два пути:
- направлять весь трафик через Ingress (с настроенными липкими сессиями), принимая во внимание возможное снижение производительности,
- либо настраивать балансировщики (Network Load Balancer) или внутренний TLS в самом кластере.
Изоляция проектов (для RPC)
Для RPC-прокси чаще применяется деление по проектам. Например, можно создать выделенную группу прокси с ролью project-a и выдать доступ к ней только конкретному пользователю.
spec:
rpcProxies:
# Поды для общих нужд
- role: default
instanceCount: 2
serviceType: NodePort
# Выделенные поды под проект Project A
- role: project-a
instanceCount: 2
serviceType: NodePort
Чтобы клиент начал работать с выделенной группой прокси, в коде приложения (или в настройках CLI) нужно явно указать proxy_role. Если этого не сделать, клиент по умолчанию пойдёт в роль default.
Пример для Python
# Пример клиента Python, жестко привязанного к группе
client = yt.YtClient(proxy="yt.cluster", config={"proxy_role": "project-a"})
Пример для CLI
# Можно передать через переменную окружения перед запуском скриптов
export YT_CONFIG_PATCHES='{proxy_role="project-a"}'
yt list //home
Липкие сессии (sticky sessions) — механизм балансировки, при котором Ingress-контроллер привязывает клиента к конкретному серверу (поду) на время всей сессии. При первом обращении балансировщик выдаёт клиенту специальную cookie-метку, благодаря которой все последующие запросы гарантированно попадают на тот же самый под.