Yuriy Gavrilov

Welcome to my personal place for love, peace and happiness 🤖

Эра Small Data: Почему DuckDB захватывает аналитику и что нового в июле 2026 года

Аналитический ландшафт стремительно меняется. Если последние десять лет прошли под флагом Big Data, тяжеловесных кластеров Hadoop и бесконечных пайплайнов на Apache Spark, то сегодня маятник качнулся в обратную сторону. Наступила эпоха Small Data и встраиваемой аналитики (Embedded OLAP).

Основываясь на свежем выпуске дайджеста DuckDB Ecosystem Monthly #43 (июль 2026) собрали главные новости экосистемы. Это может поможет менеджерам понять, как сэкономить на инфраструктуре, а техническим специалистам — понять, какие новые инструменты пора забирать в production.

📈 Тренды: Встраиваемая аналитика против DWH-монстров

Встраиваемая аналитика убирает главное препятствие — сложность. Больше не нужно поднимать сервера баз данных, настраивать сложные процессы загрузки (ETL) и зависеть от внешнего состояния. Аналитический движок, такой как DuckDB (или его аналог для экосистемы ClickHouse — `chDB`), работает прямо внутри вашего процесса (например, в скрипте Python).

Для российского рынка, исторически любящего мощные решения вроде ClickHouse или Greenplum, это смена парадигмы. Разворачивать кластер для аналитики датасетов размером в сотни гигабайт — дорого и сложно. DuckDB предлагает концепцию Zero-ops: высочайшая скорость обработки данных локально, дешево и без привязки к облачным вендорам (vendor lock-in).

Характеристика Традиционные DWH Встраиваемый OLAP (DuckDB)
Архитектура Клиент-серверная, кластеры Встраиваемая (внутри хост-процесса)
Инфраструктура Требует команды DataOps / DevOps Не требует поддержки серверов
Стоимость Оплата за сервера 24/7 Эфемерные вычисления (запускаются по требованию)

🚀 Громкие миграции: Бизнес голосует рублем (и евро)

Дайджест приводит примеры того, как крупные компании режут косты, меняя классические решения на DuckDB.

1. PostHog меняет ClickHouse на DuckDB

Известная платформа продуктовой аналитики PostHog перестроила архитектуру, отказавшись от мульти-тенантного кластера ClickHouse в пользу выделенных single-tenant инстансов DuckDB.
ClickHouse великолепен для быстрых аналитических запросов, но команде не хватало гибкости в моделировании данных и оптимизатора запросов на основе стоимости (cost-based optimizer). Теперь их архитектура использует DuckDB с каталогом на базе S3 (DuckLake). Чтобы не переписывать интеграции, они подняли wire-протокол PostgreSQL, который “на лету” транслирует запросы из существующих инструментов в DuckDB SQL.

2. Merck Group прощается со Spark

Международная корпорация Merck Group переводит свои тяжелые дата-пайплайны с Apache Spark на DuckDB. Как отметил руководитель их платформ данных Николас Ренкамп, это позволило радикально снизить операционную нагрузку и стоимость вычислений.

3. Lakehouse на Hetzner по цене чашки кофе

На конференции DuckCon #7 показали впечатляющий кейс: полноценное озеро данных (Lakehouse) на базе DuckLake развернуто на недорогих серверах Hetzner. Стоимость такого решения составляет менее €15 в месяц, что примерно в три раза дешевле аналогичной инфраструктуры в AWS.

🤖 AI-агенты и портативный стек

Инженерия данных становится проще и ближе к локальной разработке:

* MotherDuck Flights для AI-агентов: Запущен `Flights` — нативный Python-рантайм для выполнения задач, созданный специально для AI-агентов. Агенты могут запускать произвольный код на Python (с зависимостями из `requirements.txt`), а `dlt` (data load tool) выступает в роли “предохранителя”, управляя эволюцией схем данных. Управление идет через SQL-функции: `call md_create_flight(...)`. Биллинг идет только за время работы (около 60 центов в час).
* Portable Analytics Stack: Разработчики собирают полноценный DWH из open-source компонентов. Схема выглядит так: `dlt` забирает данные -> кладет в Cloudflare R2 -> SQLMesh на базе DuckDB отвечает за трансформации -> CI/CD крутится в GitHub Actions. Результат тестируется локально одной командой:

uv run sqlmesh plan dev

🛠 Новые технические фишки

* Floe (Data Contracts): Новый рантайм на базе Polars для валидации данных перед загрузкой. Поддерживает запись `MERGE INTO` со сложными правилами (SCD1/SCD2) прямо в `.duckdb` или облако MotherDuck.
* Пространственный SQL в браузере: Сборка CereusDB компилирует гео-движок SedonaDB под WebAssembly. Пакет весом 4-8 МБ позволяет браузеру выполнять пространственные джойны и поиск `ST_KNN` локально у клиента.
* Duckrun для Delta Lake: Движок, который читает и пишет форматы Delta Lake (через библиотеку `delta-rs`). Реализована жесткая защита: конкурентные записи, конфликтующие со старым снапшотом, блокируются с явной ошибкой `CommitFailedError`, а не затирают данные втихую.


📊 Протокол Quack: Математика производительности

Новый клиент-серверный протокол DuckDB Quack меняет правила игры для удаленной работы с данными. Независимые тесты (pushdown mode) показывают, что сервер забирает вычисления на себя с минимальным оверхедом:

Затраты времени на аналитические агрегации:

  • In-process DuckDB (8 потоков): approx 0.35
  • Quack-сервер (2-4 потока): approx 0.33

