Trino Gateway: маршрутизация, балансировка, blue/green апгрейды
В модуле про fault tolerance мы пришли к идее нескольких кластеров: отдельный интерактивный кластер с retry-policy=NONE и отдельный batch-кластер с retry-policy=TASK. Но у такого подхода есть нерешённая проблема: клиентам теперь нужно знать про несколько кластеров и выбирать, к какому подключаться. А ещё — что делать при апгрейде кластера, не роняя пользователей.
Обе проблемы решает Trino Gateway — балансировщик, прокси и маршрутизирующий шлюз для нескольких кластеров Trino. Этот урок разбирает, что даёт Gateway: единый URL, маршрутизацию и балансировку, привязку запроса к кластеру по query id и апгрейды без простоя.
Зачем нужен Gateway
Без Gateway множество кластеров — это головная боль для клиентов. Каждый BI-инструмент, каждое приложение должно знать адреса всех кластеров и логику «интерактив — туда, batch — сюда». Добавили кластер, вывели кластер на обслуживание — правь конфигурацию у всех клиентов. Это не масштабируется.
Trino Gateway ставится перед кластерами Trino. Клиенты подключаются не к кластерам, а к Gateway — по одному URL. Gateway уже сам решает, на какой кластер направить запрос. Для клиента множество кластеров становится невидимым: он видит «один Trino», а за шлюзом — сколько угодно кластеров под разные нагрузки.
Trino Gateway — отдельный продукт со своим репозиторием (trinodb/trino-gateway) и собственной версионностью, не совпадающей с номерами релизов Trino. Это не часть ядра Trino, а самостоятельный компонент, который ставят рядом.
Маршрутизация и балансировка
Главная работа Gateway — решить, на какой кластер отправить пришедший запрос. Gateway группирует кластеры в routing groups (группы маршрутизации) — например, группа interactive и группа batch — и направляет запрос в подходящую группу, а внутри группы балансирует нагрузку между её кластерами.
Как Gateway выбирает группу — поддерживается несколько стратегий маршрутизации:
| Стратегия маршрутизации | Как выбирается группа/кластер |
|---|---|
| По HTTP-заголовку | клиент указывает целевую routing group заголовком запроса |
| Правила (rules engine) | набор правил на MVEL-выражениях сопоставляет атрибуты запроса с группой |
| Внешний сервис | решение о маршрутизации делегируется внешнему сервису |
| По нагрузке | запрос направляется на менее загруженный кластер |
Внутри выбранной routing group Gateway распределяет запросы между её кластерами — adaptive (с учётом загрузки) или round-robin. Так Gateway совмещает две функции: маршрутизацию (в правильную группу под тип нагрузки) и балансировку (равномерно по кластерам внутри группы).
Практический смысл — ровно тот, к которому мы шли в модуле про fault tolerance. Routing group interactive ведёт на NONE-кластеры, группа batch — на TASK-кластеры с FTE. Клиент дашборда и клиент тяжёлого ETL ходят на один URL Gateway, а тот разводит их по кластерам с подходящей retry-policy. Разделение кластеров остаётся прозрачным.
Привязка запроса к кластеру по query id
Тонкий, но важный механизм. Протокол Trino — не «один запрос = одно HTTP-обращение». Клиент отправляет statement, получает в ответе query id и nextUri, а потом многократно опрашивает nextUri, забирая страницы результата. То есть один запрос — это серия HTTP-обращений во времени.
Возникает проблема для шлюза. Запрос исполняется на конкретном кластере. Если Gateway первое обращение направит на кластер A, а последующие polling-обращения того же запроса по балансировке улетят на кластер B — там про этот запрос ничего не знают, и всё ломается.
Gateway решает это привязкой по query id. Из ответа на первое обращение Gateway извлекает query id и запоминает, на какой кластер этот запрос ушёл. Все последующие обращения с тем же query id Gateway направляет на тот же кластер. Запрос «прилипает» к своему кластеру на всё время жизни.
Без query-id affinity балансировка ломала бы каждый запрос; с ней балансировка применяется к выбору кластера для нового запроса, а уже идущий запрос остаётся на своём кластере.
Состояние и health checks
Gateway — не просто статичный прокси, он ведёт состояние и следит за здоровьем кластеров.
Состояние Gateway хранит во внешней базе данных — PostgreSQL, MySQL или Oracle. Там лежат конфигурация кластеров, привязки запросов, история. Схему БД Gateway мигрирует сам (через Flyway). Внешняя БД означает, что несколько экземпляров Gateway могут работать с общим состоянием — сам Gateway не становится единой точкой отказа.
Health checks. Gateway периодически проверяет здоровье кластеров за ним. Нездоровый кластер — упавший, перегруженный, выведенный на обслуживание — Gateway исключает из маршрутизации: новые запросы на него не пойдут, пока он не вернётся в строй. Это автоматическая защита: сбойный кластер не получает трафик, а клиенты этого даже не замечают.
Аутентификация на самом Gateway тоже есть — он поддерживает OAuth/OIDC, form-based вход, JWT, — так что Gateway становится и единой точкой входа, и единой точкой контроля доступа к парку кластеров.
Docker Compose: быстрый стенд для проверки Gateway
Blue/green апгрейды без простоя
Самая ценная эксплуатационная возможность Gateway — апгрейды кластеров без простоя. Trino выходит часто (раз в 1-4 недели), и обновлять кластер, роняя пользователей на каждый релиз, недопустимо.
Gateway делает апгрейд по схеме blue/green. Идея:
- Рядом с работающим («blue») кластером поднимается новый («green») кластер — уже на новой версии Trino.
- Green-кластер добавляется за Gateway. Gateway начинает направлять новые запросы на green-кластер.
- Blue-кластер при этом не убивают сразу — он доисполняет уже идущие на нём запросы (привязанные к нему по query id). Дренаж.
- Когда на blue-кластере не осталось активных запросов, его выводят. Апгрейд завершён.
Ключ к тому, что это работает без потери запросов, — та самая query-id affinity. Запросы, начатые на blue-кластере, остаются привязаны к нему и спокойно доисполняются, пока новые уходят на green. Простоя нет, оборванных запросов нет — пользователи апгрейда просто не замечают. Тем же приёмом делают canary-выкатки (часть трафика на новую версию для проверки) и прозрачное изменение мощности кластеров.
Связка через весь курс. Gateway даёт единый URL и blue/green апгрейды; query-id affinity делает апгрейды безопасными; routing groups разводят интерактив и batch по кластерам с разной retry-policy из модуля fault tolerance; graceful shutdown из урока про Kubernetes корректно гасит дренируемые ноды. Эти механизмы складываются в одну эксплуатационную картину: парк кластеров Trino, который обновляется и масштабируется, не роняя пользователей.
Попробуй сам
Поставь Trino Gateway перед несколькими кластерами на тестовом стенде.
- Подними два небольших кластера Trino (через docker-compose или Helm) — например, один пометь как интерактивный, другой как batch. Затем подними Trino Gateway с внешней БД (PostgreSQL) для его состояния.
- Зарегистрируй оба кластера за Gateway, распредели их по routing groups. Подключи Trino CLI к URL Gateway и выполни запросы — проверь, что они доходят до кластеров.
- Проверь query-id affinity: запусти запрос подлиннее и проследи, что все polling-обращения идут на один и тот же кластер, а не разбредаются.
- Сымитируй blue/green: добавь третий «green» кластер за Gateway, переведи на него новые запросы и убедись, что запросы, уже идущие на «blue», доживают на нём. Затем выведи «blue».
Цель — увидеть, что Gateway прячет множество кластеров за единым URL и делает апгрейды без простоя за счёт привязки запросов к кластерам.