Архитектура Provisa¶
Обзор¶
Provisa — это платформа виртуализации данных, управляемая конфигурацией, специально спроектированная для питания семантического слоя от небольших команд до крупных предприятий. Она предоставляет единый API поверх разнородных источников данных с governance, безопасностью и оптимизацией производительности. Клиенты выполняют запросы через SQL, GraphQL или Cypher; все три — полноправные интерфейсы с идентично применяемым governance. (REQ-002, REQ-038)
Разграничение семантического слоя важно. Чтобы добавить что-то в семантический слой, нужно создать новые источники данных или агрегаты внутри слоя виртуализации данных. Это создаёт чистое разделение — никакие новые дополнения к семантике не могут быть сделаны за пределами платформы, что обеспечивает подлинный data governance. (REQ-136) Применение происходит на уровне компилятора: каталог утверждённых связей — это источник истины независимо от того, какой язык запросов используется. (REQ-002)
Provisa спроектирована быть высокопроизводительной для операционных нужд и высокомасштабируемой для аналитических нужд предприятия. Одна платформа обслуживает и то, и другое без потери скорости или масштабируемости.
Config YAML → PG Metadata → Federation Catalogs
↓
Federation engine metadata → Schema Generator → SDL / SQL catalog / Cypher labels / gRPC proto (per role)
↓
Query → Parser → SQL Compiler → Transpiler
↓
Router (Smart Dispatch)
/ | \
Federation Direct PG Direct MySQL/etc.
\ | /
Executor Pool
↓
┌───── Inline ─────┐ ┌──── Redirect ────┐
│ JSON (HTTP) │ │ CTAS → S3 │
│ Arrow (Flight) │ │ (Parquet, ORC) │
│ Protobuf (gRPC) │ │ Provisa → S3 │
└─────────────────-┘ │ (JSON, CSV, …) │
└─────────────────-┘
Интерфейсы запросов¶
Каждый интерфейс — это отдельный транспорт. Все четыре применяют один и тот же конвейер безопасности (RLS, маскирование, сэмплирование, проверка ролей). (REQ-002, REQ-038) Клиенты никогда не обращаются напрямую к движку федерации. (REQ-266) «Язык запросов» (SQL / GraphQL / Cypher) ортогонален транспорту — несколько языков могут поступать по одному и тому же транспорту.
| Порт | Транспорт | Принимаемые языки запросов | Сценарий использования |
|---|---|---|---|
| 8001 | HTTP | GraphQL, SQL, Cypher | Веб-клиенты, BI-инструменты, curl, потребители REST |
| 8815 | Arrow Flight (gRPC) | SQL (через Arrow Flight SQL) | Инструменты данных (Pandas, DuckDB, Spark, ADBC) |
| 50051 | Protobuf gRPC | Сгенерированные для каждой роли RPC на базе proto | Взаимодействие сервис-сервис с типизированными контрактами |
| настраиваемый¹ | Проводной протокол PostgreSQL (pgwire) | SQL | psql, DBeaver, SQLAlchemy, любой PG-совместимый клиент |
¹ Установите PROVISA_PGWIRE_PORT (например, 5433). Отключено, если не задано или равно 0.
HTTP (порт 8001)¶
Несколько конечных точек на одном порту, различаются по пути:
| Путь | Язык | Примечания |
|---|---|---|
POST /data/graphql |
GraphQL | Чтение и мутации; хеш APQ принимается через extensions.persistedQuery |
POST /data/sql |
SQL | Только чтение; без gate по возможностям (capability) — governance через видимость объектов + RLS + маскирование (REQ-001, REQ-267) |
POST /data/query |
Cypher | Только чтение; стандартная роль |
GET /data/nl |
Естественный язык | Переводится в SQL/GraphQL/Cypher в зависимости от типа источника |
GET /data/subscribe/{table} |
GraphQL | Поток подписки SSE |
GET /neo4j/... |
Cypher (совместимость с Neo4j) | Прослойка совместимости с HTTP API Neo4j |
POST /admin/graphql |
GraphQL | Admin API (требуется роль superuser/admin) |
Все пути по умолчанию возвращают JSON. Accept: text/csv, application/vnd.apache.parquet, application/vnd.apache.arrow.stream и application/octet-stream (сырые бинарные данные) поддерживаются через согласование содержимого (content negotiation). Результаты, превышающие настроенный порог размера, автоматически перенаправляются на подписанный URL S3. (REQ-029, REQ-137)
Arrow Flight (порт 8815)¶
Нативный колоночный транспорт Arrow через gRPC. (REQ-045, REQ-143) Клиенты отправляют JSON-тикет:
и получают потоково, лениво, RecordBatches Arrow. Когда доступен прокси Zaychik Arrow Flight SQL, данные текут потоком Arrow record batches от начала до конца: (REQ-144)
Полный результат никогда не материализуется в памяти Provisa — батчи пересылаются по мере поступления. (REQ-145) Это делает Arrow Flight неограниченным путём, подходящим для сколь угодно больших результатов.
Protobuf gRPC (порт 50051)¶
Автоматически сгенерированный .proto из схемы данных, генерируется для каждой роли. (REQ-525) Потоковые запросы (одно сообщение на строку), унарные мутации. Включена рефлексия сервера. (REQ-526) Роль передаётся через ключ метаданных x-provisa-role.
Проводной протокол PostgreSQL / pgwire (настраиваемый порт)¶
Реализует протокол frontend/backend PostgreSQL с использованием библиотеки buenavista. (REQ-527) Любой PostgreSQL-совместимый клиент — psql, DBeaver, SQLAlchemy с psycopg2, JDBC — может подключиться без изменений. Принимает только SQL. Полный конвейер governance (RLS, маскирование, разрешения на домен) применяется к соединениям pgwire идентично. (REQ-266, REQ-002) Включается установкой PROVISA_PGWIRE_PORT на ненулевой порт.
Конвейер запроса¶
Принимаются три языка запросов. Все они сходятся на governance после соответствующих этапов разбора/компиляции. (REQ-262, REQ-263) Только GraphQL поддерживает записи. (REQ-037) Для самого запроса нет gate по возможностям (capability) — любая аутентифицированная идентичность может выполнять запросы на любом языке, а данные управляются исключительно видимостью объектов, RLS и маскированием. (REQ-001)
| Интерфейс | Чтение | Запись | Gate запроса |
|---|---|---|---|
GraphQL (/data/graphql) |
Да | Да (мутации) | Нет — только governance на уровне данных |
SQL (/data/sql) |
Да | Нет | Нет — только governance на уровне данных (REQ-267) |
Cypher (/data/query) |
Да | Нет | Нет — только governance на уровне данных |
flowchart TD
A[GraphQL Request] --> B[Auth / Role Resolution]
A2[SQL Request] --> B
A3[Cypher Request] --> B
B --> E[APQ Hash Check]
E --> F[Parse & Validate]
F --> G[Extract Directives / Hints]
G --> H{Cache Hit?}
H -- yes --> R
H -- no --> I{Input Type}
I -- GraphQL --> I1[Compile → Semantic SQL]
I -- SQL --> I2[Parse & Validate SQL\nApply Namespace / Source Binding]
I -- Cypher --> I3[Translate Cypher → SQL\nResolve Node / Rel Mappings]
I1 --> J[Governance: RLS + Masking + Visibility + Sampling]
I2 --> J
I3 --> J
J --> K[MV Rewrite]
K --> L{Route}
L -- Direct --> M[Transpile → Source Dialect\nExecute via Driver]
L -- Federation --> N[Transpile → Federation SQL\nInject Session Hints\nExecute via Federation Engine / Flight]
L -- Materialize --> O[Fetch from REST / GraphQL / gRPC\nMaterialize → S3 Parquet\nPost-filter via Federation Engine]
L -- Mutation --> P[RLS Injection\nTranspile → Source Dialect\nExecute via Driver\nInvalidate Cache + MV\nEmit Change Event]
M --> Q{Redirect?}
N --> Q
O --> Q
Q -- yes --> S[Upload to S3\nReturn Signed URL]
Q -- no --> R[Serialize: JSON / CSV / Parquet / Arrow]
R --> T[Store in Cache]
T --> U[Return to Client]
P --> U
Решения о маршрутизации:
| Маршрут | Когда |
|---|---|
| Cache | Попадание в кеш результата — вычисляется первым, отдаёт сохранённый результат без выполнения (REQ-865) |
| Cheap-count | Запрос формы count(*) над нематериализованным источником, предоставляющим точный нативный счётчик — маршрутизируется на нативный вызов подсчёта вместо материализации ради подсчёта (REQ-875) |
| Direct | Один источник + есть нативный драйвер + есть коннектор федерации |
| Federation | Федерация нескольких источников, либо источник имеет коннектор, но не имеет драйвера |
| Materialize | У источника нет коннектора федерации — сначала выбрать и закешировать в S3/PG |
| Mutation | GraphQL-мутация — всегда напрямую, никогда не федерируется |
Маршрутизация использует вывод этапа оптимизации после governance, а не governed SQL до оптимизации. Governance может ДОБАВИТЬ источники (предикаты подзапроса RLS); этап оптимизации может их УБРАТЬ (встраивание горячих таблиц как VALUES-CTE, переписывание API-кеша, отсечение веток union). Федеративный запрос, который после встраивания схлопывается до одного живого источника, поэтому перемаршрутизируется как прямой. (REQ-863)
Запросы с несколькими корнями¶
GraphQL-запросы с несколькими корневыми полями (например, { orders { id } customers { name } }) компилируются в отдельные SQL-запросы и выполняются независимо. (REQ-534) Запросы SQL и Cypher по определению однокорневые. Результаты объединяются в единый ответ:
- Поля ниже порога перенаправления возвращаются встроенно в
data - Поля выше порога перенаправляются, с записями для каждого поля в
redirects - Бинарные форматы (Parquet, Arrow) поддерживаются только для однокорневых запросов
Пути выполнения федерации¶
| Путь | Транспорт | Через | Когда используется |
|---|---|---|---|
| REST | клиент движка федерации (HTTP :8080) | Прямой запрос | По умолчанию, всегда доступен |
| Flight SQL | adbc-driver-flightsql (gRPC :8480) |
Прокси Zaychik → JDBC | Когда запущен Zaychik |
| CTAS | клиент движка федерации (HTTP :8080) | Прямая запись, Iceberg в S3 | Перенаправление Parquet/ORC |
Прокси Zaychik Arrow Flight SQL¶
Движок федерации нативно не поддерживает протокол Arrow Flight SQL. Zaychik — это Java-прокси, реализующий gRPC-интерфейс Arrow Flight SQL, транслирующий запросы в JDBC-запросы и потоково возвращающий результаты как Arrow record batches. (REQ-144)
ADBC client → gRPC :8480 → Zaychik → JDBC :8080 → Federation Engine → results → Arrow batches → client
Flight-сервер Provisa (порт 8815) подключается к Zaychik как ADBC-клиент, обеспечивая потоковую передачу Arrow от начала до конца без материализации результатов. (REQ-145)
Каталог результатов Iceberg¶
Перенаправление CTAS использует коннектор Iceberg (каталог results), опирающийся на JDBC-каталог на существующем экземпляре PostgreSQL. (REQ-169) Iceberg пишет файлы Parquet/ORC напрямую в MinIO/S3 через нативную файловую систему S3 (fs.native-s3.enabled=true).
Движки федерации¶
Provisa выбирает движок федерации при старте через переменную окружения PROVISA_ENGINE, сохранённую конфигурацию admin UI либо значение по умолчанию. Если ничего не задано, по умолчанию используется DuckDB — полностью встроенный, без внешнего сервиса (REQ-989). Подробности выбора см. в Configuration.
Каждый движок — это экземпляр FederationEngine, определённый в provisa/federation/engine.py. Экземпляр владеет набором коннекторов, определяющим, какие типы источников движок может читать вживую (ATTACH), а какие сначала должны попасть в хранилище материализации движка. [tool-verified: engine.py _ENGINE_BUILDERS, ENGINE_REGISTRY]
Классы драйверов (REQ-840) [tool-verified: engine.py DriverClass]¶
| Класс | Значение | Примеры |
|---|---|---|
BROAD |
Достигает многих внешних типов источников через нативные коннекторы | Trino |
PARTIAL |
Достигает подмножества (реляционные, файлы, облачное объектное хранилище/lake), а всё остальное приземляет | DuckDB, PostgreSQL, ClickHouse, Databricks, Snowflake, BigQuery, Fabric, Synapse |
SELF_ONLY |
Достигает только собственного хранилища; всё остальное приземляется | SQLAlchemy |
Доступные движки [tool-verified: engine.py _ENGINE_BUILDERS]¶
| Ключ движка | Диалект | MPP | Механизм внешней связи | Аутентификация |
|---|---|---|---|---|
trino / trino-byo |
Trino SQL | Да | Каталоги Trino (широкий набор коннекторов) | Учётные данные JDBC |
pg |
PostgreSQL | Нет | FDW / pg_duckdb | Учётные данные PostgreSQL |
duckdb |
DuckDB | Нет | Нативное расширение ATTACH | Нет (в процессе) |
clickhouse / clickhouse-server |
ClickHouse | Да (шарды) | Табличные движки S3 / IcebergS3 / DeltaLake (REQ-986) | Учётные данные ClickHouse |
snowflake |
Snowflake | Да | Внешний stage + внешняя таблица (REQ-988) | PROVISA_ENGINE_URL |
databricks |
Databricks SQL | Да | Внешние таблицы Unity Catalog через REST (REQ-987) | Bearer-токен (http_path в federation_hints) |
bigquery |
BigQuery | Да (Dremel) | Внешние таблицы BigQuery / BigLake | Ключ сервисного аккаунта GOOGLE_APPLICATION_CREDENTIALS |
fabric |
T-SQL | Да | Ярлыки OneLake → OPENROWSET | Azure AD (az login / managed identity) |
synapse |
T-SQL | Да | ADLS OPENROWSET / внешние таблицы | Azure AD |
sqlalchemy |
Любой диалект SQLAlchemy | Нет | Нет (только приземление) | Учётные данные для каждого диалекта |
Готовый к работе без конфигурации по умолчанию: DuckDB (REQ-989) [tool-verified: engine.py build_duckdb_engine, _embedded_duckdb_materialize_default]¶
Когда PROVISA_ENGINE не задан, Provisa использует полностью встроенный внутрипроцессный движок DuckDB. Хранилище материализации DuckDB — это встроенный файл DuckDB по пути $PROVISA_DATA_DIR/materialize.duckdb (по умолчанию ~/.provisa/materialize.duckdb). Внешняя база данных или сервис не требуются.
Поскольку DuckDB допускает только одного писателя на файл, store_connection.py пишет во встроенное хранилище через собственное соединение движка — никогда через второе независимое соединение. Это единственный случай, когда движок и хранилище материализации намеренно разделяют один файловый дескриптор. [tool-verified: store_connection.py module docstring]
Нативный для Arrow транспорт чтения (REQ-986, REQ-987, REQ-988) [tool-verified: engine.py build_*_engine capabilities=]¶
ClickHouse, DuckDB, Snowflake, Databricks, BigQuery, Fabric и Synapse — все заявляют EngineCapability.ARROW и EngineCapability.ARROW_STREAM. Запросы к этим движкам возвращают RecordBatches Arrow напрямую — путь сериализации строк полностью минуется. Flight-сервер передаёт эти батчи клиентам потоково, не материализуя полный результат в памяти процесса Provisa. Для Trino потоковая передача Arrow опирается на прокси Zaychik; для движков хранилищ данных — на собственный Arrow-нативный API движка (Cloud Fetch для Databricks, Storage Read API для BigQuery, fetch_arrow_table для DuckDB и Snowflake), питающий поток Flight.
Внешние связи с данными (ATTACH) [tool-verified: engine.py _warehouse_connectors]¶
Каждый движок хранилища данных может сканировать облачные объектные/lake-данные на месте, не приземляя копию. Файлы Parquet, CSV, Iceberg и Delta Lake на S3, GCS или OneLake присоединяются к движку напрямую, как будто это нативные таблицы. Стратегия — ATTACH (сканирование на месте) или LAND (копирование в хранилище) — определяется объявленным Mechanism коннектора; в планировщике нет ветвления, специфичного для движка. Коннектор Mechanism.ATTACH_R запускает сканирование с нулевым копированием; Mechanism.DIRECT или отсутствие коннектора запускает приземление. [tool-verified: connector_base.py Mechanism, engine.py _warehouse_connectors]
Attach автоматически подготавливает все предпосылки в момент присоединения:
| Движок | Форматы объектов/lake | Механизм | Автоматическая подготовка [tool-verified] |
|---|---|---|---|
| Databricks | parquet, csv, iceberg, delta_lake | Внешняя таблица UC (ATTACH_R) |
REST устанавливает storage credential Unity Catalog + external location, затем CREATE TABLE … USING <format> LOCATION … — проверено вживую поверх Cloudflare R2 |
| BigQuery | parquet, csv, json, iceberg, delta_lake | Внешняя таблица BigQuery / BigLake (ATTACH_R) |
CREATE OR REPLACE EXTERNAL TABLE … OPTIONS(format=…, uris=[…]) — проверено вживую |
| ClickHouse | csv, parquet, iceberg, delta_lake | Табличный движок S3 / IcebergS3 / DeltaLake (ATTACH_R) |
Проверочный зонд выполняется в момент присоединения — проверено вживую поверх Cloudflare R2 |
| Fabric | parquet, csv, iceberg, delta_lake | Ярлык OneLake → OPENROWSET (ATTACH_R) |
REST создаёт соединение AmazonS3Compatible + lakehouse + shortcut; возвращает путь BULK OneLake — проверено вживую при чтении R2 через Fabric |
| Snowflake | parquet, csv, json, iceberg, delta_lake | Внешний stage + внешняя таблица (ATTACH_R) |
CREATE STAGE … URL=… CREDENTIALS=…, затем CREATE OR REPLACE EXTERNAL TABLE … LOCATION=@stage FILE_FORMAT=(TYPE=…) — реализовано; не протестировано вживую (нет доступного аккаунта) |
Учётные данные для облачного хранилища передаются в federation_hints источника (см. Sources). Любой тип источника, который не может выполнить ATTACH, сначала приземляется в хранилище материализации движка.
Колоночные записи материализации (REQ-990) [tool-verified: core/database.py:436, store_connection.py:99]¶
Connection.bulk_copy в provisa/core/database.py выбирает самый быстрый путь массовой загрузки для каждого диалекта хранилища: бинарный COPY (copy_records_to_table asyncpg) для хранилищ PostgreSQL и один подготовленный запрос executemany для всех остальных реляционных хранилищ. Встроенное хранилище DuckDB приземляется через land_duckdb_native в store_connection.py — один вызов executemany на весь батч, никогда построчный цикл.
Перенаправление больших результатов¶
Результаты, превышающие порог по числу строк, перенаправляются в S3-совместимое хранилище (MinIO) вместо возврата встроенно. (REQ-029)
Режимы перенаправления¶
| Режим | Как работает | Данные проходят через Provisa? |
|---|---|---|
| CTAS (Parquet, ORC) | Движок федерации пишет напрямую в S3 через CREATE TABLE AS SELECT |
Нет |
| Загрузка Provisa (JSON, NDJSON, CSV, Arrow IPC) | Provisa сериализует и загружает через boto3 | Да |
Для нативных для CTAS форматов Provisa никогда не обрабатывает данные — движок федерации пишет файлы напрямую в MinIO/S3. (REQ-138) Это предпочтительный путь для крупных аналитических экспортов.
Заголовки перенаправления¶
| Заголовок | Эффект |
|---|---|
X-Provisa-Redirect-Format: <mime> |
Перенаправить в этом формате (подразумевает принудительность, если не задан порог) |
X-Provisa-Redirect-Threshold: N |
Перенаправлять, только если результат превышает N строк |
X-Provisa-Redirect: true |
Принудительное перенаправление с использованием формата по умолчанию |
Эти заголовки реализуют перенаправление, управляемое клиентом. (REQ-137)
Ответ:
{
"data": {"orders": null},
"redirect": {
"redirect_url": "https://minio:9000/provisa-results/results/abc.parquet?...",
"row_count": 50000,
"expires_in": 3600,
"content_type": "application/vnd.apache.parquet"
}
}
Конфигурация сервера¶
| Переменная окружения | По умолчанию | Назначение |
|---|---|---|
PROVISA_REDIRECT_ENABLED |
false |
Включить перенаправление по порогу на стороне сервера |
PROVISA_REDIRECT_THRESHOLD |
1000 |
Порог по количеству строк по умолчанию |
PROVISA_REDIRECT_FORMAT |
parquet |
Формат перенаправления по умолчанию |
PROVISA_REDIRECT_BUCKET |
provisa-results |
Имя бакета S3 |
PROVISA_REDIRECT_ENDPOINT |
URL S3-совместимой конечной точки | |
PROVISA_REDIRECT_TTL |
3600 |
TTL подписанного URL (секунды) |
Дерево решений маршрутизации¶
Multi-source query? → Federation engine
NoSQL source (MongoDB, Cassandra)? → Federation engine
Uses path columns on non-PG source? → Federation engine
Single RDBMS with driver? → Direct (sub-100ms target)
Single RDBMS without driver? → Federation engine
Steward hint "federated"? → Federation engine (override)
Steward hint "direct"? → Direct (if possible)
Redirect to Parquet/ORC? → Federation engine (CTAS, regardless of source count)
(REQ-027, REQ-028, REQ-030, REQ-279)
Оптимизация федеративных запросов¶
Provisa автоматически подготавливает оптимизатор движка федерации на основе стоимости, так что межисточниковые планы запросов основаны на реальном распределении данных, а не на жёстко заданных значениях по умолчанию.
Автоматическая статистика (ANALYZE)¶
При регистрации источника Provisa запускает ANALYZE catalog.schema.table для каждой опубликованной таблицы. (REQ-275) Это собирает:
- Количество строк
- Для каждой колонки: долю null-значений, количество различных значений, min/max, гистограммы (зависит от коннектора)
Оптимизатор использует их для оценки селективности отфильтрованных запросов. Без статистики он откатывается к фиксированным значениям по умолчанию (например, 10% селективности для предикатов равенства), что даёт плохие планы join на скошенных или высококардинальных данных. Со статистикой оценки достаточно точны, чтобы правильно выбирать между broadcast- и partitioned-join для большинства нагрузок.
Покрытие: поддержка статистики варьируется от коннектора к коннектору. PostgreSQL, MySQL, Hive, Iceberg и Delta Lake полностью поддерживают ANALYZE. Коннекторы MongoDB и Cassandra имеют частичную поддержку или не имеют её вовсе. Provisa молча поглощает сбои ANALYZE — регистрация никогда не блокируется. (REQ-275)
Ограничения селективности: статистика предоставляет оценки для каждой колонки отдельно. Для коррелированных предикатов (WHERE region = 'US' AND city = 'Seattle') оптимизатор предполагает независимость колонок, что может занижать оценку числа строк. Это известное ограничение статистики уровня колонок во всех оптимизаторах на основе стоимости.
Источники API: таблицы api_cache_{table_name} в PostgreSQL анализируются автоматически после каждого цикла обновления кеша, так что у оптимизатора есть актуальные оценки числа строк при соединении источников на базе API с реляционными источниками. (REQ-280)
Admin: обновление статистики¶
Повторный запуск сбора статистики по требованию через admin API: (REQ-276)
mutation {
refreshSourceStatistics(sourceId: "sales-pg") {
tablesAnalyzed
failures { table message }
}
}
Полезно, когда источник получил значительный объём новых данных с момента регистрации.
Материализованные представления¶
MV прозрачно оптимизируют дорогие запросы, предварительно вычисляя и кешируя результаты.
Связи как подсказки для MV¶
Объявление связи — это не только артефакт governance — это также структурное описание формы join. Именно эта форма нужна оптимизатору MV: две таблицы, две колонки, тип join. Это значит, что связь может напрямую управлять материализацией.
Для межисточниковых связей это происходит автоматически при старте: каждая утверждённая межисточниковая связь генерирует MV JoinPattern (auto-mv-<rel_id>). (REQ-158) Отдельная конфигурация MV не требуется. Когда компилятор видит этот join в запросе, переписчик прозрачно подставляет предварительно материализованный результат.
Для связей в пределах одного источника стюарды могут явно включить это через materialize: true. JOIN в пределах одного источника уже быстры за счёт прямого выполнения, поэтому материализация оправдана только для очень горячих путей join. (REQ-159)
Практическое следствие: стюарды, утверждающие связь, неявно решают, является ли join хорошим кандидатом для материализации. Акт governance и подсказка оптимизации — это одно и то же объявление.
Режимы¶
| Режим | Конфигурация | Поведение |
|---|---|---|
| Join-pattern | join_pattern в конфигурации MV |
Переписывает совпадающие JOIN на чтение из таблицы MV |
| Custom SQL | sql в конфигурации MV |
Произвольный SELECT, опционально раскрываемый в SDL |
| Автоматически материализованная связь | межисточниковая связь (автоматически) | Автоматически генерирует join-pattern MV; конфигурация не требуется |
| Материализованная стюардом связь | materialize: true на связи в пределах одного источника |
Явное включение для горячих путей join в пределах одного источника |
Автоматическая материализация¶
Межисточниковые JOIN — самые дорогие запросы (всегда федерируются). Межисточниковые связи автоматически генерируют определения MV при старте: (REQ-158)
relationships:
- id: orders-to-reviews
source_table_id: orders # sales-pg
target_table_id: product_reviews # reviews-mongo
source_column: product_id
target_column: product_id
cardinality: one-to-many
materialize: true # auto-create MV
refresh_interval: 600 # refresh every 10 minutes
Только межисточниковые связи генерируют MV (JOIN в пределах одного источника уже быстры за счёт прямого выполнения). (REQ-159) MV начинает в статусе STALE и обновляется фоновым циклом обновления, прежде чем его начнёт использовать оптимизатор запросов. (REQ-160)
Жизненный цикл обновления¶
STALE → (refresh loop picks up) → REFRESHING → FRESH
↑ |
└──── mutation hits source table ────────────────┘
Цикл обновления запускается каждые 30 секунд, проверяет get_due_for_refresh() и выполняет CREATE TABLE AS SELECT (первый запуск) или DELETE + INSERT (последующие) над целевой таблицей MV через движок федерации. (REQ-160, REQ-234)
Карта модулей¶
| Модуль | Назначение |
|---|---|
api/ |
Приложение FastAPI, роутеры, middleware, управление жизненным циклом |
api/flight/ |
Сервер Arrow Flight (gRPC, порт 8815) |
api/admin/ |
Admin GraphQL API на Strawberry — конфигурация, обнаружение, представления |
api/rest/ |
Автоматически сгенерированные REST-конечные точки из зарегистрированных таблиц |
api/jsonapi/ |
Автоматически сгенерированные конечные точки JSON:API с пагинацией и обработкой ошибок |
api/data/subscribe.py |
Подписки SSE — LISTEN/NOTIFY, опрос, Debezium CDC |
compiler/ |
Парсеры GraphQL/SQL, генератор семантического SQL, RLS, маскирование, сэмплирование, двухэтапный governance (stage2.py) |
cypher/ |
Транслятор Cypher → SQL, парсер, карта меток (REQ-351), транслятор записи для мутаций Cypher |
pgwire/ |
Сервер проводного протокола PostgreSQL; catalog.py перехватывает pg_catalog/information_schema для видимости объектов для каждой роли (REQ-527, REQ-883, REQ-891) |
vector/ |
Векторный поиск — реестр моделей, провайдеры эмбеддингов (openai/ollama/huggingface), трансляция cosine_similarity(), резервный кеш pgvector, декларативная генерация эмбеддингов (REQ-419–431) |
compiler/federation.py |
Поддержка субграфа Apollo Federation v2 |
transpiler/ |
Транспиляция диалектов, логика маршрутизации |
executor/ |
Федеративное/прямое выполнение, сериализация, форматы вывода |
executor/drivers/ |
Прямые драйверы источников (PostgreSQL, MySQL, DuckDB, Snowflake, Databricks, ClickHouse, …) |
executor/trino_flight.py |
ADBC-клиент Flight SQL для движка федерации |
executor/ctas_write.py |
Перенаправление на базе CTAS (движок федерации пишет в S3) |
executor/redirect.py |
Логика перенаправления S3, загрузка со стороны Provisa |
federation/engine.py |
FederationEngine, DriverClass, _ENGINE_BUILDERS, ENGINE_REGISTRY, build_engine |
federation/connector.py |
Абстракции коннекторов — Trino, ClickHouse; Mechanism, WarehouseNativeConnector |
federation/connector_duckdb.py |
Определения коннекторов DuckDB и PostgreSQL FDW |
federation/snowflake_connectors.py |
Коннекторы ATTACH внешнего stage + внешней таблицы Snowflake (REQ-988) |
federation/databricks_connectors.py |
Коннекторы ATTACH внешней таблицы Databricks UC (REQ-987) |
federation/bigquery_connectors.py |
Коннекторы ATTACH BigQuery external / BigLake |
federation/databricks_uc.py |
Автоматическая подготовка credential Unity Catalog + external location |
federation/databricks_backend.py |
Бэкенд выполнения Databricks SQL warehouse |
federation/snowflake_backend.py |
Бэкенд выполнения Snowflake |
federation/bigquery_backend.py |
Бэкенд выполнения BigQuery (Arrow-транспорт Storage Read API) |
federation/mssql_warehouse_backend.py |
Бэкенды выполнения Fabric Warehouse + Synapse (T-SQL через ODBC) |
federation/mssql_warehouse_connectors.py |
Коннекторы ATTACH OPENROWSET для Fabric / Synapse |
federation/fabric_shortcuts.py |
Автоматическая подготовка ярлыков OneLake (соединение → lakehouse → shortcut) |
federation/clickhouse_backend.py |
Бэкенд выполнения ClickHouse |
federation/duckdb_backend.py |
Внутрипроцессный бэкенд выполнения DuckDB |
federation/pg_backend.py |
Бэкенд выполнения PostgreSQL |
federation/store_connection.py |
Нативное для DuckDB звено записи хранилища материализации (REQ-989, REQ-990) |
registry/ |
Реестр сохранённых запросов, governance |
security/ |
Видимость, права, маскирование колонок |
cache/ |
Кеширование результатов запросов на базе Redis (горячий уровень) |
mv/ |
Реестр материализованных представлений, обновление, переписыватель SQL |
events/ |
События изменения наборов данных и диспетчеризация триггеров |
webhooks/ |
Исходящее выполнение webhook для мутаций и событий |
scheduler/ |
Управление фоновыми заданиями на базе APScheduler — cron- и интервальные триггеры, запускающие webhook'и, мутации или публикации в приёмники Kafka |
apq/ |
Проводной протокол Apollo APQ — кеш хешей запросов на базе Redis; отдельно от кеширования результатов |
compiler/cursor.py |
Курсорная пагинация в стиле Relay — аргументы first/after/last/before и генерация pageInfo для всех запросов списков |
compiler/aggregate_gen.py |
Автоматически сгенерированные типы запросов {table}_aggregate с подполями count, sum, avg, min, max и доступом к отфильтрованным nodes |
compiler/enum_detect.py |
Автоматическое обнаружение enum-типов — нативные enum-типы PostgreSQL (pg_enum), раскрываемые как GraphQL enum-типы, а не строковые скаляры |
compiler/hints.py |
Подсказки производительности федерации — директивы маршрутизации на уровне запроса, встроенные как SQL-комментарии (/* @provisa route=federated */), переопределяющие автоматическую маршрутизацию |
compiler/mutation_gen.py |
Компилятор мутаций; пресеты колонок — статические значения или значения из переменных сессии на стороне сервера, применяемые при insert/update, не раскрываемые во входном типе мутации |
auth/approval_hook.py |
Хук утверждения ABAC — подключаемая внешняя авторизация, вызываемая перед выполнением запроса; транспорты webhook, gRPC и unix_socket; область действия для таблицы/источника/глобальная; настраиваемая политика отката |
subscriptions/ |
Состояние и доставка подписок SSE |
discovery/ |
Обнаружение связей на базе LLM (API Claude) |
grpc/ |
Генерация proto, сервер gRPC, рефлексия |
api_source/ |
Источники REST/GraphQL/gRPC API с кешем PG |
kafka/ |
Источники тем Kafka, приёмник, Schema Registry |
auth/ |
Подключаемые провайдеры аутентификации, middleware, отображение ролей |
core/ |
Конфигурация, модели, БД, репозитории, секреты; модель ролей поддерживает parent_role_id и flatten_roles() для рекурсивного наследования ролей |
hasura_v2/ |
Конвертер метаданных Hasura v2 → конфигурация Provisa |
ddn/ |
Конвертер supergraph Hasura DDN → конфигурация Provisa |
mongodb/ |
Коннектор источника MongoDB |
elasticsearch/ |
Коннектор источника Elasticsearch |
cassandra/ |
Коннектор источника Cassandra |
prometheus/ |
Коннектор источника метрик Prometheus |
source_adapters/ |
Общий слой адаптеров для соединений с источниками |
Admin API¶
Admin GraphQL API на Strawberry монтируется по адресу /admin/graphql (HTTP-порт 8001). Он отделён от конечной точки данных GraphQL и требует роли superuser или admin.
| Возможность | Описание |
|---|---|
| Загрузка/выгрузка конфигурации | Экспорт или замена полной YAML-конфигурации Provisa |
| Редактор связей | Создание, обновление, удаление определений связей |
| AI-обнаружение FK | Запуск анализа кандидатов на внешний ключ на базе Claude |
| Интроспекция схемы | Просмотр опубликованных таблиц, колонок и ролей |
| Управление представлениями | Регистрация и управление определениями материализованных представлений |
(REQ-164, REQ-165, REQ-166, REQ-167)
Конфигурация AI-моделей¶
GET /admin/ai-models и PUT /admin/ai-models настраивают конвейер LLM для каждой организации. (REQ-464, REQ-419, REQ-500, REQ-370, REQ-1349)
Настройки привязаны к организации: выбор каждой организации ложится поверх конфигурации развёртывания и вступает в силу со следующего запроса — перезапуск не требуется. (REQ-1349) [tool-verified: provisa/api/admin/ai_models_router.py:38-39]
Назначения моделей для каждой операции. Пять операций NL, каждая с настраиваемым вендором и строкой модели:
| Операция | Что управляет |
|---|---|
table_description |
Сгенерированные LLM описания таблиц |
column_description |
Сгенерированные LLM описания колонок |
relationship_inference |
Обнаружение кандидатов на FK |
sql_generation |
Генерация NL → SQL |
table_selection |
Выбор таблиц для включения в промпт NL |
Поле вендора принимает любой вендор, совместимый с aisuite (anthropic, openai, groq, mistral, cohere и другие), либо локальную конечную точку (ollama, lmstudio). Пустая строка модели удаляет переопределение организации и возвращает к значению по умолчанию из развёртывания. [tool-verified: provisa/api/admin/ai_models_router.py:29-35, provisa-ui/src/components/admin/AiModelsTab.tsx:43-60]
Ограничение частоты запросов NL. Опциональный предел запросов за период, применяемый для каждой роли. Избыточные запросы возвращают 429 с Retry-After. [tool-verified: provisa-ui/src/components/admin/AiModelsTab.tsx:306-313]
Реестр векторных моделей. Список моделей эмбеддинга (поля: id, provider, dimensions, опционально api_key_env и base_url, флаг enabled). Полная замена списка: у каждой записи должны быть id, provider и dimensions, иначе запись на запись отклоняется с 400. [tool-verified: provisa/api/admin/ai_models_router.py:122-131]
API-ключи. Ключи API LLM для каждого вендора хранятся зашифрованными через provisa.core.org_secrets (см. ниже). Ответ GET сообщает только о том, задан ли ключ для каждого вендора — само значение никогда не возвращается. Отправка пустой строки для вендора очищает этот ключ, возвращая вызовы LLM для этого вендора к учётным данным из переменной окружения развёртывания. (REQ-1395, REQ-1398) [tool-verified: provisa/api/admin/ai_models_router.py:76-78, provisa/api/admin/ai_models_router.py:149-165]
Зашифрованные секреты для каждой организации¶
provisa/core/org_secrets.py хранит учётные данные, которые никогда не должны появляться в базе данных как открытый текст. В настоящее время ограничено ключами API вендоров LLM ({vendor}_api_key). (REQ-1395, REQ-1398) [tool-verified: provisa/core/org_secrets.py]
Значения шифруются через общепроцессный encryption_service из provisa.encryption.runtime — тот же механизм, что и api_sources.auth. [tool-verified: provisa/core/org_secrets.py:16-17]
Поддерживаются двенадцать вендоров, совместимых с aisuite: anthropic, openai, cohere, groq, mistral, xai, deepseek, together, fireworks, nebius, sambanova и inception. Google, AWS и Azure исключены, поскольку требуют конфигурации сверх простого API-ключа (ID проекта, роли IAM, регион). Вендоры с локальной конечной точкой (ollama, lmstudio) не имеют ключа и исключены по той же причине. [tool-verified: provisa/core/org_secrets.py:33-53]
Передача value=None в write_org_secret удаляет строку. Вызывающий код, читающий секрет, немедленно его потребляет (например, для создания клиента LLM) и не должен возвращать его эхом ни в одном ответе API. [tool-verified: provisa/core/org_secrets.py:97-117]
Автоматически сгенерированные конечные точки REST и JSON:API¶
Зарегистрированные таблицы раскрываются как конечные точки REST и JSON:API наряду с интерфейсом GraphQL. (REQ-256, REQ-257)
| Интерфейс | Путь монтирования | Спецификация |
|---|---|---|
| REST | /rest/<table-id> |
Простой GET/POST с параметрами запроса |
| JSON:API | /jsonapi/<table-id> |
Соответствует jsonapi.org — пагинация, связи, объекты ошибок |
Эти конечные точки применяют тот же конвейер безопасности (RLS, маскирование, проверка ролей), что и конечная точка GraphQL. (REQ-002, REQ-038)
Подписки¶
Подписки SSE обслуживаются по адресу GET /data/subscribe/{table}. Три режима доставки: (REQ-258)
| Режим | Механизм | Когда используется |
|---|---|---|
| LISTEN/NOTIFY | LISTEN PostgreSQL на канале |
Источники PG с активностью мутаций |
| Опрос (Polling) | Повторное выполнение запроса с интервалом | Источники не PG или когда CDC недоступен |
| Debezium CDC | Тема Kafka от коннектора Debezium | Высокочастотные потоки изменений |
Клиент получает text/event-stream с одним JSON-событием на изменённую строку или diff.
Система событий и webhook¶
Мутации базы данных (INSERT/UPDATE/DELETE) могут запускать исходящие события через модули events/ и webhooks/. (REQ-172, REQ-173, REQ-220)
Mutation executed → EventDispatcher → match event trigger rules
↓
WebhookExecutor → HTTP POST to configured URL
Триггеры событий определяются в конфигурации и сопоставляются по таблице, типу операции и опциональному фильтру строк. Полезная нагрузка webhook включает тип операции, изменённую строку и контекст роли.
Фоновые сервисы¶
Четыре фоновых цикла запускаются в течение жизненного цикла приложения (api/app.py):
| Сервис | Интервал | Назначение |
|---|---|---|
| Цикл обновления MV | 30 с | Опрашивает get_due_for_refresh(), выполняет CTAS или DELETE+INSERT для устаревших MV |
| Менеджер тёплых таблиц | Настраиваемый | Продвигает часто запрашиваемые таблицы в кеш локального SSD Iceberg |
| Загрузчик горячих таблиц | Настраиваемый | Загружает небольшие справочные таблицы в кеш в памяти для доступа с задержкой менее миллисекунды |
| Опросчик источников API | Интервал для каждого источника | Повторно выбирает и перекеширует удалённые источники REST/GraphQL/gRPC |
(REQ-160, REQ-238, REQ-239, REQ-236)
Уровни кеширования горячих/тёплых таблиц¶
| Уровень | Хранилище | Критерий продвижения | Задержка доступа |
|---|---|---|---|
| Горячий | Внутрипроцессная память | Количество строк ниже порога, либо таблица — цель связи | <1 мс |
| Тёплый | Iceberg на локальном SSD | Превышен порог частоты запросов | ~5–20 мс |
| Холодный | Удалённый источник | По умолчанию | 50–500 мс |
(REQ-230, REQ-236, REQ-238, REQ-241)
Импорт метаданных (Hasura v2 / DDN)¶
Существующие развёртывания Hasura можно преобразовать в конфигурацию Provisa без ручного переписывания. (REQ-182, REQ-183)
| Модуль | Вход | Выход |
|---|---|---|
hasura_v2/ |
Hasura v2 metadata.yaml |
Provisa config.yaml |
ddn/ |
Hasura DDN supergraph JSON | Provisa config.yaml |
Оба конвертера сопоставляют отслеживаемые таблицы, связи, разрешения и удалённые схемы. Результат — полная конфигурация Provisa, готовая к развёртыванию. (REQ-182, REQ-183)
Apollo Federation¶
compiler/federation.py раскрывает Provisa как субграф Apollo Federation v2. (REQ-259) SDL субграфа автоматически генерируется из опубликованной схемы с директивами @key на колонках первичного ключа и аннотациями @external/@provides на межсубграфовых связях. Provisa отвечает на запросы _entities и _service, требуемые шлюзом федерации. (REQ-259)
Курсорная пагинация¶
Все запросы списков поддерживают курсорную пагинацию в стиле Relay через compiler/cursor.py. (REQ-218) Клиенты передают аргументы first/after (вперёд) или last/before (назад). Компилятор кодирует позицию строки как непрозрачный курсор в base64 и внедряет соответствующие предложения WHERE/LIMIT. Каждый запрос списка возвращает объект pageInfo:
| Поле | Тип | Описание |
|---|---|---|
hasNextPage |
Boolean | True, если после этой страницы есть ещё результаты |
hasPreviousPage |
Boolean | True, если есть результаты до этой страницы |
startCursor |
String | Курсор первого узла на этой странице |
endCursor |
String | Курсор последнего узла на этой странице |
Агрегатные запросы¶
Каждая зарегистрированная таблица получает автоматически сгенерированное корневое поле {table}_aggregate (compiler/aggregate_gen.py). (REQ-196) Агрегатный тип раскрывает count, sum, avg, min, max для каждой числовой колонки и nodes для доступа к отфильтрованным строкам с полным выбором полей (те же RLS/маскирование, что и в базовом запросе). (REQ-196, REQ-198) Агрегатные запросы имеют право на маршрутизацию через Aggregate MV — см. mv/aggregate_catalog.py. (REQ-198)
Автоматически сохраняемые запросы (APQ)¶
apq/cache.py реализует проводной протокол Apollo APQ. (REQ-288) Когда клиент отправляет только хеш запроса (extensions.persistedQuery), Provisa ищет его в Redis. (REQ-289) При промахе возвращается ошибка PersistedQueryNotFound; клиент повторяет запрос с полным телом, которое Provisa сохраняет. (REQ-288) Это отдельно от кеширования результатов (cache/).
Наследуемые роли¶
Роли в core/models.py могут ссылаться на parent_role_id. (REQ-215) flatten_roles() рекурсивно разрешает цепочку наследования и объединяет предложения WHERE для RLS (через AND), видимость колонок (объединение, побеждает наиболее ограничительное) и политики маскирования (дочерняя переопределяет родительскую для каждой колонки). Это позволяет избежать дублирования наборов разрешений между похожими ролями (например, analyst, наследующая от reader). (REQ-215)
Хук утверждения ABAC¶
auth/approval_hook.py — подключаемый хук авторизации, вызываемый перед выполнением запроса, после RLS и маскирования. (REQ-203) Он интегрируется с внешними движками политик (OPA, пользовательские сервисы ABAC).
| Настройка | Описание |
|---|---|
| Транспорт | webhook (HTTP POST), grpc или unix_socket |
| Область действия | Для таблицы, для источника или глобальная |
| Политика отката | allow или deny, когда конечная точка хука недостижима |
Автоматическое обнаружение enum-типов¶
compiler/enum_detect.py интроспектирует нативные enum-типы PostgreSQL (pg_enum) во время генерации схемы. (REQ-221) Колонки, использующие пользовательский enum-тип PostgreSQL, повышаются до GraphQL enum-типов — их значения становятся членами enum, а не строковыми скалярами.
Запланированные триггеры¶
scheduler/jobs.py использует APScheduler для запуска фоновых заданий, определённых как cron- или интервальные триггеры. (REQ-216) Каждое задание может выполнить POST на URL webhook, выполнить мутацию против конечной точки данных или опубликовать результаты запроса в тему Kafka. Триггеры настраиваются через admin API (мутации scheduledTrigger) или ключ scheduled_triggers в YAML-конфигурации. (REQ-216)
Подсказки производительности федерации¶
compiler/hints.py разбирает подсказки стюардов, встроенные в запросы как комментарии, с использованием синтаксиса комментариев Provisa. (REQ-279) Формат подсказки зависит от языка запроса:
| Подсказка | Эффект |
|---|---|
route=federated |
Принудительно федерировать через движок федерации, минуя прямую маршрутизацию через драйвер |
route=direct |
Принудительно выполнить напрямую через драйвер |
Пресеты колонок в мутациях¶
compiler/mutation_gen.py поддерживает пресеты для отдельных колонок на стороне сервера, применяемые при INSERT или UPDATE. (REQ-214) Пресеты не включаются в сгенерированный входной тип GraphQL-мутации — они внедряются компилятором прозрачно. Типы пресетов: static (буквальное значение) или session (значение из сессии/заголовка запроса, например x-hasura-user-id). (REQ-214)
Обозреватель схемы GraphQL Voyager¶
Admin UI (provisa-ui/src/pages/SchemaExplorer.tsx) встраивает GraphQL Voyager как интерактивный инструмент визуализации схемы. (REQ-248) Он отображает схему в области видимости роли как навигируемую диаграмму «сущность-связь» — таблицы как узлы, связи как рёбра. Показанная схема всегда отфильтрована по текущей выбранной роли.
Порядок применения безопасности¶
Для самого запроса нет gate по возможностям (capability) — governance выражается полностью через элементы управления на уровне данных. (REQ-001) Запрос на сыром SQL отклоняет (HTTP 403) любую таблицу вне области видимости объектов роли до того, как запустится governance. (REQ-267)
- Видимость объектов: схема для каждой роли скрывает неавторизованные таблицы/колонки; таблицы вне области видимости в сыром SQL отклоняются (REQ-039, REQ-267)
- Применение связей: обходы должны существовать в утверждённом каталоге связей, если роль не обладает
ignore_relationships— среди заложенных системных ролей это толькоmodeler(REQ-001, REQ-1297). В режиме повышенной безопасности эта возможность игнорируется, и ни один обход не выходит за пределы каталога (REQ-693) - RLS: внедрение предложения WHERE для каждой таблицы, для каждой роли (REQ-040, REQ-041, REQ-263)
- Маскирование колонок: преобразование данных для каждой колонки, для каждой роли (REQ-263)
- Ограничение строк (LIMIT): предел числа строк для ролей без
full_results; случайное статистическое сэмплирование — отдельная пользовательская функция запроса (REQ-263, REQ-478)
Все четыре интерфейса запросов (HTTP, Flight, gRPC, pgwire) применяют один и тот же конвейер governance этапа 2; ни один клиентский путь не может его обойти, не обойдя сервер. (REQ-002, REQ-038, REQ-266)
Пределы масштабируемости¶
Provisa — тонкий слой компиляции и маршрутизации — она добавляет к задержке запроса единицы миллисекунд. Однако пути, где Provisa сериализует данные результата, ограничены памятью процесса. Два пути по-настоящему неограничены:
| Путь | Ограничен памятью? | Подходит для |
|---|---|---|
| JSON встроенно (HTTP) | Да | Небольшие-средние результаты |
| Потоковая передача Arrow Flight (gRPC :8815) | Нет | Неограниченно — потоковая передача через Zaychik или Arrow API хранилища данных |
| Protobuf gRPC встроенно (:50051) | Да | Средние результаты, взаимодействие сервис-сервис |
| Перенаправление: загрузка Provisa (JSON, CSV, NDJSON, Arrow IPC) | Да | Средние результаты, скачивание файлов |
| Перенаправление: CTAS (Parquet, ORC) | Нет | Неограниченно — движок федерации пишет в S3 |
Пороговое зондирование¶
Для перенаправления на основе порога Provisa внедряет LIMIT threshold + 1 в запрос в качестве зонда. (REQ-140) Если в результате меньше строк, он возвращается встроенно (полный результат, никакой потраченной впустую работы). Если результат достигает предела, зонд отбрасывается, и полный запрос повторно выполняется через CTAS или загрузку Provisa. Это позволяет избежать SELECT COUNT(*) (который некоторые источники не оптимизируют) и работает для любого источника.
Для крупных аналитических нагрузок используйте один из вариантов:
- Arrow Flight (порт 8815) для потоковой передачи в инструменты данных — батчи проходят через Provisa без материализации (REQ-145)
- Перенаправление Parquet/ORC для экспортов на основе файлов — движок федерации пишет напрямую в S3, Provisa возвращает подписанный URL (REQ-138, REQ-044)
Инфраструктура¶
| Сервис | Образ | Порт | Назначение |
|---|---|---|---|
| Provisa API | (процесс хоста) | 8001 | Конечная точка HTTP/REST |
| Provisa Flight | (процесс хоста) | 8815 | Сервер Arrow Flight gRPC |
| Provisa gRPC | (процесс хоста) | 50051 | Сервер Protobuf gRPC |
| Federation Engine | trinodb/trino (по умолчанию) или внешнее хранилище данных |
8080 / варьируется | Движок федерации запросов — Trino для встроенного стека; Snowflake/Databricks/BigQuery/Fabric/Synapse/DuckDB для целей хранилищ данных |
| Zaychik | provisa-zaychik (собирается из исходников) |
8480 | Прокси Arrow Flight SQL для Trino; не требуется для движков хранилищ данных |
| PostgreSQL | postgres:16 |
5432 | Метаданные конфигурации + каталог Iceberg |
| MongoDB | mongo:7 |
27017 | Демонстрационный источник данных NoSQL |
| MinIO | minio/minio |
9000/9001 | S3-совместимое объектное хранилище |
| Redis | redis:7-alpine |
6379 | Кеш результатов запросов |
| PgBouncer | edoburu/pgbouncer |
6432 | Пул соединений для PG |
| Kafka | confluentinc/cp-kafka:7.6.0 |
9092 | Потоковые источники данных |
| Schema Registry | confluentinc/cp-schema-registry:7.6.0 |
8081 | Управление схемами Avro/Protobuf |