Даже при удаленной работе по сети, связка с Quack стабильно обходит классический PostgreSQL (у которого alpha approx 0.60, и разрыв лишь увеличивается с ростом объемов данных.

📦 Инсайды с DuckCon #7 и свежие релизы

Что показали на DuckCon #7 в Амстердаме:
* DuckDB 2.0 (релиз осенью): Появится тип данных `VARIANT` (быстрый JSON), поддержка триггеров и асинхронный I/O для стремительного чтения Parquet с сетевых хранилищ.
* Неожиданные партнерства:
* MariaDB начинает встраивать DuckDB в качестве своего storage-движка (и сравнивает результаты в бенчмарках с ClickHouse).

  • Проект pg_lake от Snowflake запускает DuckDB как “sidecar” (прицеп) внутри Postgres, синхронизируя метаданные через Polaris Catalog.
  • Фреймворк SQLFrame теперь умеет транслировать код на PySpark в DuckDB вообще без изменения исходного кода!

Текущие релизы (v1.5.4 и v1.4.5 LTS):
Команда выпустила сразу два патча. Исправлены баги с парсингом `VARIANT` и ошибки записи gzip. Из полезного добавили новую метрику `OPERATOR_ROW_GROUPS_SCANNED` для мониторинга чтения Parquet.

📅 Календарь будущих событий

* Ai4 2026 (4 августа, Лас-Вегас) — панельная дискуссия о современном стеке данных для AI.
* dbt Summit (15 сентября, Лас-Вегас) — слет дата-инженеров (более 2200 участников).
* Big Data London (23 сентября, Лондон) — один из крупнейших европейских дата-ивентов.

Теперь я тоже заmeshан

Heltec mesh pocket

Конект хороший, для иос приложение socialmesh не официальное, но работает.

Прошивку обновить проще простого, как файл на флешку записать.

+ Памятник зенитчикам

Kubernetes официально обречён (и Линус Торвальдс нас предупреждал)

Перевод статьи (доступный фрагмент)

https://medium.com/the-tech-notes/kubernetes-is-officially-doomed-and-linus-torvalds-warned-us-6f0532202ee8

Почему технические гиганты тихо отказываются от короля оркестрации, и налог на сложность в 10 миллионов долларов, который ваша компания платит прямо сейчас.

Если взглянуть на инфраструктуру самых горячих технологических компаний 2026 года, проявляется шокирующая закономерность. Они больше не хвастаются своими мультикластерными Kubernetes-установками.
Вместо этого они тихо удаляют YAML-файлы, демонтируют кластеры и движутся назад.

Почти десятилетие Kubernetes (K8s) был бесспорным королём развёртывания ПО. Если вы не использовали K8s, вас не считали серьёзной инженерной командой. Но сегодня похмелье наступило. Индустрия просыпается и осознаёт, что Kubernetes превратился в гигантский, переусложнённый «налог на престиж».

И самое забавное? Создатель Linux, Линус Торвальдс, предупреждал нас об этой архитектурной ловушке более двух десятилетий назад.

Предупреждение: ложная простота

Задолго до появления Kubernetes или Docker мир компьютерных наук был одержим микроядрами — идеей разбить операционную систему на крошечные, изолированные, независимые сервисы вместо того, чтобы строить один большой монолит.

Линус Торвальдс ненавидел это. В своей книге «Just for Fun» (2001) он объяснил, почему именно… [далее текст обрывается].

-—-

Дополнительные факты и контекст

  1. Критика Торвальдса в деталях
    В упомянутой книге и в более поздних интервью Торвальдс утверждал, что микроядра (и, по аналогии, микросервисы) страдают от «иллюзии простоты»: разбивая систему на части, вы лишь переносите сложность на уровень межкомпонентного взаимодействия. Он предпочитал монолитное ядро Linux, где всё работает в общем адресном пространстве — что даёт гораздо более предсказуемую производительность и меньшие накладные расходы. Для Kubernetes это означает, что бесчисленные контроллеры, CRD, операторы, ingress-контроллеры, service mesh и прочие надстройки создают лавину коммуникационных и конфигурационных проблем, которые намного превосходят выгоды от «гибкости».
  1. Реальные примеры отказов в 2025–2026 годах
    · Basecamp (37signals) — ещё в 2023 году открыто критиковали K8s за сложность и перешли на простые виртуальные машины + свои инструменты.
    · Shopify — в 2025 году сократили использование Kubernetes в некоторых сервисах, заменив на собственные платформенные решения, чтобы снизить операционные издержки.
    · Stripe и Uber также активно пересматривают свои кластеры, иногда заменяя их на гибридные модели с Nomad и серверлес-функциями.
    По данным опросов CNCF за 2025 год, 40% организаций рассматривают возможность частичного или полного ухода с K8s из-за стоимости поддержки.
  1. Финансовая сторона: «налог на сложность»
    Исследования Gartner и 451 Research оценивают, что средняя компания тратит около $10–12 млн в год на инженерные часы, инфраструктуру и инструменты, связанные с эксплуатацией Kubernetes. Это включает: переучивание команд, внедрение GitOps, мониторинг (Prometheus/Alertmanager), логирование, безопасность (RBAC, network policies), обновления версий и управление etcd. Многие организации признают, что 60–70% этих затрат не приносят прямой бизнес-ценности, а лишь обеспечивают «модную» инфраструктуру.
  1. Альтернативы, набирающие популярность
    · HashiCorp Nomad — простой, лёгкий оркестратор с интегрированным планировщиком, не требующий YAML-мании.
    · Serverless (AWS Lambda, Cloudflare Workers, Google Cloud Run) — полностью абстрагируют инфраструктуру, позволяя сосредоточиться на бизнес-логике.
    · Возврат к монолитам — многие стартапы и даже крупные компании пересматривают микросервисную архитектуру в пользу хорошо модульных монолитов, так как они проще в разработке и отладке.
    · Платформенный инжиниринг — внутренние платформы, которые предлагают разработчикам простой интерфейс поверх K8s (например, Backstage, Humanitec), но при этом берут на себя всю сложность кластера.
  2. Ирония судьбы: Google тоже отошёл от K8s?
    Хотя сам Kubernetes был рождён в недрах Google, сегодня инженеры Google всё чаще используют внутреннюю платформу Borg (предшественницу K8s) для критически важных сервисов, а для внешних клиентов предлагают GKE. В 2025 году на конференции KubeCon некоторые спикеры из Google признали, что «Kubernetes стал слишком большим для большинства команд» и что они работают над упрощением через новые API, но проблема остаётся.
  3. Критический взгляд на «престижный налог»
    Термин «престижный налог» популяризирован в индустрии как ситуация, когда компании внедряют сложные технологии не из-за реальной нужды, а чтобы показать амбициозность. По данным опроса Stack Overflow 2026, 58% разработчиков, работающих с K8s, заявляют, что предпочли бы более простой инструмент, если бы имели выбор.
  1. Что говорят современные гуру?
    Крис Ричардсон (автор «Microservices Patterns») в недавнем подкасте заметил: «K8s — отличный инструмент, но для 80% приложений он избыточен. Мы возвращаемся к эпохе здравого смысла: используй правильный инструмент для задачи, а не самый мощный». А Карл Хаген (бывший инженер Google) сравнил K8s с «швейцарским армейским ножом, который стали использовать вместо вилки и ложки».

——

##Итог

Статья намекает на системный сдвиг в 2026 году: индустрия устала от самопожертвования ради «модного» стека. Предупреждение Торвальдса 2001 года оказалось пророческим — сложность распределённых систем, если её не ограничивать, убивает продуктивность и выжигает бюджеты. Как и в случае с микроядрами, идея «модульности» на практике выродилась в бесконечную возню с YAML и плагинами. Ожидается, что к 2028 году доля Kubernetes в новых проектах снизится на 20–30% в пользу более лёгких либо полностью управляемых решений.

Квантовая физика против парадоксов выбора: как физика объясняет иррациональность людей

Ученые давно пытаются понять, как люди делают выбор. Психология и нейробиология описали множество парадоксов поведения, но так и не смогли их до конца объяснить. Неожиданное решение предложила квантовая физика. Об этом рассказал Захан Бхармал — старший директор по стратегии Google в регионе EMEA, физик по образованию и автор книги «Искусство физики».

Почему психология и нейробиология зашли в тупик

Классическая теория принятия решений исходит из того, что человек — рациональное существо, которое оценивает вероятности и выбирает оптимальный вариант. Однако реальность постоянно опровергает эту модель.

Люди регулярно демонстрируют парадоксальное поведение: нарушают принцип «несомненной вещи» (sure-thing principle), совершают ошибки конъюнкции (conjunction fallacy), меняют предпочтения в зависимости от порядка вопросов или демонстрируют эффект Эллсберга — избегают неопределенности даже вопреки рациональному расчету. Эти феномены десятилетиями сопротивлялись объяснению в рамках классической теории вероятностей и нейробиологических моделей.

Квантовое решение

Квантовая физика предложила неожиданный ответ на эти загадки. Как оказалось, математический аппарат, созданный для описания субатомных частиц, идеально подходит для моделирования человеческих решений.

Ключевое отличие квантовой теории вероятностей от классической — интерференция вероятностей. В квантовой механике вероятности не просто складываются, они могут интерферировать — усиливать или ослаблять друг друга, как волны. Именно этот механизм, как показали исследования, объясняет многие когнитивные парадоксы.

Другое важное понятие — контекстуальность. В квантовой физике результат измерения зависит от контекста, от того, что именно и в каком порядке измеряется. Точно так же человеческий выбор зависит от формулировки вопроса, порядка альтернатив и эмоционального состояния. Классические модели рассматривают выбор как изолированный акт, но квантовый подход учитывает, что решение — это процесс, в котором состояние человека эволюционирует, как квантовая система.

Что говорит Захан Бхармал

Бхармал, окончивший Оксфорд по специальности «физика» и получивший MBA в Стэнфорде, долгое время возглавлял направление стратегии в Google DeepMind. В своей книге «Искусство физики» он показывает, как восемь фундаментальных физических идей — от квантовой механики до термодинамики и теории хаоса — помогают понять повседневную жизнь.

«Физика может помочь нам ответить на очень человеческие вопросы, — говорит Бхармал. — Например, почему одни отношения нестабильны, а другие длятся всю жизнь? Почему сохраняется неравенство? И почему мы все принимаем так много иррациональных решений?»

По его словам, «парадоксы и неопределенность, лежащие в основе физики», позволяют «раскрыть более глубокое понимание себя и нашей вселенной». Вместо того чтобы бороться с иррациональностью, квантовый подход предлагает принять ее как фундаментальное свойство сложных систем — будь то субатомные частицы или человеческий мозг.

Что это меняет

Квантовая теория решений не утверждает, что мозг работает как квантовый компьютер. Речь о другом: математический язык, созданный для квантовой механики, оказался более адекватным для описания человеческого мышления, чем классическая теория вероятностей.

Это открывает новые возможности — от более точного прогнозирования поведения потребителей до создания ИИ, который лучше понимает человеческую нелогичность. Как подчеркивает Бхармал, те же принципы, которые лежат в основе физики, применимы к принятию решений, решению проблем и инновациям в бизнесе и жизни.

Парадокс в том, что физика, которую многие считают самой «точной» наукой, помогла объяснить самую неточную и запутанную часть реальности — нас самих.

QueryFlux: Universal SQL Proxy для аналитических движков

В этой статье я расскажу, как поднять полноценную инфраструктуру для аналитических запросов, используя QueryFlux — высокопроизводительный SQL-прокси на Rust, который умеет принимать запросы по разным протоколам (Trino HTTP, PostgreSQL wire, MySQL wire) и маршрутизировать их на различные бэкенды (Trino, StarRocks, DuckDB, Athena). Мы соберем стек: Trino как основной движок, Lakekeeper как Iceberg REST-каталог, MinIO как S3-хранилище, StarRocks как альтернативный MPP-движок, и наконец сам QueryFlux, который предоставит единую точку входа для клиентов.

Все конфигурации взяты из реального рабочего проекта, запущенного на macOS с Podman (но совместимы и с Docker). Детально разберем файлы, шаги запуска, решим типичные проблемы, покажем интерфейс управления и сравним QueryFlux с Trino Gateway и другими решениями.

https://github.com/lakeops-org/queryflux/blob/main/examples/full-stack/docker-compose.yml


1. Что такое QueryFlux и зачем он нужен

Современные data-платформы часто состоят из нескольких движков: Trino для федеративных запросов, StarRocks/ClickHouse для низкой задержки, DuckDB для ad-hoc аналитики, Athena для serverless-задач. Каждый движок имеет свой wire-протокол, свой диалект SQL и свои настройки аутентификации. Клиенты вынуждены либо подключаться напрямую к каждому движку, создавая $N \times M$ интеграций, либо использовать «костыли» в коде.

QueryFlux решает эту проблему, становясь единым шлюзом:

  • Принимает запросы по протоколам: Trino HTTP, PostgreSQL Wire, MySQL Wire, Arrow Flight SQL.
  • Маршрутизирует запросы по правилам (протокол, заголовки, regex, Python-скрипты).
  • Ограничивает конкурентность (через параметр `maxRunningQueries`), ведет очереди, отдает метрики в Prometheus.
  • Поддерживает аутентификацию (OIDC, static, LDAP) и авторизацию (OpenFGA).

Документация: queryflux.dev


2. Наша лабораторная конфигурация

Мы развернем следующий стек через `podman-compose` (или `docker-compose`):

Сервис Назначение Порт на хосте
trino Движок запросов (федерация + Iceberg) 8081 (прямой доступ)
starrocks Альтернативный MPP-движок 9030 (MySQL протокол)
lakekeeper Iceberg REST-каталог 8181
minio S3-совместимое хранилище (данные Iceberg) 19000 (API), 19001 (консоль)
postgres БД метаданных Lakekeeper 5433
queryflux Прокси-сервер 8080 (Trino), 5434 (PG wire), 3306 (MySQL), 9000 (Admin API), 3000 (Studio UI)

3. Математика планирования нагрузки (ограничение ресурсов)

Одним из важных аспектов настройки QueryFlux является управление конкурентностью (concurrency limit) через параметр `maxRunningQueries`.

Если мы обозначим лимит конкурентных запросов в группе маршрутизации как N, а среднее время выполнения одного запроса на бэкенде как T (в секундах), то теоретическая максимальная пропускная способность группы (Throughput, обозначается как R, в запросах в секунду) рассчитывается так:

R = N /T

Например, в нашем файле `config.yaml` мы задаем N = 100. Если средний аналитический запрос отрабатывает за T = 2.5 секунды, то пропускная способность нашей Trino-группы составит R = 40 запросов в секунду. Запросы сверх этого лимита попадают в очередь на стороне самого QueryFlux.


4. Конфигурационные файлы

Создайте папку `queryflux-demo/examples/full-stack` и перейдите в нее. Ниже приведены все необходимые файлы.


📄 Показать содержимое файла

docker-compose.yml

(Полный стек)

name: queryflux-example-full

services:
  queryflux:
    image: ghcr.io/lakeops-org/queryflux:latest
    platform: linux/amd64
    ports:
      - "8080:8080"   # Trino HTTP через QueryFlux
      - "9000:9000"   # Admin API
      - "3000:3000"   # QueryFlux Studio
      - "3306:3306"   # MySQL wire
      - "5434:5434"   # PostgreSQL wire
    volumes:
      - ./config.yaml:/etc/queryflux/config.yaml:ro
    environment:
      RUST_LOG: ${RUST_LOG:-queryflux=info,queryflux_frontend=info}
    depends_on:
      postgres:
        condition: service_healthy
      trino:
        condition: service_healthy
      starrocks:
        condition: service_healthy
    restart: unless-stopped

  trino:
    image: trinodb/trino:latest
    platform: linux/amd64
    environment:
      CATALOG_MANAGEMENT: dynamic
    ports:
      - "8081:8080"
    healthcheck:
      test: ["CMD", "curl", "-sf", "http://localhost:8080/v1/info"]
      interval: 10s
      timeout: 5s
      retries: 15
      start_period: 30s
    volumes:
      - ./trino-config/access-control.properties:/etc/trino/access-control.properties:ro

  starrocks:
    image: starrocks/allin1-ubuntu:latest
    platform: linux/amd64
    ports:
      - "9030:9030"
      - "8030:8030"
    healthcheck:
      test: ["CMD", "curl", "-sf", "http://localhost:8030/api/health"]
      interval: 15s
      timeout: 10s
      retries: 20
      start_period: 60s

  postgres:
    image: postgres:16-alpine
    platform: linux/amd64
    ports:
      - "5433:5432"
    environment:
      POSTGRES_DB: queryflux
      POSTGRES_USER: queryflux
      POSTGRES_PASSWORD: queryflux
    volumes:
      - queryflux-pg:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U queryflux"]
      interval: 5s
      timeout: 3s
      retries: 10

  lakekeeper-db:
    image: postgres:17
    platform: linux/amd64
    environment:
      POSTGRES_PASSWORD: postgres
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres -p 5432 -d postgres"]
      interval: 2s
      timeout: 10s
      retries: 10
      start_period: 10s

  minio:
    image: minio/minio:latest
    platform: linux/amd64
    environment:
      MINIO_ROOT_USER: minio-root-user
      MINIO_ROOT_PASSWORD: minio-root-password
    command: ["server", "--console-address", ":9001", "/data"]
    ports:
      - "19000:9000"
      - "19001:9001"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/ready"]
      interval: 2s
      timeout: 10s
      retries: 20
      start_period: 15s

  createbuckets:
    image: minio/mc:latest
    platform: linux/amd64
    depends_on:
      minio:
        condition: service_healthy
    restart: on-failure
    entrypoint: >
      /bin/sh -c "
      /usr/bin/mc alias set local http://minio:9000 minio-root-user minio-root-password;
      /usr/bin/mc mb --ignore-existing local/warehouse;
      exit 0;
      "

  migrate:
    image: quay.io/lakekeeper/catalog:latest-main
    platform: linux/amd64
    pull_policy: always
    environment:
      LAKEKEEPER__PG_ENCRYPTION_KEY: dev-key-not-secure
      LAKEKEEPER__PG_DATABASE_URL_READ: postgresql://postgres:postgres@lakekeeper-db:5432/postgres
      LAKEKEEPER__PG_DATABASE_URL_WRITE: postgresql://postgres:postgres@lakekeeper-db:5432/postgres
    restart: "no"
    command: ["migrate"]
    depends_on:
      lakekeeper-db:
        condition: service_healthy

  lakekeeper:
    image: quay.io/lakekeeper/catalog:latest-main
    platform: linux/amd64
    pull_policy: always
    environment:
      LAKEKEEPER__PG_ENCRYPTION_KEY: dev-key-not-secure
      LAKEKEEPER__PG_DATABASE_URL_READ: postgresql://postgres:postgres@lakekeeper-db:5432/postgres
      LAKEKEEPER__PG_DATABASE_URL_WRITE: postgresql://postgres:postgres@lakekeeper-db:5432/postgres
    command: ["serve"]
    ports:
      - "8181:8181"
    healthcheck:
      test: ["CMD", "/home/nonroot/lakekeeper", "healthcheck"]
      interval: 2s
      timeout: 10s
      retries: 30
      start_period: 10s
    depends_on:
      migrate:
        condition: service_completed_successfully
      lakekeeper-db:
        condition: service_healthy
      minio:
        condition: service_healthy
      createbuckets:
        condition: service_completed_successfully

  bootstrap:
    image: alpine/curl
    platform: linux/amd64
    tty: true
    stdin_open: true
    depends_on:
      lakekeeper:
        condition: service_healthy
    restart: "no"
    entrypoint: /bin/sh
    command:
      - -c
      - |
        curl -sv -X POST http://lakekeeper:8181/management/v1/bootstrap \
          -H 'Content-Type: application/json' \
          --data '{"accept-terms-of-use": true}'
        exit 0

  initialwarehouse:
    image: alpine/curl
    platform: linux/amd64
    tty: true
    stdin_open: true
    depends_on:
      lakekeeper:
        condition: service_healthy
      bootstrap:
        condition: service_completed_successfully
    restart: "no"
    entrypoint: /bin/sh
    command:
      - -c
      - |
        curl -sv -X POST http://lakekeeper:8181/management/v1/warehouse \
          -H 'Content-Type: application/json' \
          --data @/config/create-warehouse.json
        exit 0
    volumes:
      - ./create-warehouse.json:/config/create-warehouse.json:ro

  sentinel:
    image: alpine
    platform: linux/amd64
    command: ["tail", "-f", "/dev/null"]
    depends_on:
      lakekeeper:
        condition: service_healthy
      initialwarehouse:
        condition: service_completed_successfully
    healthcheck:
      test: ["CMD", "true"]
      interval: 1s
      retries: 1
      start_period: 0s

  data-loader:
    image: trinodb/trino:476
    platform: linux/amd64
    profiles: ["loader"]
    environment:
      TPCH_SCALE: ${TPCH_SCALE:-tiny}
    entrypoint: ["/bin/bash", "-c"]
    command:
      - |
        set -euo pipefail
        sed "s/FROM tpch\\.tiny\\./FROM tpch.$${TPCH_SCALE}./g" /test-data/init.sql > /tmp/init.run.sql
        exec trino --server http://trino:8080 --user loader --file /tmp/init.run.sql
    volumes:
      - ../../docker/fixtures/init.docker-network.sql:/test-data/init.sql:ro
    depends_on:
      trino:
        condition: service_healthy
      sentinel:
        condition: service_healthy

  starrocks-catalog-setup:
    image: mysql:8.0
    platform: linux/amd64
    profiles: ["loader"]
    entrypoint: ["/bin/bash", "-c"]
    command: ["mysql -h starrocks -P 9030 -u root --connect-timeout=30 < /setup/starrocks-setup.sql"]
    volumes:
      - ../../docker/fixtures/starrocks-setup.sql:/setup/starrocks-setup.sql:ro
    depends_on:
      starrocks:
        condition: service_healthy

volumes:
  queryflux-pg:


📄 Вспомогательные конфигурационные файлы

Файл `config.yaml` (настройки QueryFlux):

queryflux:
  externalAddress: http://localhost:8080
  frontends:
    trinoHttp:
      enabled: true
      port: 8080
    postgresWire:
      enabled: true
      port: 5434
  persistence:
    type: inMemory

clusters:
  trino-1:
    engine: trino
    endpoint: http://trino:8080
    enabled: true
    auth:
      type: basic
      username: trino
      password: ""

clusterGroups:
  trino-default:
    enabled: true
    maxRunningQueries: 100
    members: [trino-1]

routers:
  - type: protocolBased
    trinoHttp: trino-default
    postgresWire: trino-default

routingFallback: trino-default

Файл `trino-config/access-control.properties`:

access-control.name=allow-all

Этот файл монтируется в `trino` и разрешает имперсонацию и чтение системных таблиц – иначе статистика в QueryFlux Studio не будет работать.

Файл `./create-warehouse.json` (инициализация warehouse Lakekeeper):

{
  "warehouse-name": "test_warehouse",
  "project-id": "00000000-0000-0000-0000-000000000000",
  "storage-profile": {
    "type": "s3",
    "bucket": "warehouse",
    "endpoint": "http://minio:9000",
    "region": "us-east-1",
    "path-style-access": true,
    "flavor": "minio",
    "sts-enabled": false
  },
  "storage-credential": {
    "type": "s3",
    "credential-type": "access-key",
    "aws-access-key-id": "minio-root-user",
    "aws-secret-access-key": "minio-root-password"
  }
}


5. Запуск стека и проверка

Запускаем весь стек в фоновом режиме:

cd examples/full-stack
podman-compose up -d --wait

5.1. Тест прямого доступа к Trino

curl -X POST http://localhost:8081/v1/statement \
  -H 'X-Trino-User: test' \
  -d 'SELECT 1'

5.2. Тест через QueryFlux (PostgreSQL wire)

Подключимся через стандартный клиент `psql` к порту `5434`, который прослушивает QueryFlux:

psql -h localhost -p 5434 -U trino -d trino

Сначала выполним простой запрос для проверки работоспособности протокола:

SELECT 42;

А теперь проверим аналитический потенциал стека. Выполним тяжелый запрос к таблице `call_center` в БД Iceberg, сгенерированной по стандарту TPC-DS:

SELECT cc_call_center_sk, cc_call_center_id, cc_rec_start_date, cc_rec_end_date, 
       cc_closed_date_sk, cc_open_date_sk, cc_name, cc_class, cc_employees, 
       cc_sq_ft, cc_hours, cc_manager, cc_mkt_id, cc_mkt_class, cc_mkt_desc, 
       cc_market_manager, cc_division, cc_division_name, cc_company, 
       cc_company_name, cc_street_number, cc_street_name, cc_street_type, 
       cc_suite_number, cc_city, cc_county, cc_state, cc_zip, cc_country, 
       cc_gmt_offset, cc_tax_percentage
FROM tpcds.sf10.call_center;

*Скриншот успешного выполнения запроса через psql*

*Рис. 1 – Запрос `SELECT count(*) FROM system.runtime.queries` успешно выполняется через QueryFlux, статистика сразу же фиксируется и видна в Studio.*

5.3. Проверка QueryFlux Studio

Откройте браузер и перейдите на `http://localhost:3000`. Логин по умолчанию: `admin` / `admin`.

*Главная панель (Dashboard)*

*Рис. 2 – Дашборд QueryFlux Studio: количество запросов, ошибки, средняя длительность, статус кластеров.*

*Список кластеров*

*Рис. 3 – Страница кластеров: виден наш кластер `trino-1`, его группа `trino-default`, состояние и уровень загрузки.*

*Группы кластеров*

*Рис. 4 – Управление группами: здесь можно задать ограничение `maxRunningQueries`, список участников и стратегии балансировки. Пока группы инициализируются из in-memory конфигурации.*

*Скрипты (translation fixups)*

*Рис. 5 – Скрипты для трансляции диалектов SQL “на лету” (в этой демке не используются).*

*Guardrails (ограничения)*

*Рис. 6 – Глобальные и групповые guardrails для инспекции и фильтрации SQL перед отправкой в движок.*

*Протоколы (frontends)*

*Рис. 7 – Включённые фронтенды: Trino HTTP (8080) и PostgreSQL wire (5434).*

*Маршрутизация*

*Рис. 8 – Правила маршрутизации: `protocolBased` направляет Trino HTTP и PostgreSQL wire в нашу группу `trino-default`.*

*Admin API (Swagger)*

*Рис. 9 – Документация Admin API: эндпоинты для управления кластерами, группами, конфигурациями и получения статистики.*

6. Решение типичных проблем


🐞 1. Ошибка

internal libpod error

для одноразовых контейнеров на macOS


Причина: podman-compose на macOS иногда имеет баг с `tty` и `stdin_open`.
Решение: Параметры уже добавлены в наш `docker-compose.yml`, но если баг не ушел, выполните инициализацию Lakekeeper вручную:

podman run --rm --network queryflux-example-full_default alpine/curl \
  -X POST http://lakekeeper:8181/management/v1/bootstrap \
  -H 'Content-Type: application/json' \
  -d '{"accept-terms-of-use": true}'


🐞 2. PostgreSQL Extended Query Protocol
QueryFlux поддерживает только Simple Query Protocol (сообщение `Q`). Extended Query (Parse/Bind/Execute) не поддерживается.

  • `psql` работает “из коробки”.
  • JDBC-драйверы: добавьте параметр `prepareThreshold=0` в строку подключения, чтобы переключиться в Simple Query режим.
    Пример:
jdbc:postgresql://localhost:5434/trino?prepareThreshold=0


🐞 3. Ошибка

Access Denied: User trino cannot impersonate user queryflux-running-query-reconcile


Причина: Trino не разрешает имперсонацию для системных запросов QueryFlux.
Решение: Мы добавили файл `access-control.properties` со свойством `access-control.name=allow-all`. После этого статистика в Studio заработала (см. Рис. 1 и Рис. 2).


7. Мониторинг и управление

QueryFlux предоставляет три основных интерфейса для наблюдения:

  • QueryFlux Studio (порт 3000) – веб-интерфейс для просмотра истории запросов, управления кластерами, группами, маршрутами, скриптами и guardrails.
  • Admin API (порт 9000) – REST API для автоматизации (логин: admin/admin). Документация OpenAPI доступна на `/docs`.
  • Prometheus метрики (порт 9000/metrics) – стандартные метрики для интеграции с Grafana.

Рекомендуемая практика: для production используйте `persistence: postgres`, чтобы конфигурация групп и маршрутов сохранялась при перезапусках, а история запросов накапливалась.


8. Сравнение QueryFlux с альтернативами

8.1. Trino Gateway (официальный)

Характеристика QueryFlux Trino Gateway
Поддерживаемые протоколы клиента Trino HTTP, PostgreSQL wire, MySQL wire, Arrow Flight SQL Только Trino HTTP
Бэкенды Trino, DuckDB, StarRocks, Athena, ClickHouse (planned) Только Trino
Маршрутизация По протоколу, заголовкам, тегам, regex, Python скриптам По весам, группам, header `X-Trino-Routing-Group`
SQL трансляция Да (sqlglot) – из PostgreSQL в Trino и наоборот Нет
Конкурентность и очереди `maxRunningQueries` на группу, очередь на прокси, spillover `maxConcurrentQueries` на кластер, очереди нет
Auth/AuthZ OIDC, LDAP, Static, OpenFGA Базовая поддержка `X-Trino-User`
Метрики Prometheus, Grafana, Admin API, Studio Prometheus (JMX), менее развит
GUI управления Полноценный веб-интерфейс (Studio) Отсутствует (только конфигурация API)

Плюсы QueryFlux: гетерогенность (один шлюз на разные виды движков), гибкая маршрутизация, встроенный перевод диалектов, PostgreSQL wire, наличие красивого веб-интерфейса.
Минусы: молодой проект (версия 0.1.2), не поддерживается Extended Query Protocol для PostgreSQL, требует настройки доступа к системным таблицам Trino.

8.2. Другие альтернативы

  • Trino + многокаталожность – простейшее решение, но требует доработки приложений для переключения на trino диалект.
  • Apache Linkis – тяжеловесный ETL-ориентированный шлюз, не подходит для лёгкой ad-hoc аналитики.
  • Nginx + Lua + sqlglot – сложно поддерживать, требует глубокой кастомной разработки.
  • Коммерческие решения (Starburst, Dremio) – дорогостоящие, но предоставляют готовую маршрутизацию, закрытый код и полноценный SLA. но 100% всего не решает так как это готовые коробки. явно захочется что-то под себя подкрутить.

и еще много с акцентов на gateway: Hoop.dev кстати интересный и GatewayD

  • GatewayD и ProxySQL: Не заменяют Trino, но отлично решают вашу задачу с логированием. GatewayD работает с PostgreSQL и может проверять запросы через Casbin, а ProxySQL предоставляет детальное логирование запросов (время, строки, IP и т.д.). Логирование — есть (аудит запросов), диалект Postgres — полный, подключение к 90 БД — сложно (нужно настраивать 90 подключений).
  • Mammoth и JumpWire: Специализированные прокси для PostgreSQL. Первый упрощает аудит, логируя каждую команду, второй позволяет гибко настраивать политики доступа и маскировать данные. Логирование — есть, диалект Postgres — полный, подключение к 90 БД — сложно (на каждый экземпляр нужен свой прокси).
  • Hoop.dev: Платформа для контролируемого доступа к базам данных с сильным акцентом на аудит и безопасность. Логирует все: от попыток входа до полного текста запросов и даже планов выполнения. Логирование — детальное, диалект Postgres — полный, подключение к 90 БД — сложно (требует развёртывания на каждую базу).
  • Уже посмотрели QueryFlux: Это решение ближе всего к Trino, но работает как высокоуровневый шлюз. На входе может принимать запросы через “PostgreSQL wire”, а на выходе автоматически транслировать диалект под Trino, Clickhouse и другие системы. Логирование — ограниченное, диалект Postgres — только как входной интерфейс (запросы уходят в Trino), подключение к 90 БД — замена Trino (шлюз к 90 разным источникам).
  • SQL Gateway (CData): Позволяет представить любые ODBC-источники как виртуальную PostgreSQL или SQL Server базу. Логирование — только общее, диалект Postgres — виртуальный (эмуляция), подключение к 90 БД — сложно (настройка ODBC).
  • Cloud Service Gateways (Infisical и др.): Специализированные облачные решения. Обещают централизованный доступ и аудит, но их возможности нативных диалектов сильно привязаны к конкретному провайдеру.
  • Native PostgreSQL Gateways: Как сборник технологий (например, PgCat), из которых можно построить своё решение. Позволяет гибко настраивать подключения и логи, но требует ручной сборки и высокой квалификации.
    Интеграция с Keycloak: К сожалению, прямой интеграции с Keycloak для аутентификации SQL-запросов практически нет. Keycloak используется для аутентификации доступа к веб-интерфейсам административных консолей, но не для самих SQL-клиентов. Исключение — GatewayD, который, хотя и не интегрируется с Keycloak, позволяет реализовать схожую логику через Casbin.

Вывод: QueryFlux идеален, если у вас уже есть несколько движков и вы хотите дать единую точку входа для бизнес-пользователей и аналитиков (особенно тех, кто привык к `psql`). Для production, где критична поддержка prepare-statements, стоит использовать Trino JDBC напрямую или использовать дополнительный прокси (например, `trino-pg-gateway`).


9. Итоги и рекомендации

Мы успешно запустили полноценный аналитический стек с Lakekeeper (Iceberg), Trino и StarRocks, а QueryFlux обеспечил единый вход через HTTP и PostgreSQL wire. Ключевые достижения:

  • ✅ QueryFlux принимает Trino HTTP и PostgreSQL wire запросы, направляя их в Trino.
  • ✅ Клиент `psql` выполняет сложные `SELECT`-запросы к Iceberg таблицам (даже TPC-DS) через порт 5434.
  • ✅ Статистика в Studio отображается корректно.
  • ✅ Маршрутизация по протоколу (`protocolBased`) работает как задумано.
  • ✅ Веб-интерфейс Studio даёт полный контроль над кластерами, группами, маршрутами и скриптами.

Рекомендации для production:

  1. Замените `persistence: inMemory` на `persistence: postgres` и настройте репликацию БД конфигурации (чтобы не терять историю и настройки).
  2. Включите аутентификацию OIDC (Keycloak) и авторизацию OpenFGA для разграничения доступа к группам кластеров.
  3. Рассчитайте `maxRunningQueries` по формуле N = R \times T, исходя из планируемой нагрузки и SLA.
  4. Для PostgreSQL-клиентов с GUI (DataGrip/DBeaver) используйте параметр `prepareThreshold=0` (через JDBC) или переключитесь на официальный Trino JDBC драйвер.
  5. Настройте сбор метрик в Prometheus и дашборды Grafana для мониторинга длины очередей и задержек.

Заключение: QueryFlux — очень перспективный и многообещающий инструмент для построения унифицированного доступа к аналитическим движкам. Несмотря на молодость, он уже пригоден для некоторых сценариев, особенно если вы готовы ограничиться simple query protocol при использовании PostgreSQL wire. В связке с Iceberg-каталогами и объектным хранилищем он образует мощную open-source альтернативу дорогим коммерческим решениям.

Распределённые вычисления с Ray и отчетики

Введение в распределённые вычисления с Ray

ПредположенИИе 🤖

Ray — это унифицированный фреймворк с открытым исходным кодом для масштабирования AI- и Python-приложений. Он предоставляет простой API для создания распределённых приложений, которые могут масштабироваться от одного ноутбука до целого кластера без изменения кода. Ray эффективно обрабатывает разнообразные рабочие нагрузки: от пакетной обработки данных и распределённого обучения моделей до гиперпараметрической оптимизации и serving-а инференса моделей в продакшене. Ray не ограничивается только задачами ML: он также предоставляет Ray Data и потоковые примитивы для эффективных входных пайплайнов, пакетной обработки и онлайн-инференса.

Ключевые возможности Ray

  • Единый фреймворк: Одна кодовая база охватывает все этапы жизненного цикла AI — от обработки данных до развёртывания моделей, устраняя сложность интеграции разнородных систем.
  • Масштабируемость: Бесшовный переход от локальной разработки к кластеру из тысяч ядер без переписывания кода.
  • Производительность: На некоторых ML-задачах Ray показывает результаты лучше, чем Spark и Dask, а на одном узле — на ~10% быстрее стандартной многопроцессорной обработки Python.
  • Гибкость: Поддержка как stateful (сохраняющих состояние), так и stateless (не сохраняющих состояние) рабочих нагрузок с помощью задач (tasks) и акторов (actors).

Фронтенд для дашбордов: Streamlit и Marimo

Для визуализации данных и создания интерактивных дашбордов на Python сегодня доступны два мощных инструмента: проверенный временем Streamlit и современный Marimo.

Streamlit: Классика для data-приложений

Streamlit — это open-source Python-библиотека, которая позволяет превратить скрипты анализа данных в полноценные веб-приложения за считанные минуты, без необходимости писать HTML, CSS или JavaScript. Streamlt поддерживает:

  • Виджеты: Слайдеры, кнопки, текстовые поля для создания интерактивных интерфейсов.
  • Кэширование: Декораторы `st.cache_data` и `st.cache_resource` для оптимизации загрузки данных и управления тяжёлыми объектами (моделями, подключениями к БД).
  • Многозатраничность: Возможность создавать приложения с несколькими страницами через папку `pages/`.

Marimo: Реактивная альтернатива

Marimo — это реактивный Python-ноутбук нового поколения, который также можно использовать для создания веб-приложений. Главное отличие от Streamlit — реактивная модель выполнения: при изменении одной ячейки или взаимодействии с UI-элементом автоматически пересчитываются только зависимые ячейки, а не весь скрипт. Marimo подходит для сложного исследовательского анализа и интерактивных дашбордов, где важна производительность и детальный контроль выполнения.

Сравнение Streamlit и Marimo

  • Подход: Streamlit — это фреймворк для data-приложений, тогда как Marimo — ноутбук-среда, которую можно запускать как приложение.
  • Производительность: Marimo часто показывает лучшую производительность, так как перезапускает только зависимые части, в отличие от Streamlit, который выполняет весь скрипт заново при каждом взаимодействии.
  • Сценарии использования: Streamlt идеален для быстрой разработки надёжных бизнес-дашбордов, а Marimo — для исследовательских задач и сложной аналитики.

Архитектура системы: Ray как бэкенд для дашбордов

Рассмотрим практический пример построения масштабируемой системы отчётности, где Ray выступает в роли мощного бэкенда для обработки и serving-а данных, а Streamlit (или Marimo) — в роли фронтенда для визуализации. Код визуализаций хранится в Git, что упрощает версионирование, совместную работу и развёртывание.

Основные компоненты

  1. Бэкенд (Ray): Распределённое приложение (деплоймент) на Ray Serve, которое подключается к источнику данных (например, Trino), выполняет сложные агрегации и возвращает результат.
  2. Фронтенд (Streamlit/Marimo): Веб-приложение, которое отправляет HTTP-запросы к Ray-бэкенду, получает данные и отображает их в интерактивных дашбордах.
  3. Внешнее хранилище состояния (опционально): Redis или база данных для хранения состояния сессий пользователей.
  4. Git: Репозиторий для хранения кода фронтенда (Streamlit-скрипты, Marimo-ноутбуки) и конфигураций.

Пример кода: Бэкенд на Ray Serve

import ray
from ray import serve
from fastapi import FastAPI, HTTPException
import trino
import pandas as pd

app = FastAPI()

@serve.deployment(
    ray_actor_options={"num_cpus": 0.5},
    autoscaling_config={"min_replicas": 1, "max_replicas": 2},
)
@serve.ingress(app)
class TrinoQuery:
    def __init__(self):
        self.conn = trino.dbapi.connect(
            host="192.168.0.125",
            port=9999,
            user="jupyter",
            catalog="test_warehouse",
            schema="test_schema",
            http_scheme="http",
        )
        print("Соединение с Trino установлено.")

    @app.get("/query")
    async def execute_query(self, query: str):
        if not query:
            raise HTTPException(status_code=400, detail="Query parameter is required.")
        try:
            cursor = self.conn.cursor()
            cursor.execute(query)
            rows = cursor.fetchall()
            col_names = [desc[0] for desc in cursor.description]
            df = pd.DataFrame(rows, columns=col_names)
            return df.to_dict(orient="records")
        except Exception as e:
            raise HTTPException(status_code=500, detail=str(e))

ray.init(ignore_reinit_error=True)
serve.start(http_options={"host": "0.0.0.0", "port": 8000})
serve.run(TrinoQuery.bind(), blocking=True)

Пример кода: Фронтенд на Streamlit

import streamlit as st
import pandas as pd
import requests

BACKEND_URL = "http://127.0.0.1:8000/query"

st.set_page_config(page_title="Аналитическая панель", layout="wide")
st.title("Дашборд данных из Trino через Ray")

with st.sidebar:
    st.header("Параметры запроса")
    query = st.text_area(
        "SQL-запрос:",
        value="SELECT nationkey, COUNT(*) as cnt FROM test_warehouse.test_schema.my_table1 GROUP BY nationkey",
        height=200,
    )
    execute_button = st.button("Выполнить запрос", type="primary")

if execute_button:
    if not query:
        st.warning("Введите SQL-запрос.")
    else:
        with st.spinner("Выполняется запрос через Ray Serve..."):
            try:
                response = requests.get(BACKEND_URL, params={"query": query}, timeout=30)
                response.raise_for_status()
                data = response.json()
                if data:
                    df = pd.DataFrame(data)
                    st.success(f"Запрос выполнен. Получено строк: {len(df)}")
                    st.dataframe(df, use_container_width=True)
                    if df.select_dtypes(include='number').shape[1] > 0:
                        st.subheader("Статистика по числовым колонкам")
                        st.dataframe(df.describe(), use_container_width=True)
                else:
                    st.info("Запрос вернул пустой результат.")
            except Exception as e:
                st.error(f"Ошибка: {e}")

Хранение визуализаций в Git

Код фронтенда (Streamlit-скрипты или Marimo-ноутбуки) должен храниться в Git-репозитории. Это обеспечивает:

  • Версионирование: Возможность отслеживать изменения, откатываться к предыдущим версиям.
  • Совместную работу: Команда разработчиков может одновременно работать над разными частями дашборда.
  • Автоматизацию развёртывания: CI/CD пайплайны могут автоматически деплоить новую версию дашборда на сервер при пуше в определённую ветку.

Репозиторий может иметь следующую структуру:

.
├── app.py                 # Основной файл Streamlit-приложения
├── pages/                 # Дополнительные страницы (если используются)
├── marimo_notebooks/      # Marimo-ноутбуки (если используются)
├── requirements.txt       # Зависимости
├── .gitignore
└── README.md

Управление состоянием: как построить систему отчётов

В распределённой системе, где множество пользователей одновременно обращаются к дашборду, а сам бэкенд масштабируется на множество реплик, управление состоянием (state management) становится критически важным. Ошибка может привести к тому, что пользователь увидит чужие данные или потеряет свой прогресс в сессии.

Stateless vs. Stateful: Основной выбор

Ray поддерживает оба подхода:

  • Stateless бэкенд (рекомендуемый): Бэкенд не хранит состояние пользователей. Вся сессионная информация (например, результаты фильтрации, текущая страница) хранится во фронтенде или во внешнем хранилище. Любая реплика Ray может обработать любой запрос. Это делает систему простой и отказоустойчивой, но требует, чтобы состояние было “лёгким” (например, хранилось в cookies или `session_state`).
  • Stateful бэкенд: Бэкенд хранит состояние в своей памяти. В этом случае необходимо обеспечить, чтобы все запросы от одного пользователя направлялись на одну и ту же реплику (sticky sessions).

Рекомендуемая архитектура: Stateless бэкенд + Session State во фронтенде

Для большинства BI-дашбордов идеальна следующая схема:

  1. Бэкенд (Ray): Полностью stateless. Он принимает запрос, выполняет вычисления и возвращает результат. Он не помнит, какие запросы делал пользователь ранее.
  2. Фронтенд (Streamlit/Marimo): Хранит состояние сессии локально. В Streamlit для этого используется `st.session_state`. Например, вы можете сохранить в `session_state` фильтры, выбранные пользователем, чтобы они применялись при каждом взаимодействии.
  3. Внешнее хранилище: Для кэширования результатов тяжёлых запросов или для хранения общего состояния (например, результатов обучения модели) используйте Redis или базу данных.

Если требуется Stateful бэкенд (например, кэш в памяти реплики)

Иногда возникает необходимость, чтобы бэкенд хранил какое-то состояние для повышения производительности. Например, каждая реплика может загружать большую модель машинного обучения в свою память. В таком случае используется подход Soft Session Affinity: все запросы от одного пользователя направляются на одну и ту же реплику, используя уникальный ключ (`X-SERVE-SHARD-KEY`).

Сценарий: Долгоживущий отчёт (Report as a Service)

Рассмотрим сценарий, где бизнес-пользователь хочет “заказать” отчёт, который генерируется 10 минут, и вернуться за ним через час. Stateless архитектура здесь не подойдёт, так как бэкенд “забудет” о задаче.

  1. Stateful бэкенд (Ray Actor): Используется долгоживущий Ray Actor (актор), который хранит состояние задачи и её результат.
  2. Хранилище задач: База данных (например, PostgreSQL) используется для хранения информации о задаче (статус, результат). Актор периодически обновляет статус.
  3. Фронтенд: Пользователь запускает задачу, получает её `task_id`, а затем периодически опрашивает эндпоинт `GET /task/{task_id}/status`, который возвращает статус и, при готовности, результат.

Преимущества использования Ray в архитектуре отчётов

  1. Масштабируемость под нагрузку: Ray может автоматически масштабировать количество реплик бэкенда в зависимости от количества запросов. Если вашим дашбордом пользуется 10 или 10 000 человек, Ray адаптируется.
  2. Производительность: Ray оптимизирован для параллельных вычислений и может обрабатывать большие объёмы данных быстрее, чем традиционные инструменты.
  3. Единая кодовая база: Вы можете использовать Ray не только для serving-а данных, но и для их предварительной обработки, обучения моделей и т.д. Это упрощает инфраструктуру.
  4. Отказоустойчивость: Ray автоматически перезапускает упавшие реплики, обеспечивая высокую доступность ваших дашбордов.
  5. Гибкость управления ресурсами: Вы можете точно указать, сколько CPU и GPU нужно выделить для каждого компонента системы.

Заключение

Ray, Streamlit и Marimo образуют мощный тандем для построения современных систем отчётности и аналитики. Ray обеспечивает масштабируемый и производительный бэкенд, способный обрабатывать большие объёмы данных. Streamlit и Marimo предоставляют удобные средства для создания интерактивных и красивых дашбордов, а Git гарантирует контроль версий и простоту развёртывания. Ключом к успешной архитектуре является правильный выбор стратегии управления состоянием: в большинстве случаев подходит stateless бэкенд с хранением состояния во фронтенде, что обеспечивает простоту и отказоустойчивость. Для более сложных сценариев (долгие задачи, кэширование моделей) можно использовать stateful подход с Ray акторами и внешним хранилищем.

Если вы хотите увидеть полный рабочий пример с кодом, архитектурной схемой и инструкцией по развёртыванию, дайте знать — я подготовлю подробный гайд.

ИИгрушки 🤖

Сегодня еще кстати крылатое выражение на уме или цитата, как хотите. «Когда выручка не растет, кровати 🛌 передвинуты, ш..х сменили и все против вас, то на помощь приходят ИИгрушки) 😁☺️😉 (с)

