Клиенты: Trino CLI, JDBC, trino-python-client, dbt-trino
Trino без клиента — мотор без колёс. Координатор принимает запросы только через HTTP, и любой клиент — будь то CLI в терминале, BI-инструмент, Python-скрипт или dbt — это надстройка над одним и тем же протоколом. Этот урок разбирает четыре основных клиента и, главное, общий client protocol под ними. Понимать протокол важно: он объясняет, почему клиент ведёт себя именно так, и почему «зависший» клиент почти никогда не означает зависший Trino.
Client protocol: что под всеми клиентами
Координатор Trino предоставляет HTTP/REST-протокол. Он устроен вокруг polling (опроса), и это его определяющая черта.
Клиент отправляет SQL-текст одним HTTP-запросом (POST /v1/statement). Trino не блокирует соединение до конца запроса. Вместо этого он немедленно отвечает JSON-документом, в котором есть nextUri — ссылка, по которой надо запросить продолжение. Клиент идёт по nextUri, получает следующий документ: там либо первая порция строк результата и снова nextUri, либо состояние «ещё выполняется» и снова nextUri. Клиент опрашивает nextUri в цикле, пока не выберет все строки и не получит документ без nextUri — это конец.
Из устройства протокола следуют важные практические выводы:
- Запрос продолжается на кластере, даже если клиент перестал опрашивать. Это объясняет «зависшие» дашборды: BI-инструмент мог отвалиться по своему таймауту, а запрос на Trino всё ещё идёт — его видно в Web UI со state RUNNING.
- Результат стримится порциями. Клиент получает строки по мере готовности, ему не нужно ждать полной материализации. Поэтому CLI начинает печатать первые строки большого результата почти сразу.
- Состояние запроса живёт на координаторе. Клиент держит только query id и текущий
nextUri. Сетевой сбой между двумя опросами не убивает запрос. - Любой клиент — это реализация этого цикла. CLI, JDBC, Python-клиент отличаются языком и удобствами, но внутри делают одно и то же.
Polling-протокол объясняет ключевое правило диагностики: «клиент завис» и «Trino завис» — разные вещи. Если клиент не отвечает, первым делом откройте Web UI и найдите запрос по query id. State RUNNING означает, что Trino работает и проблема на стороне клиента или сети; FINISHED означает, что запрос давно готов, а клиент просто перестал забирать результат. Чинить нужно ту сторону, где реально проблема.
Trino CLI
Trino CLI — официальный клиент командной строки, поставляемый как self-executable JAR (запускается напрямую без отдельной установки JVM-обвязки). Это основной инструмент для интерактивной работы, отладки и скриптов.
# Интерактивная сессия
trino --server https://trino.example.com:8443 \
--user analyst --catalog iceberg --schema analytics
# Один запрос и выход — удобно для скриптов
trino --server https://trino.example.com:8443 \
--catalog tpch --schema sf1 \
--execute "SELECT count(*) FROM lineitem"
# Запрос из файла, вывод без рамок для пайплайна
trino --server https://trino.example.com:8443 \
--catalog iceberg --schema analytics \
--file report.sql --output-format CSV
В интерактивном режиме CLI показывает прогресс-бар запроса — это тот же прогресс, что в Web UI, отрисованный в терминале. Полезные флаги: --output-format (ALIGNED для человека, CSV/TSV/JSON для пайплайнов), --session для session-параметров, --execute и --file для неинтерактивного запуска. Внутри CLI работает по описанному protocol: POST запроса, цикл опроса nextUri, печать порций по мере прихода.
JDBC-драйвер
Для JVM-приложений и большинства BI-инструментов Trino предоставляет JDBC-драйвер. Это стандартный JDBC: приложение работает с Connection, Statement, ResultSet, не зная про polling, — драйвер прячет цикл опроса под привычным API.
String url = "jdbc:trino://trino.example.com:8443/iceberg/analytics";
Properties props = new Properties();
props.setProperty("user", "analyst");
props.setProperty("password", "secret");
props.setProperty("SSL", "true");
try (Connection conn = DriverManager.getConnection(url, props);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(
"SELECT event_type, count(*) AS cnt " +
"FROM events GROUP BY event_type")) {
while (rs.next()) {
System.out.println(rs.getString("event_type")
+ " = " + rs.getLong("cnt"));
}
}
JDBC URL кодирует адрес координатора и опционально каталог со схемой по умолчанию; параметры подключения (учётные данные, TLS, session properties) передаются через Properties. Через JDBC к Trino подключаются Tableau, DBeaver, Apache Superset и другие JVM-совместимые инструменты. Важная деталь версионирования: с 2025 года JDBC-драйвер Trino требует Java 11 или 17 — это отдельное требование, не совпадающее с версией Java серверной части (сервер на актуальных релизах требует более новую JDK).
trino-python-client
Для Python-экосистемы есть официальный trino-python-client. Он работает на Python 3.9+ и PyPy и предлагает три уровня API под разные задачи.
# DBAPI 2.0 — стандартный для Python интерфейс к БД
from trino.dbapi import connect
conn = connect(
host="trino.example.com",
port=8443,
user="analyst",
catalog="iceberg",
schema="analytics",
http_scheme="https",
)
cur = conn.cursor()
cur.execute("SELECT event_type, count(*) FROM events GROUP BY 1")
for event_type, cnt in cur.fetchall():
print(event_type, cnt)
Три уровня:
- Low-level client — прямая работа с protocol, максимальный контроль над опросом и страницами результата.
- DBAPI 2.0 — стандартный для Python интерфейс к БД (
connect,cursor,execute,fetchall); им пользуются чаще всего, и его понимают инструменты, ожидающие DBAPI-совместимое соединение. - SQLAlchemy-адаптер — позволяет работать с Trino через SQLAlchemy; так Trino подключается к инструментам, построенным поверх SQLAlchemy.
Python-клиент — основа для скриптов извлечения данных, ноутбуков и пайплайнов оркестрации, где шаг — это запрос к Trino.
Сессии и параметры запроса
У всех клиентов есть общее понятие, которое стоит разобрать, — сессия. Когда клиент подключается к Trino, у соединения есть контекст: каталог и схема по умолчанию, часовой пояс, язык и, главное, session properties — параметры, влияющие на поведение движка для запросов этой сессии.
Session properties — это рычаги тюнинга, которые применяются без перезапуска кластера и только к текущему соединению. Например, join_distribution_type принудительно задаёт тип распределения join, query_max_memory ограничивает память запроса, join_reordering_strategy управляет переупорядочиванием join. В CLI их задают флагом --session или командой SET SESSION в сессии; в JDBC — через Properties; в Python-клиенте — аргументом session_properties; в profiles.yml dbt-trino — отдельной секцией. Под капотом любой клиент просто передаёт их координатору вместе с запросом.
Это объясняет важную деталь диагностики из урока про Web UI: на странице деталей запроса видны session-параметры, с которыми он был запущен. Неожиданное поведение запроса часто объясняется именно случайно выставленным session property — например, инструмент мог проставить свой join_distribution_type, и план запроса оказался не таким, как ожидалось. Поэтому при разборе странного плана session-параметры проверяют одними из первых.
Session properties удобны для экспериментов и точечных обходов, но это не способ постоянной настройки кластера. Если каждый клиент проставляет свои session-параметры, поведение Trino становится непредсказуемым и зависит от того, кто и как подключился. Постоянные настройки место в конфигурации кластера, а session properties — для разовых случаев: проверить гипотезу тюнинга, обойти конкретную проблему конкретного запроса.
dbt-trino
dbt: адаптер dbt-trino — конфигурация и materialization-стратегииdbt-trino — адаптер, делающий Trino движком трансформаций для dbt. dbt описывает модели как SQL-файлы со ссылками ref(), строит из них DAG и исполняет в правильном порядке; адаптер транслирует это в конкретный движок. dbt-trino делает движком Trino.
# profiles.yml — профиль подключения dbt к Trino
analytics_project:
target: prod
outputs:
prod:
type: trino
host: trino.example.com
port: 8443
user: dbt_runner
http_scheme: https
catalog: iceberg
schema: analytics
threads: 8
Связка особенно естественна именно с Trino из-за его федеративности. dbt-модель может в одном SELECT соединить таблицы из разных каталогов — Iceberg-факты и dimension из PostgreSQL, — и dbt построит из такой модели материализованную витрину. Получается ELT, где T работает поверх нескольких источников сразу, без предварительного сведения данных в одно хранилище. Параметр threads задаёт, сколько моделей dbt-trino отправляет на Trino параллельно; Trino-кластер с его MPP-исполнением такую параллельную нагрузку рассчитан принимать.
Какой клиент когда
Все четыре клиента говорят по одному протоколу — выбор определяется задачей.
| Задача | Клиент |
|---|---|
| Интерактивная отладка, ad-hoc, шелл-скрипты | Trino CLI |
| BI-инструменты, JVM-приложения | JDBC-драйвер |
| Python-скрипты, ноутбуки, пайплайны оркестрации | trino-python-client |
| ELT-трансформации, моделирование витрин | dbt-trino |
| Операционные дашборды по данным lakehouse | Grafana Trino Data Source Plugin |
Какой бы клиент вы ни использовали, в продакшене соединение почти всегда идёт через TLS (https) и с аутентификацией. В примерах выше это http_scheme: https, SSL=true, порт 8443. Поскольку под всеми клиентами один протокол, настройки безопасности у них концептуально одинаковы — меняется только синтаксис их передачи: флаги CLI, свойства JDBC, аргументы Python-клиента, поля profiles.yml.
Попробуй сам
Подключитесь к локальному Trino двумя разными клиентами и убедитесь, что под ними один протокол.
- Через Trino CLI выполните запрос, который вернёт много строк, например
SELECT * FROM tpch.sf1.orders LIMIT 200000. Заметьте: первые строки печатаются почти сразу, не дожидаясь конца, — это стриминг порций. - Установите
pip install trinoи из Python через DBAPI 2.0 выполнитеSELECT count(*) FROM tpch.sf1.lineitem. Это тот же кластер, другой клиент. - Запустите долгий запрос через CLI и, не дожидаясь конца, прервите CLI по Ctrl-C. Откройте Web UI: что показывает state этого запроса сразу после прерывания клиента?
- Снова запустите долгий запрос и в Web UI на странице деталей в блоке Overview найдите поле источника (source). Сравните, как обозначены запросы из CLI и из Python-клиента.
- Запустите тот же запрос с флагом
--output-format JSONи посмотрите, как меняется представление результата.
Цель — на практике увидеть, что клиент — это лишь надстройка над protocol, и что прерывание клиента не равно остановке запроса на Trino.