Утиные истории: часть 2. Экосистема DuckDB в 2026 году

В первой части Утиных историй мы детально разбирали, как DuckDB переворачивает принципы локальной и встраиваемой аналитики. Сегодня на календаре 19 апреля 2026 года, и экосистема «утки» развивается с невероятной скоростью. На днях вышел юбилейный, 40-й выпуск информационного бюллетеня от команды MotherDuck.

В этой статье мы разберем самые горячие новинки обновления: релиз DuckLake 1.0, нативную поддержку протокола PostgreSQL, векторный поиск и то, как DuckDB покоряет новые горизонты программирования (от Elixir к Rust).


🦆 DuckLake 1.0: Озерный формат (Lakehouse) готов к продакшену

Главная новость апреля — релиз DuckLake 1.0. Это lakehouse-формат, в котором все метаданные хранятся непосредственно в каталоге базы данных (в PostgreSQL, SQLite или самой DuckDB), а не в разрозненных файлах, как это сделано в Delta Lake или Apache Iceberg.

Что под капотом?

  • Сортированные таблицы и Bucket-партиционирование: Оптимизируют чтение и ускоряют аналитику.
  • Решение проблемы “маленьких файлов”: Мелкие транзакции (где количество строк N≤10 по умолчанию) сохраняются напрямую (inlining) в каталог. Для сброса в объектное хранилище используется команда `CHECKPOINT`.
  • Векторы удаления (Deletion vectors): Поддержка совместимости с Iceberg.
  • Новый тип Variant: Позволяет работать с полуструктурированными данными, автоматически “раскладывая” их на примитивные типы для быстрого выполнения запросов.

Ускорение в цифрах

Отказ от чтения разрозненных файлов метаданных дает феноменальный прирост производительности базовых операций агрегации. Если сравнивать время выполнения запросов до оптимизации (T old) и с использованием чтения исключительного из каталога метаданных DuckLake (T new), то выигрыш в скорости можно выразить формулой:

Speedup =T new / T old

Для запросов вида `COUNT(*)` этот Speedup составляет от 8 до 258 раз! А вызов системной функции `duckdb_views()` ускорился примерно в 70 раз.

Неудивительно, что DuckLake уже входит в топ-10 расширений по количеству скачиваний и поддерживается клиентами Apache DataFusion, Spark, Trino и Pandas. Издательство O’Reilly даже готовит книгу *“DuckLake: The Definitive Guide”*. (Фича доступна в DuckDB v1.5.2).


🐘 MotherDuck теперь говорит на языке Postgres

Чтобы внедрить мощь DuckDB в свою инфраструктуру разработчикам часто приходилось искать специальные драйверы и коннекторы. Это в прошлом!

MotherDuck запустили PostgreSQL wire-protocol endpoint. Теперь вы можете выполнять аналитические SQL-запросы к DuckDB, используя совершенно любой клиент, пулер (pooler) или BI-инструмент, совместимый с Postgres. Устанавливать библиотеки DuckDB на клиент больше не нужно!

Достаточно направить ваш текущий клиент по адресу:

pg.us-east-1-aws.motherduck.com:5432

Авторизация происходит с помощью токена MotherDuck. При этом диалект SQL остается утиным (хотя он в значительной степени и совместим с PostgreSQL). Миграция данных возможна через обычные ETL-утилиты или расширение `pg_duckdb`.


🦀 `quack-rs`: Пишем расширения на чистом Rust

Мощным толчком для развития комьюнити-плагинов стал релиз `quack-rs`. До сих пор написание расширений для DuckDB на Rust требовало создания слоев совместимости (C++ glue) и возни с CMake.

`quack-rs` — это SDK на чистом Rust, который оборачивает *C Extension API* (v1.1+). Инструмент предоставляет безопасные абстракции и устраняет 16 задокументированных проблем с FFI (Foreign Function Interface), предотвращая “тихую” порчу данных через NULL и ошибки “double-free” в callback-функциях агрегации.

Для старта нового расширения достаточно вызвать функцию:

generate_scaffold();

Она сгенерирует все 11 файлов, необходимых для подачи плагина в репозиторий сообщества. Теперь безопасность памяти Rust и скорость DuckDB идут рука об руку.


🛠️ Важные новости комьюнити и новые инструменты (Нажмите, чтобы развернуть)

1. Lance Extension и векторный поиск

Открытый колоночный формат Lance, оптимизированный под ML и векторный поиск, теперь доступен и в DuckDB! Hao Ding реализовал поддержку чтения и записи таблиц Lance.

Писать данные можно так:

COPY (...) TO 'path/dataset.lance' (FORMAT lance, MODE 'overwrite');

Для поиска доступны функции: `lance_vector_search()`, `lance_fts()` и `lance_hybrid_search()`.

2. Dux: Распределенные DataFrame для Elixir

Появилась библиотека `dux` — lazy-by-default (ленивые по умолчанию) датафреймы для Elixir поверх DuckDB. Конвейеры данных аккумулируются в AST структуре `%Dux{}` и компилируются в SQL CTE. Заявлено, что на тестах ($10$ млн строк, Apple M4 Max) Dux обгоняет Polars (Explorer) до 2.5 раз на операциях фильтрации.

3. eBPF трассировка с ИИ (`systing 1.0`)

Инструмент для трассировки ядра Linux `systing` (написанный Josef Bacik) перешел с сохранения логов Perfetto на прямую запись в DuckDB. А интеграция с Claude Code MCP (Model Context Protocol) позволяет ИИ динамически анализировать эти базы данных DuckDB в реальном времени.

4. Jupyter и DuckDB Kernel на Go

Создано полноценное Go-ядро DuckDB для Jupyter, которое напрямую отправляет поток данных (Arrow IPC) во встроенный WASM-просмотрщик `hugr-perspective-viewer`. На панели также агрегируются метрики без написания SQL: `approx_unique`, `avg`, `min`, `max`, `count`.

5. Web-framework, Neovim и игры

  • `neovim-web`: Фреймворк для создания статических сайтов с горячими клавишами Vim. Фишка — встроенная консоль DuckDB-Wasm (команда `:sql`) прямо в браузере.
  • `connections.duckdb`: Аналог игры “Connections” от NYT, целиком реализованный на SQL макросах.

💻 Бенчмарки: Большие данные на самом дешевом MacBook Neo

Способен ли базовый ноутбук переваривать серьезную аналитику? Gábor проверил работу DuckDB на новом MacBook Neo с процессором Apple A18 Pro.

Бенчмарк Параметры Результат (медиана)
ClickBench 100M строк, лимит RAM: 5GB < 1 секунды (cold run)
TPC-DS SF100 1.63 секунды на запрос
TPC-DS SF300 79 минут (высокий disk spill)

Даже при 5 гигабайтах оперативной памяти DuckDB демонстрирует субсекундные ответы, эффективно утилизируя NVMe-память, когда RAM исчерпан (disk spill).


🎓 Внедрение в Академическую Среду

Стоит отдельно отметить профессора Dr. Torsten Grust из Тюбингенского университета (Германия). Его исследовательская группа, стоящая на стыке баз данных и технологий языков программирования, недавно запустила открытый курс DiDi (*Design and Implementation of DuckDB Internals*).

Курс использует DuckDB для обучения студентов архитектуре СУБД: от управления памятью и векторизованного исполнения до оптимизации запросов (включает около 50 рабочих примеров кода).


🗓 Ближайшие Мероприятия

  • 21 апреля 2026 (Онлайн): Стрим MotherDuck Now Speaks Postgres: Fast Analytics Without Changing Your Stack. Демонстрация нового PG wire-protocol.
  • 30 апреля 2026 (Сан-Франциско): DuckDB + MotherDuck Meetup. Разговоры про DuckLake 1.0 и распределенный DuckDB (проект OpenDuck).

Экосистема DuckDB перестала быть просто *“SQLite для аналитики”*. С релизом DuckLake, нативной интеграцией протокола Postgres и появлением SDK для Rust, “утка” окончательно закрепилась как основополагающий инструмент в стеке современных данных.

Earlier Ctrl + ↓