<?xml version="1.0" encoding="utf-8"?> 
<rss version="2.0"
  xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
  xmlns:atom="http://www.w3.org/2005/Atom">

<channel>

<title>Yuriy Gavrilov: posts tagged datafusion</title>
<link>https://gavrilov.info/tags/datafusion/</link>
<description>Welcome to my personal place for love, peace and happiness 🤖 Yuiry Gavrilov</description>
<author></author>
<language>en</language>
<generator>Aegea 11.4 (v4171e)</generator>

<itunes:owner>
<itunes:name></itunes:name>
<itunes:email>yvgavrilov@gmail.com</itunes:email>
</itunes:owner>
<itunes:subtitle>Welcome to my personal place for love, peace and happiness 🤖 Yuiry Gavrilov</itunes:subtitle>
<itunes:image href="https://gavrilov.info/pictures/userpic/userpic-square@2x.jpg?1643451008" />
<itunes:explicit>no</itunes:explicit>

<item>
<title>Архитектура Client Spooling: Как быстро выгружать гигантские датасеты в Trino и Apache DataFusion</title>
<guid isPermaLink="false">327</guid>
<link>https://gavrilov.info/all/arhitektura-client-spooling-kak-bystro-vygruzhat-gigantskie-data/</link>
<pubDate>Sun, 12 Apr 2026 19:11:05 +0300</pubDate>
<author></author>
<comments>https://gavrilov.info/all/arhitektura-client-spooling-kak-bystro-vygruzhat-gigantskie-data/</comments>
<description>
&lt;p&gt;Работа с Big Data часто упирается в классическое “узкое горлышко”: кластер может обработать терабайты данных за секунды, но передача результатов (Result Set) обратно на сторону клиента (например, в Jupyter или скрипт) занимает часы. На дворе апрель 2026 года, и современные аналитические движки предлагают эффективные методы обхода этой проблемы — концепцию &lt;b&gt;Spooling&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;Немного душноты:&lt;/p&gt;
&lt;p&gt;Архитектура Client Spooling в Trino создавалась с параноидальным акцентом на безопасность, в S3 выкидываются куски сырых, возможно, чувствительных данных.&lt;/p&gt;
&lt;p&gt;Когда Trino решает сбросить данные в объектное хранилище, он всегда шифрует их на лету.&lt;br /&gt;
Для этого используется механизм S3 SSE-C (Server-Side Encryption with Customer-provided keys). Trino генерирует уникальный случайный AES-ключ для каждого запроса, отправляет его в MinIO вместе с данными, а клиенту (вашему Jupyter) отдает ссылку + этот же ключ для расшифровки.&lt;br /&gt;
Если мы используем локальный MinIO по адресу &lt;a href="http://minio:9000"&gt;http://minio:9000&lt;/a&gt; (без SSL/TLS), сервер MinIO видит, что ему пытаются передать секретный пароль (SSE-C ключ) по открытому незащищенному HTTP-каналу.&lt;br /&gt;
MinIO (как и настоящий AWS S3) строго запрещает это по спецификации. Он возвращает HTTP 400 Bad Request с ошибкой: “Requests specifying Server Side Encryption... must be made over a secure connection”. Поэтому тестировать лучше на реальном s3. И еще&lt;/p&gt;
&lt;p&gt;Мгновенное удаление (Сборка мусора)&lt;/p&gt;
&lt;p&gt;Главное правило Client Spooling: Trino удаляет файлы сразу же, как только они были прочитаны клиентом.&lt;br /&gt;
Как только ваш Python-скрипт или Jupyter получает ссылку на файл, скачивает его и отправляет координатору Trino HTTP-сигнал (ACK), что кусок получен, координатор дает команду немедленно удалить этот объект из S3.&lt;br /&gt;
Если запрос отменен или упал с ошибкой, Trino тоже моментально зачищает за собой fs.location. Вы просто не успеете их там увидеть.&lt;/p&gt;
&lt;p&gt;Данных слишком мало (Thresholds)&lt;/p&gt;
&lt;p&gt;Писать 10 строк в S3, генерировать для них Pre-signed URLs и отдавать клиенту — это дольше, чем просто плюнуть эти 10 строк текстом через координатор. Trino использует эвристику: если Result Set маленький, он отдается “инлайн” (внутри JSON-ответа самого координатора), и S3 не задействуется.&lt;/p&gt;
&lt;p&gt;В этой статье мы разберем, как передавать результаты запросов через промежуточное S3-хранилище, на примере движков Trino и Apache DataFusion.&lt;/p&gt;
&lt;h4&gt;Физика проблемы и математика Spooling&lt;/h4&gt;
&lt;p&gt;В классической архитектуре все воркеры кластера отправляют вычисленные строки на главный узел (Coordinator), а тот уже отдает их по одному каналу клиенту.&lt;/p&gt;
&lt;p&gt;Если D — это объем результирующей выборки, а B c — пропускная способность сети координатора, то время выгрузки данных клиенту без спулинга равно:&lt;/p&gt;
&lt;p&gt;T classic = B / Dc&lt;/p&gt;
&lt;p&gt;В режиме &lt;b&gt;Spooling&lt;/b&gt; координатор не гоняет данные через себя. Воркеры напрямую, параллельно пишут куски результата в дешевое объектное хранилище (S3/MinIO). Клиент получает лишь ссылки на эти файлы и скачивает их напрямую. Если у нас N файлов в S3, доступных для многопоточного скачивания с пропускной способностью клиента B client: T spooling ≈ min(N×B s3,B client)D&lt;/p&gt;
&lt;p&gt;Это позволяет ускорить выгрузку в десятки раз, так как $B_{client}$ и распределенный $B_{s3}$ обычно значительно больше ограничений одного координатора.&lt;/p&gt;
&lt;hr /&gt;
&lt;h4&gt;Подготовка минимальной инфраструктуры&lt;/h4&gt;
&lt;p&gt;Для демонстрации двух подходов мы убрали из нашего кластера все тяжелые клиентские среды (Jupyter, Spark) и оставили только “голое” ядро: хранилище S3, REST-каталог и SQL-движок.&lt;/p&gt;
&lt;p&gt;&lt;summary&gt;&lt;b&gt;минимальный&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;docker-compose.yml&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;/b&gt;&lt;/summary&gt;&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;version: '3.8'

services:
  minio:
    image: minio/minio:latest
    ports:
      - &amp;quot;19000:9000&amp;quot;
      - &amp;quot;19001:9001&amp;quot;
    environment:
      MINIO_ROOT_USER: &amp;quot;minio-root-user&amp;quot;
      MINIO_ROOT_PASSWORD: &amp;quot;minio-root-password&amp;quot;
    command: server /data --console-address &amp;quot;:9001&amp;quot;

  minio-setup:
    image: minio/mc:latest
    depends_on:
      - minio
    entrypoint: &amp;gt;
      /bin/sh -c &amp;quot;
      sleep 5;
      mc alias set myminio http://minio:9000 minio-root-user minio-root-password;
      mc mb myminio/warehouse || true;
      &amp;quot;

  lakekeeper:
    image: dalongrong/lakekeeper:latest
    ports:
      - &amp;quot;8181:8181&amp;quot;
    environment:
      - S3_ENDPOINT=http://minio:9000
      - S3_REGION=us-east-1
      - S3_ACCESS_KEY_ID=minio-root-user
      - S3_SECRET_ACCESS_KEY=minio-root-password
    depends_on:
      - minio-setup

  trino:
    image: trinodb/trino:latest
    ports:
      - &amp;quot;8080:8080&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;summary&gt;&lt;b&gt;Шаг 1. Настройка каталога и генерация данных (Trino)&lt;/b&gt;&lt;/summary&gt;&lt;br /&gt;
&lt;br&gt;&lt;br /&gt;
Сначала мы генерируем данные в Trino. Запрос&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;CREATE CATALOG&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;использует динамическое подключение к Lakekeeper REST API. Скрипт записывает файлы в формате Parquet в MinIO:&lt;/p&gt;
&lt;p&gt;&lt;b&gt;config.properties&lt;/b&gt;&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;protocol.spooling.enabled=true
# 256-битный ключ в формате base64. Вы можете сгенерировать свой с помощью команды `openssl rand -base64 32`
protocol.spooling.shared-secret-key=jxTKysfCBuMZtFqUf8UJDQ1w9ez8rynEJsJqgJf66u0=

catalog.management=dynamic&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;b&gt;spooling-manager.properties&lt;/b&gt;&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;spooling-manager.name=filesystem
# Включаем чтение/запись в S3 для Spooling
fs.s3.enabled=true
# Путь внутри MinIO (указываем через s3://)
fs.location=s3://warehouse/client-spooling/

# Системные настройки S3 (MinIO)
s3.endpoint=http://minio:9000
s3.region=us-east-1
s3.aws-access-key=minio-root-user
s3.aws-secret-key=minio-root-password
s3.path-style-access=true&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;-- 1. Подключение каталога Iceberg&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;CREATE CATALOG test_warehouse USING iceberg
WITH (
    &amp;quot;iceberg.catalog.type&amp;quot; = 'rest',
    &amp;quot;iceberg.rest-catalog.uri&amp;quot; = 'http://lakekeeper:8181/catalog/',
    &amp;quot;iceberg.rest-catalog.warehouse&amp;quot; = '00000000-0000-0000-0000-000000000000/test_warehouse',
    &amp;quot;iceberg.rest-catalog.security&amp;quot; = 'OAUTH2',
    &amp;quot;iceberg.rest-catalog.nested-namespace-enabled&amp;quot; = 'true',
    &amp;quot;iceberg.rest-catalog.vended-credentials-enabled&amp;quot; = 'true',
    &amp;quot;fs.native-s3.enabled&amp;quot; = 'true',
    &amp;quot;s3.region&amp;quot; = 'us-east-1',
    &amp;quot;s3.path-style-access&amp;quot; = 'true',
    &amp;quot;s3.endpoint&amp;quot; = 'http://minio:9000'
);&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;-- 2. Создание структуры&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;CREATE SCHEMA test_warehouse.test_schema;

CREATE TABLE test_warehouse.test_schema.my_table (
    id BIGINT,
    data VARCHAR
) WITH (format = 'PARQUET');&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;-- 3. Запись данных&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;INSERT INTO test_warehouse.test_schema.my_table VALUES (1, 'hello'), (2, 'world');&lt;/code&gt;&lt;/pre&gt;&lt;hr /&gt;
&lt;p&gt;Если написать Select – должно быть как-то так&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/Snimok-ekrana-2026-04-12-v-18.25.52.png" width="490" height="284" alt="" /&gt;
&lt;/div&gt;
&lt;h4&gt;Аналог Spooling в Apache DataFusion (Через экспорт)&lt;/h4&gt;
&lt;p&gt;Trino поддерживает протокол *Client Spooling* “из коробки” — когда Python-клиент запрашивает огромный `SELECT`, Trino сам незаметно пишет куски в S3 и отдает клиенту готовые ссылки.&lt;/p&gt;
&lt;p&gt;В &lt;b&gt;Apache DataFusion&lt;/b&gt; (который часто работает как локальный движок `datafusion-cli` или встраиваемая библиотка поверх S3) применяется более прозрачный паттерн делегирования (Explicit Spooling). Мы вручную инструктируем движок сохранить результаты агрегации в распределенное хранилище, чтобы позже забрать их в удобном формате — например, упаковав их в `JSON` и сжав алгоритмом `ZSTD`.&lt;/p&gt;
&lt;h5&gt;1. Подключение к S3 и маппинг исходной таблицы&lt;/h5&gt;
&lt;p&gt;Запускаем `datafusion-cli`, передав доступы как переменные среды (для предотвращения ошибок парсинга опций):&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;AWS_ACCESS_KEY_ID=&amp;quot;minio-root-user&amp;quot; \
AWS_SECRET_ACCESS_KEY=&amp;quot;minio-root-password&amp;quot; \
AWS_ENDPOINT=&amp;quot;http://localhost:19000&amp;quot; \
AWS_REGION=&amp;quot;us-east-1&amp;quot; \
AWS_ALLOW_HTTP=&amp;quot;true&amp;quot; \
datafusion-cli&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Внутри консоли подключаем директорию с Parquet-файлами, сгенерированными Trino:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;CREATE EXTERNAL TABLE my_parquet_data 
STORED AS PARQUET 
LOCATION 's3://warehouse/019d81a3-c2d6-7ed2-ab15-070becf62582/my_table-13e4b91a2b4e47d98f312b1384263880/data/';&lt;/code&gt;&lt;/pre&gt;&lt;h5&gt;2. Массовая конвертация и выгрузка (DataFusion COPY)&lt;/h5&gt;
&lt;p&gt;Вместо того чтобы тянуть миллионы строк на локальный терминал, мы просим DataFusion выполнить преобразование и записать итог запроса обратно в MinIO.&lt;/p&gt;
&lt;p&gt;Мы выбираем построчный JSON с экстремальным сжатием:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;COPY (
    -- Тут может быть любая сложная агрегация:
    -- SELECT id, count(data) FROM my_parquet_data GROUP BY id
    SELECT * FROM my_parquet_data
) 
TO 's3://warehouse/019d81a3-c2d6-7ed2-ab15-070becf62582/my_table-13e4b91a2b4e47d98f312b1384263880/json_export/' 
STORED AS JSON
OPTIONS (
    'format.compression' 'zstd'
);&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;b&gt;Результат:&lt;/b&gt;&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;+-------+
| count |
+-------+
| 2     |
+-------+
1 row(s) fetched. 
Elapsed 0.270 seconds.&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;За миллисекунды (0.270 sec) DataFusion прочитал партиции, трансформировал бинарные столбцы в текст и сжал его.&lt;/p&gt;
&lt;h4&gt;В чем преимущество подхода DataFusion?&lt;/h4&gt;
&lt;p&gt;Описанный паттерн выполнения команды `COPY TO` с сохранением `.json.zst` в MinIO полностью воспроизводит механику Spooling:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Отсутствие OOM (Out Of Memory):&lt;/b&gt; Клиент получает только метаданные `count`, а не гигабайты сырых данных в оперативную память.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Параллелизм:&lt;/b&gt; Если исходных файлов много, DataFusion будет писать множество потоков `part-0.json.zst`, `part-1.json.zst` в бакет параллельно.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Удаленное потребление:&lt;/b&gt; Вы можете запустить легкий Python-скрипт (Pandas) на дешевой машине, который просто прочитает эти сжатые легковесные JSON объекты напрямую из MinIO, минуя дорогостоящие вычислительные кластеры.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Еще немного про  Fault-Tolerant Execution (FTE), нужно провести важную границу между &lt;b&gt;архитектурой Trino&lt;/b&gt; (готовый распределенный кластер) и &lt;b&gt;архитектурой DataFusion&lt;/b&gt; (ядро/библиотека выполнения запросов).&lt;/p&gt;
&lt;p&gt;В самом “голом” ядре DataFusion (которое вы запускаете в `datafusion-cli` или в Jupyter) &lt;b&gt;нет встроенного механизма Task Retries&lt;/b&gt;, потому что процессы выполняются на одной машине в рамках одного приложения. Если сервер падает — запрос прерывается.&lt;/p&gt;
&lt;p&gt;Однако, в экосистеме DataFusion есть механизмы отказоустойчивости, которые делятся на два уровня: &lt;b&gt;локальный (Spilling)&lt;/b&gt; и &lt;b&gt;распределенный (Apache Ballista / Ray)&lt;/b&gt;.&lt;/p&gt;
&lt;hr /&gt;
&lt;h4&gt;1. Локальная отказоустойчивость (защита от OOM)&lt;/h4&gt;
&lt;p&gt;В Trino частой причиной падения задач является нехватка памяти (Out of Memory). В DataFusion реализован мощный механизм управления памятью.&lt;/p&gt;
&lt;p&gt;Если DataFusion понимает, что оперативной памяти для агрегации или JOIN’а не хватает, он не “роняет” задачу, а начинает сбрасывать промежуточные данные на диск (&lt;b&gt;Spill to Disk&lt;/b&gt;).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Это настраивается через конфигурацию `datafusion.execution.disk_manager`.&lt;/li&gt;
&lt;li&gt;Это аналог локального `spill-enabled = true` в Trino. Запрос замедлится, но выполнится до конца, не упав с ошибкой.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;2. Распределенная отказоустойчивость (Аналог Trino FTE)&lt;/h4&gt;
&lt;p&gt;Trino использует архитектуру &lt;b&gt;Fault-Tolerant Execution (FTE)&lt;/b&gt;, при которой промежуточные результаты (Shuffle Exchange) пишутся в S3, а упавшие воркеры заменяются, и их задачи (Tasks) перезапускаются координатором.&lt;/p&gt;
&lt;p&gt;В мире DataFusion эту задачу решает не само ядро, а &lt;b&gt;распределенные планировщики&lt;/b&gt;, построенные поверх него:&lt;/p&gt;
&lt;h5&gt;А. Apache Ballista (Официальный распределенный DataFusion)&lt;/h5&gt;
&lt;p&gt;Ballista — это надстройка над DataFusion, превращающая его в полноценный кластер (с Coordinator и Executors), архитектурно очень похожая на Apache Spark и Trino.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Task Retries:&lt;/b&gt; Если один из Executor’ов теряется из-за сбоя сети или железа, Ballista Coordinator замечает это и &lt;b&gt;переназначает задачу (Task) другому воркеру&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Shuffle Spilling:&lt;/b&gt; Промежуточные данные между стадиями (Stages) записываются во временные файлы. Следовательно, если упала только последняя стадия, кластеру не нужно пересчитывать весь запрос с нуля — он прочитает промежуточные Shuffle-файлы и повторит только упавший кусок.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;Б. DataFusion on Ray (datafusion-ray)&lt;/h5&gt;
&lt;p&gt;Сейчас огромную популярность набирает запуск DataFusion поверх кластера &lt;b&gt;Ray&lt;/b&gt;.&lt;br /&gt;
Ray — это супер-устойчивый распределенный фреймворк. Интеграция `datafusion-ray` позволяет разбить SQL-запрос на граф задач прямо в Ray.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;За отказоустойчивость, Retry-логику и восстановление упавших узлов (Actor/Task) здесь отвечает сам Ray, который делает это на уровне индустриального стандарта.&lt;/li&gt;
&lt;li&gt;Это максимально близко к концепции отказоустойчивого кластера.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Резюме: Как получить “Trino-like” Fault Tolerance в DataFusion?&lt;/h4&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Если вы используете &lt;b&gt;локальный DataFusion&lt;/b&gt; (в Python или CLI): Отказоустойчивости уровня узлов нет, но есть защита от падений по памяти (Spill to Disk). Если упадет процесс — нужно перезапускать запрос руками.&lt;/li&gt;
&lt;li&gt;Если вам нужен настоящий &lt;b&gt;Task Repeat / Fault Tolerance&lt;/b&gt; на сотнях серверов, где падение серверов — норма: вы используете движок DataFusion вместе с кластерным менеджером &lt;b&gt;Apache Ballista&lt;/b&gt; или &lt;b&gt;Ray&lt;/b&gt;, которые прозрачно обеспечат перезапуск задач (Retries) и сохранение промежуточных состояний (Shuffle), полностью повторяя логику Trino FTE.&lt;/li&gt;
&lt;/ol&gt;
</description>
</item>

<item>
<title>Искусство скорости: Руководство по оптимизации для аналитики в Data Lakehouse с DuckDB</title>
<guid isPermaLink="false">279</guid>
<link>https://gavrilov.info/all/iskusstvo-skorosti-rukovodstvo-po-optimizacii-dlya-analitiki-v-d/</link>
<pubDate>Tue, 09 Sep 2025 01:48:12 +0300</pubDate>
<author></author>
<comments>https://gavrilov.info/all/iskusstvo-skorosti-rukovodstvo-po-optimizacii-dlya-analitiki-v-d/</comments>
<enclosure url="https://gavrilov.info/video/-5436782684090959843.mp4" type="video/mp4" length="2206521" />
<description>
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/Snimok-ekrana-2025-09-09-v-01.35.35.png" width="1174" height="108" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;DuckDB завоевал огромную популярность как “SQLite для аналитики”. Это невероятно быстрый, встраиваемый, колоночный движок, который не требует отдельного сервера. Однако его мощь по-настоящему раскрывается, когда он получает доступ к данным эффективно. Просто натравить DuckDB на петабайтный дата-лейк без подготовки — это рецепт для медленных запросов и высоких затрат.&lt;/p&gt;
&lt;p&gt;Как же построить мост между огромным хранилищем данных и молниеносной интерактивной аналитикой, которую обещает DuckDB?&lt;/p&gt;
&lt;div class="e2-text-video"&gt;
&lt;video src="https://gavrilov.info/video/-5436782684090959843.mp4#t=0.001" width="640" height="480" controls alt="" /&gt;

&lt;/div&gt;
&lt;p&gt;В этой статье рассмотрим три фундаментальных архитектурных подхода к организации доступа к данным для DuckDB. Но прежде чем мы погрузимся в то, как *читать* данные, давайте поговорим о том, как их *готовить*.&lt;/p&gt;
&lt;h4&gt;Большая картина: Подготовка данных с помощью Trino&lt;/h4&gt;
&lt;p&gt;Данные в вашем Lakehouse не появляются из ниоткуда. Они поступают из операционных баз данных, потоков событий (Kafka), логов и десятков других источников. Прежде чем DuckDB сможет их эффективно запросить, эти данные нужно собрать, очистить, трансформировать и, что самое важное, организовать в надежный и производительный формат.&lt;/p&gt;
&lt;p&gt;Здесь на сцену выходит &lt;b&gt;Trino&lt;/b&gt; (ранее известный как PrestoSQL).&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Что такое Trino?&lt;/b&gt; Это мощный распределенный SQL-движок, созданный для выполнения запросов к гетерогенным источникам данных. Его суперсила — способность “на лету” объединять данные из PostgreSQL, Kafka, Hive, MySQL и многих других систем.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Роль Trino в Lakehouse:&lt;/b&gt; В современной архитектуре Trino часто выступает в роли “фабрики данных”. Он выполняет тяжелую работу по &lt;b&gt;ETL/ELT&lt;/b&gt; (Extract, Transform, Load), подготавливая данные для аналитических инструментов вроде DuckDB.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Типичный сценарий использования:&lt;/b&gt;&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Источники:&lt;/b&gt; У вас есть события о прослушивании треков в Kafka, а информация о пользователях — в базе данных PostgreSQL.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Задача:&lt;/b&gt; Создать единую, денормализованную таблицу Iceberg для аналитики.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Решение с Trino:&lt;/b&gt; Вы настраиваете в Trino коннекторы к Kafka и PostgreSQL. Затем вы запускаете периодический SQL-запрос, который читает данные из обоих источников, объединяет их и записывает результат в новую или существующую таблицу Iceberg.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;-- Этот запрос выполняется в Trino, а не в DuckDB!
    INSERT INTO iceberg_catalog.analytics.daily_user_activity
    SELECT
        u.user_id,
        u.country,
        e.event_timestamp,
        e.track_id,
        e.duration_ms
    FROM
        postgres_catalog.public.users u
    JOIN
        kafka_catalog.raw_data.listen_events e ON u.user_id = e.user_id
    WHERE
        e.event_date = CURRENT_DATE;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Как отмечается в одном из руководств, именно такой `INSERT INTO ... SELECT ...` является типичным способом перемещения данных в Iceberg с помощью Trino.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Итог:&lt;/b&gt; Trino работает “глубоко в машинном отделении” вашего Lakehouse. Он берет на себя тяжелые, распределенные задачи по преобразованию данных, а DuckDB получает на вход уже чистые, структурированные и оптимизированные для чтения таблицы Iceberg.&lt;/p&gt;
&lt;p&gt;Теперь, когда данные готовы, давайте рассмотрим, как их лучше всего потреблять.&lt;/p&gt;
&lt;h4&gt;Подход 1: Табличные форматы (Iceberg) — Читайте только то, что нужно&lt;/h4&gt;
&lt;p&gt;Это самый продвинутый и рекомендуемый подход для серьезной аналитики, особенно в serverless-архитектуре.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Как это работает:&lt;/b&gt; Вместо того чтобы работать с “россыпью” файлов Parquet, вы работаете с логической таблицей, управляемой Apache Iceberg. Расширение `iceberg` в DuckDB использует метаданные Iceberg для интеллектуального отсечения ненужных файлов (partition pruning) и блоков данных (predicate pushdown), читая с диска минимально необходимый объем информации.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Архитектура:&lt;/b&gt; `Данные на S3 -&gt; Trino (ETL) -&gt; Таблица Iceberg -&gt; DuckDB (Аналитика)`&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;Назначение и сценарии использования:&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Serverless-аналитика:&lt;/b&gt; Основной кейс. AWS Lambda или Google Cloud Function, оснащенная DuckDB, выполняет SQL-запрос к озеру данных. Благодаря Iceberg, функция читает всего несколько мегабайт вместо гигабайт, что делает ее выполнение быстрым (&lt;1 сек) и дешевым.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Локальная разработка и BI:&lt;/b&gt; Аналитик данных или инженер открывает Jupyter Notebook на своем ноутбуке. С помощью DuckDB он подключается напрямую к производственному Lakehouse и выполняет исследовательский анализ, не создавая копий данных и не перегружая кластеры.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Встраиваемая аналитика:&lt;/b&gt; Backend-сервис на Python или Node.js, которому нужно быстро отвечать на аналитические вопросы (например, “показать статистику пользователя за последний месяц”). Он использует DuckDB для прямого запроса к Lakehouse без обращения к промежуточной базе данных.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Подход 2: RPC-стриминг (Apache Arrow Flight) — Прямой канал к данным&lt;/h4&gt;
&lt;p&gt;Иногда вам не нужна вся мощь Iceberg, а нужно просто эффективно выполнить запрос на удаленном экземпляре DuckDB и получить результат.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Как это работает:&lt;/b&gt; Вы запускаете сервер, который инкапсулирует DuckDB. Клиент и сервер общаются по протоколу Arrow Flight — высокопроизводительному фреймворку для стриминга колоночных данных в формате Apache Arrow без затрат на сериализацию.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Архитектура:&lt;/b&gt; `Клиент -&gt; Arrow Flight RPC -&gt; Сервер с DuckDB -&gt; Данные (любой источник)`&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;Назначение и сценарии использования:&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Интерактивные дашборды:&lt;/b&gt; Веб-интерфейс (React, Vue) должен строить графики в реальном времени. Он отправляет SQL-запросы на Flight-сервер и получает данные для отрисовки практически мгновенно, без “тяжести” HTTP/JSON.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;API-шлюз для данных:&lt;/b&gt; Централизация доступа к данным для множества внутренних микросервисов. Вместо того чтобы каждый сервис имел свои креды и логику подключения к БД, они обращаются к единому, стабильному Flight API.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Кросс-языковое взаимодействие:&lt;/b&gt; Сервис на Java должен получить результаты вычислений из BI-системы, построенной на Python и DuckDB. Arrow Flight обеспечивает эффективный и стандартизированный мост между ними.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Подход 3: “API поверх данных” (ROAPI &amp; DataFusion) — Декларативная альтернатива&lt;/h4&gt;
&lt;p&gt;Что, если вам не нужна вся гибкость SQL, а нужен стандартный REST или GraphQL API поверх ваших данных без строчки кода? Здесь на сцену выходит &lt;b&gt;ROAPI&lt;/b&gt;.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/image-212.png" width="1612" height="1435" alt="" /&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Как это работает:&lt;/b&gt; ROAPI — это инструмент, который автоматически создает API, читая конфигурационный YAML-файл, где вы описываете ваши данные (Parquet, CSV и т.д.). Под капотом он использует Apache Arrow DataFusion, движок запросов, написанный на Rust, являющийся идейным братом DuckDB.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Архитектура:&lt;/b&gt; `Клиент (HTTP/GraphQL) -&gt; ROAPI Server -&gt; Данные (файлы)`&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;Назначение и сценарии использования:&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Быстрое прототипирование:&lt;/b&gt; Вам нужно за 5 минут предоставить команде фронтенда API для нового набора данных. Вы пишете 10 строк в YAML, запускаете ROAPI — и API готов.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Простые микросервисы данных:&lt;/b&gt; Сервис, единственная задача которого — раздавать данные из файла с поддержкой фильтрации и пагинации. ROAPI делает это из коробки, избавляя вас от написания рутинного кода на FastAPI или Express.js.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Дата-фиды для внешних систем:&lt;/b&gt; Предоставление стандартизированного API для партнерской системы, которая умеет работать с REST, но не умеет читать Parquet.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;и еще немного про DuckDB&lt;/h4&gt;
&lt;h5&gt;1. Читайте меньше данных (Золотое правило)&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Используйте Iceberg:&lt;/b&gt; Это лучший способ.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Проекция колонок (`SELECT col1, col2...`):&lt;/b&gt; &lt;b&gt;Никогда не используйте `SELECT *`&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Проталкивание предикатов (`WHERE`):&lt;/b&gt; Пишите максимально конкретные фильтры. DuckDB автоматически проталкивает их в сканеры Parquet и Iceberg. Используйте `EXPLAIN` для проверки того, что фильтры применяются на этапе сканирования.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;2. Оптимизация SQL-запросов&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Материализация промежуточных результатов:&lt;/b&gt; Если вы делаете несколько агрегаций над одним и тем же отфильтрованным срезом, сохраните его во временную таблицу с помощью `CREATE TEMP TABLE ... AS`.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Используйте `COPY` для массовой загрузки:&lt;/b&gt; При загрузке данных в DuckDB `COPY` на порядки быстрее, чем `INSERT`.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Предварительная агрегация:&lt;/b&gt; Для сверхбольших данных создавайте “витрины” с помощью Trino (см. выше) или DuckDB, а запросы стройте уже по ним.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;3. Настройка окружения DuckDB&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Управление памятью:&lt;/b&gt; `SET memory_limit = ‘1GB’;` — обязательная настройка в Lambda и контейнерах.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Параллелизм:&lt;/b&gt; `SET threads = 4;` — адаптируйте количество потоков под vCPU вашего окружения.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Настройка `httpfs` для S3:&lt;/b&gt; Настройте регион (`s3_region`), креды и включите кэширование метаданных, чтобы не перечитывать их при каждом запуске. ( Это комьюнити дополнение -&lt;a href="https://duckdb.org/community_extensions/extensions/cache_httpfs.html"&gt;cache_httpfs&lt;/a&gt;, см. ниже “Проблема Шторм” )&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Еще вот тут можно почитать: &lt;a href="https://duckdb.org/docs/stable/guides/performance/how_to_tune_workloads"&gt;https://duckdb.org/docs/stable/guides/performance/how_to_tune_workloads&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;Заключение: Какой подход выбрать?&lt;/h4&gt;
&lt;p&gt;Выбор архитектуры зависит от вашей задачи. Каждая из них занимает свою нишу в стеке современной инженерии данных.&lt;/p&gt;
&lt;table cellpadding="0" cellspacing="0" border="0" class="e2-text-table"&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;Подход&lt;/td&gt;
&lt;td style="text-align: center"&gt;Ключевая технология&lt;/td&gt;
&lt;td style="text-align: center"&gt;Когда использовать&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Табличный формат&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Trino (Подготовка) + DuckDB/Iceberg (Потребление)&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Стандарт для Lakehouse.&lt;/b&gt; Нужна строгая структура, надежность и максимальная производительность для аналитических SQL-запросов от различных инструментов.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;RPC-стриминг&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;DuckDB + Arrow Flight&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;Нужен &lt;b&gt;быстрый интерактивный SQL-доступ&lt;/b&gt; к удаленному экземпляру DuckDB, например, для дашборда или кастомного клиента.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;API поверх данных&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;ROAPI + DataFusion&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;Нужно &lt;b&gt;быстро и без кода&lt;/b&gt; поднять стандартный `REST`/`GraphQL` API поверх наборов данных для прототипирования или простых микросервисов.&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;hr /&gt;
&lt;h4&gt;Проблема Шторм из GET-запросов к S3&lt;/h4&gt;
&lt;p&gt;Давайте представим, что вы выполняете запрос к таблице Iceberg или просто к набору из 1000 файлов Parquet на S3:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;SELECT count(*)
FROM read_parquet('s3://my-bucket/data/*.parquet')
WHERE event_type = 'click';&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Чтобы выполнить этот запрос с максимальной эффективностью (с “проталкиванием предиката”), DuckDB должен сделать следующее, *прежде чем* читать основные данные:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Получить список всех 1000 файлов.&lt;/li&gt;
&lt;li&gt;Для &lt;b&gt;каждого&lt;/b&gt; из 1000 файлов прочитать его &lt;b&gt;метаданные (футер)&lt;/b&gt;. Футер Parquet-файла — это небольшой блок в конце файла, содержащий схему и, что самое важное, статистику по колонкам (min/max значения).&lt;/li&gt;
&lt;li&gt;Проанализировав футер, DuckDB понимает, может ли в этом файле вообще содержаться `event_type = ‘click’`. Если статистика говорит, что в файле есть только типы `’view’` и `’purchase’`, утка его пропустит.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Проблема в том, что для чтения футера каждого файла DuckDB должен отправить отдельный HTTP `GET` запрос с указанием диапазона байт (range request) к S3. То есть, один SQL-запрос порождает &lt;b&gt;1000+ мелких HTTP-запросов&lt;/b&gt;. Это может быть медленно и может быть дорого, так как в S3 вы платите за каждый `GET` запрос.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Кэширование метаданных решает именно эту проблему:&lt;/b&gt; оно сохраняет результаты этих мелких запросов на локальный диск, чтобы при повторном обращении к тем же файлам DuckDB брал их из локального кэша, а не летел снова в S3.&lt;/p&gt;
&lt;h4&gt;Решение: Комьюнити-расширение `cache_httpfs`&lt;/h4&gt;
&lt;p&gt;Для реализации постоянного, дискового кэширования в DuckDB используется специальное комьюнити-расширение `cache_httpfs`. Оно работает как “обертка” над стандартным `httpfs`.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Основная идея:&lt;/b&gt; Вы говорите DuckDB использовать `cache_httpfs` в качестве клиента для HTTP-запросов. Этот клиент сначала проверяет, нет ли уже нужного блока данных (например, футера Parquet-файла) в локальном кэше. Если есть — отдает его мгновенно. Если нет — идет в S3, скачивает блок, сохраняет его в кэш и отдает DuckDB.&lt;/p&gt;
&lt;p&gt;Вот как это настроить:&lt;/p&gt;
&lt;h5&gt;Шаг 1: Установка и загрузка расширений&lt;/h5&gt;
&lt;p&gt;Вам понадобятся три расширения: `httpfs` (для работы с S3), `cache_httpfs` (для кэширования) и, если вы работаете с Iceberg, то и `iceberg`.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;INSTALL httpfs;
INSTALL cache_httpfs;
LOAD httpfs;
LOAD cache_httpfs;&lt;/code&gt;&lt;/pre&gt;&lt;h5&gt;Шаг 2: Активация кэширующего клиента&lt;/h5&gt;
&lt;p&gt;Это ключевой шаг. Вы должны указать DuckDB использовать `cache_httpfs` для всех HTTP-операций.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;SET httpfs_client = 'cached_httpfs';&lt;/code&gt;&lt;/pre&gt;&lt;h5&gt;Шаг 3: Настройка пути к кэшу (критически важно для Serverless)&lt;/h5&gt;
&lt;p&gt;По умолчанию `cache_httpfs` сохраняет кэш в директорию `~/.cache/duckdb/`. Это хорошо работает на локальной машине, но в serverless-окружениях (AWS Lambda, Cloud Functions) эта папка либо недоступна для записи, либо является эфемерной.&lt;/p&gt;
&lt;p&gt;В serverless-среде единственное гарантированно доступное для записи место — это директория `/tmp`.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;SET cache_httpfs_cache_path = '/tmp/duckdb_cache';&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Этот кэш в `/tmp` будет “жить” между “теплыми” вызовами вашей Lambda-функции. Если одна и та же функция вызывается несколько раз подряд, второй и последующие вызовы будут использовать уже заполненный кэш, что кардинально ускорит выполнение запросов к одним и тем же данным.&lt;/p&gt;
&lt;h4&gt;Полный пример конфигурации (Python)&lt;/h4&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;import duckdb

# Подключаемся к базе данных
con = duckdb.connect()

# Устанавливаем и загружаем расширения
con.execute(&amp;quot;INSTALL httpfs;&amp;quot;)
con.execute(&amp;quot;INSTALL cache_httpfs;&amp;quot;)
con.execute(&amp;quot;LOAD httpfs;&amp;quot;)
con.execute(&amp;quot;LOAD cache_httpfs;&amp;quot;)

# --- Настройка S3 и кэша ---

# 1. Настройте креды для S3 (если не используются IAM-роли)
# con.execute(&amp;quot;SET s3_access_key_id='YOUR_KEY';&amp;quot;)
# con.execute(&amp;quot;SET s3_secret_access_key='YOUR_SECRET';&amp;quot;)
con.execute(&amp;quot;SET s3_region='us-east-1';&amp;quot;)

# 2. Активируем кэширующий http-клиент
con.execute(&amp;quot;SET httpfs_client = 'cached_httpfs';&amp;quot;)

# 3. Указываем путь к директории кэша (обязательно для serverless)
con.execute(&amp;quot;SET cache_httpfs_cache_path = '/tmp/duckdb_http_cache';&amp;quot;)

# --- Выполняем запрос ---

# Первый запуск этого запроса будет медленнее,
# так как он заполнит кэш метаданными файлов.
result1 = con.execute(&amp;quot;SELECT count(*) FROM 's3://my-bucket/data/*.parquet'&amp;quot;).fetchone()
print(f&amp;quot;Первый запуск: {result1[0]}&amp;quot;)

# Второй запуск будет на порядки быстрее,
# так как все метаданные будут прочитаны из локального кэша в /tmp.
result2 = con.execute(&amp;quot;SELECT count(*) FROM 's3://my-bucket/data/*.parquet'&amp;quot;).fetchone()
print(f&amp;quot;Второй запуск (с кэшем): {result2[0]}&amp;quot;)&lt;/code&gt;&lt;/pre&gt;&lt;h4&gt;Сравнение: Встроенный кэш vs `cache_httpfs`&lt;/h4&gt;
&lt;p&gt;Стоит отметить, что стандартный `httpfs` тоже имеет небольшой *внутренний, оперативный кэш*, но его возможности ограничены.&lt;/p&gt;
&lt;table cellpadding="0" cellspacing="0" border="0" class="e2-text-table"&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;Параметр&lt;/td&gt;
&lt;td style="text-align: center"&gt;Встроенный кэш `httpfs`&lt;/td&gt;
&lt;td style="text-align: center"&gt;Расширение `cache_httpfs`&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Тип&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;Внутренний, в памяти&lt;/td&gt;
&lt;td style="text-align: center"&gt;Явный, на диске&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Жизненный цикл&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;Живет &lt;b&gt;в рамках одного соединения&lt;/b&gt; (connection). При переподключении кэш пуст.&lt;/td&gt;
&lt;td style="text-align: center"&gt;Живет &lt;b&gt;между сессиями и процессами&lt;/b&gt;. Сохраняется на диске до очистки.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Назначение&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;Ускорение повторных запросов в одной и той же длительной сессии.&lt;/td&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Радикальное ускорение&lt;/b&gt; для любых повторных запросов, особенно в serverless (warm starts) и при локальной разработке.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Активация&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;Включен по умолчанию&lt;/td&gt;
&lt;td style="text-align: center"&gt;Требует `SET httpfs_client = ‘cached_httpfs’;`&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Настройка&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;Не настраивается&lt;/td&gt;
&lt;td style="text-align: center"&gt;Настраивается путь (`cache_httpfs_cache_path`) и максимальный размер.&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Для серьезной работы с данными на S3, особенно в serverless-архитектуре, использование расширения `cache_httpfs` является приятным дополнением и зачастую обязательным. Это та самая “серебряная пуля”, которая убирает узкое место в виде задержек сети и большого количества API-вызовов к облачному хранилищу.&lt;/p&gt;
&lt;p&gt;Начиная с тяжелых ETL-процессов на Trino и заканчивая быстрыми запросами в DuckDB, современный стек данных предлагает невероятную гибкость и производительность. Выбрав правильный инструмент или их комбинацию для каждой задачи, можно построить по-настоящему эффективную и масштабируемую аналитическую платформу.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/duck.png" width="198" height="149" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;pic. Krenskiy Dmitriy&lt;/div&gt;
&lt;/div&gt;
</description>
</item>

<item>
<title>Расцвет одноузловой обработки: Бросая вызов подходу – распределённое решение в первую очередь</title>
<guid isPermaLink="false">195</guid>
<link>https://gavrilov.info/all/rascvet-odnouzlovoy-obrabotki-brosaya-vyzov-podhodu-raspredelyon/</link>
<pubDate>Sun, 23 Feb 2025 21:05:19 +0300</pubDate>
<author></author>
<comments>https://gavrilov.info/all/rascvet-odnouzlovoy-obrabotki-brosaya-vyzov-podhodu-raspredelyon/</comments>
<description>
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/image-140.png" width="1002" height="708" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Перевод: &lt;a href="https://www.pracdata.io/p/the-rise-of-single-node-processing"&gt;https://www.pracdata.io/p/the-rise-of-single-node-processing&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;b&gt;Введение&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;В 2024 году наблюдается растущий интерес к одноузловым системам обработки данных. Инструменты вроде DuckDB, Apache DataFusion и Polars привлекли внимание сообщества и стали невероятно популярными. Этот тренд — не просто технологический прогресс, а переосмысление подходов к аналитике данных.&lt;/p&gt;
&lt;p&gt;По мере отказа от парадигмы «распределённые системы прежде всего», доминировавшей в эпоху «больших данных», компании обнаруживают, что одноузловые решения часто эффективнее, экономичнее и проще в управлении, особенно при работе с данными умеренного объёма.&lt;/p&gt;
&lt;p&gt;Недавний пост «Почему одноузловые системы набирают обороты в обработке данных» в LinkedIn вызвал неожиданно живой отклик сообщества, что подчеркнуло возросший интерес к теме. В этой статье мы рассмотрим её подробнее.&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Переосмысление «больших данных»&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Последнее десятилетие компании активно внедряли стратегии big data, инвестируя в распределённые системы вроде Hadoop и Spark. Однако исследования показывают, что большинству компаний «большие данные» не нужны.&lt;/p&gt;
&lt;p&gt;Итоги анализа:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Jordan Tigani&lt;/b&gt; (основатель Google BigQuery): медианный объём данных у активных пользователей BigQuery — менее 100 ГБ.&lt;/li&gt;
&lt;li&gt;Исследование 500 млн запросов Amazon Redshift:
&lt;ul&gt;
  &lt;li&gt;99% обрабатывали менее 10 ТБ данных;&lt;/li&gt;
  &lt;li&gt;90% сессий работали с менее чем 1 ТБ;&lt;/li&gt;
  &lt;li&gt;98% таблиц содержат меньше миллиарда строк.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Вывод:&lt;/b&gt; Для 90% запросов достаточно одноузловых систем вместо распределённых (Spark, Trino, Athena).&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Паттерны рабочих нагрузок и старение данных&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;1. Эффект старения данных&lt;/b&gt;&lt;br /&gt;
Доступ к данным резко сокращается со временем:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Горячие данные&lt;/b&gt; (0–48 часов): обработка ETL-пайплайнами.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Тёплые данные&lt;/b&gt; (2–30 дней): основа аналитических запросов.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Холодные данные&lt;/b&gt; (30+ дней): редко запрашиваются (сохранены для истории или аудита).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Исследование Meta и eBay подтверждает: 95% обращений к данным происходят в первые 48 часов. В «золотой» аналитической зоне 95% запросов выполняются в течение 30 дней.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;2. Правило 90/10&lt;/b&gt;&lt;br /&gt;
90% рабочих нагрузок приходится на 10% данных (за 30 дней). Даже при хранении данных год, аналитики в основном работают с последними 30 днями.&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Эволюция оборудования: масштабирование вверх вместо распределения&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Рост возможностей одноузловых систем:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;В 2006 году (эпоха Hadoop) серверы имели 1 CPU и 2 ГБ RAM.&lt;/li&gt;
&lt;li&gt;Сегодня облачные инстансы (например, AWS EC2) предлагают 64+ ядер и 256+ ГБ RAM.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Экономика масштабирования:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Стоимость крупных инстансов (например, m5.16xlarge) сопоставима с расходами на несколько мелких узлов (например, 8 × m5.2xlarge) при одинаковой мощности.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Итог:&lt;/b&gt; Современные одноузловые системы справляются с задачами, которые раньше требовали распределения, но с меньшей сложностью.&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Производительность одноузловых систем&lt;/b&gt;&lt;br /&gt;
DuckDB, Apache DataFusion и другие движки используют:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Векторизованное выполнение запросов;&lt;/li&gt;
&lt;li&gt;Параллелизм;&lt;/li&gt;
&lt;li&gt;Оптимизацию использования памяти.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Примеры роста скорости:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Переход с Postgres на DuckDB дал ускорение в 4–200 раз (Vantage).&lt;/li&gt;
&lt;li&gt;DuckDB превзошёл коммерческие хранилища на TPC-DS до 300 ГБ (Fivetran).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Причины выбрать одноузловую обработку&lt;/b&gt;&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Простота:&lt;/b&gt; Меньше сложности, чем в распределённых системах.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Эффективность:&lt;/b&gt; Реализация до 80% кода на C/C++ (против 10% в распределённых движках).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Совместимость:&lt;/b&gt; Интеграция с облачными хранилищами, языками программирования, BI-инструментами.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Ограничения&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Не все движки эффективно используют многоядерные CPU.&lt;/li&gt;
&lt;li&gt;Пропускная способность RAM/CPU может стать узким местом.&lt;/li&gt;
&lt;li&gt;Очень большие наборы данных (&gt;1 ТБ) всё ещё требуют распределения.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Заключение&lt;/b&gt;&lt;br /&gt;
Одноузловая обработка — прагматичный ответ на реальные потребности бизнеса. С развитием оборудования и оптимизацией движков необходимость в распределённых системах будет снижаться.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Главный вывод:&lt;/b&gt; Выбирайте инструмент под конкретную задачу, а не следуйте трендам. Будущее — за балансом между мощью одноузловых систем и гибкостью распределённых решений.&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Полный дословный перевод&lt;/b&gt;:&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Введение&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;В 2024 году наблюдался растущий интерес к фреймворкам одноузловой обработки, при этом такие инструменты, как DuckDB, Apache DataFusion и Polars, привлекли повышенное внимание и завоевали беспрецедентную популярность в сообществе специалистов по данным.&lt;/p&gt;
&lt;p&gt;Эта тенденция представляет собой не просто технологический прогресс — она знаменует собой фундаментальную переоценку подхода к анализу данных.&lt;/p&gt;
&lt;p&gt;По мере того, как мы отходим от подхода “распределённое решение в первую очередь” эпохи “больших данных”, многие предприятия обнаруживают, что решения одноузловой обработки зачастую обеспечивают более эффективный, экономичный и управляемый подход к своим аналитическим потребностям, когда размер их данных не так велик.&lt;/p&gt;
&lt;p&gt;Когда я недавно опубликовал небольшую заметку в LinkedIn под названием “Почему одноузловые движки набирают обороты в обработке данных”, я не ожидал, что она привлечет такое значительное внимание со стороны сообщества специалистов по данным в LinkedIn. Этот отклик подчеркнул растущий интерес отрасли к этой теме.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/image-141.png" width="1054" height="1144" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;В этой статье я углублюсь в эту тему, изучив её более детально и предоставив дополнительные сведения.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Переосмысление больших данных&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Последнее десятилетие многие предприятия изо всех сил пытались внедрить стратегии больших данных, при этом многие компании вкладывали значительные средства в фреймворки распределенной обработки, такие как Hadoop и Spark.&lt;/p&gt;
&lt;p&gt;Однако недавние анализы выявили удивительную правду: у большинства компаний на самом деле нет “больших данных”.&lt;/p&gt;
&lt;p&gt;Значительному большинству компаний не требуются крупные платформы данных для удовлетворения своих потребностей в анализе данных. Часто эти компании поддаются маркетинговой шумихе и делают значительные инвестиции в эти платформы, которые могут неэффективно решать их фактические проблемы с данными.&lt;/p&gt;
&lt;p&gt;Джордан Тигани, один из инженеров-основателей Google BigQuery, проанализировал шаблоны использования и обнаружил, что медианный размер хранилища данных среди активных пользователей BigQuery составляет менее 100 ГБ.&lt;/p&gt;
&lt;p&gt;Ещё более показательным является анализ полумиллиарда запросов, выполненных в Amazon Redshift и опубликованных в статье:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Более 99% запросов обработали менее 10 ТБ данных.&lt;/li&gt;
&lt;li&gt;Более 90% сеансов обработали менее 1 ТБ.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;В статье также говорится, что:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Большинство таблиц содержит менее миллиона строк, и подавляющее большинство (98%) — менее миллиарда строк. Большая часть этих данных достаточно мала, чтобы её можно было кэшировать или реплицировать.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Этот анализ показывает, что при пороговом значении для больших данных в 1 ТБ более 90% запросов находятся ниже этого порога.&lt;/p&gt;
&lt;p&gt;В результате, одноузловые движки обработки потенциально способны обрабатывать рабочие нагрузки, которые ранее требовали распределенных систем, таких как Spark, Trino или Amazon Athena, для обработки на нескольких машинах.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/image-142.png" width="1201" height="812" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Эта реальность ставит под сомнение распространенное представление о том, что инфраструктура больших данных является необходимостью для всех современных предприятий.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Шаблоны рабочей нагрузки и быстрое устаревание данных&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Аргументы в пользу одноузловой обработки становятся ещё более убедительными, когда мы изучаем, как организации в действительности используют свои данные.&lt;/p&gt;
&lt;p&gt;Выявляются два ключевых шаблона: эффект устаревания данных и правило 90/10 для аналитических рабочих нагрузок.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Эффект устаревания данных&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;По мере устаревания данных частота доступа к ним резко снижается. Для большинства компаний шаблоны доступа к данным следуют предсказуемому жизненному циклу:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Активные данные (0-48 часов): в основном из конвейеров ETL.&lt;/li&gt;
&lt;li&gt;Теплые данные (2-30 дней): составляют большую часть аналитических запросов.&lt;/li&gt;
&lt;li&gt;Холодные данные (30+ дней): редко используются, но часто хранятся для соответствия требованиям или исторического анализа.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Исследование шаблонов доступа к данным Meta и eBay выявило резкое снижение доступа после первых нескольких дней, причем данные обычно становились холодными через месяц.&lt;/p&gt;
&lt;p&gt;В нашем анализе озера данных петабайтного масштаба мы обнаружили, что необработанные данные остаются активными только в течение 48 часов, причем 95% доступа приходится на это время, в основном со стороны нисходящих конвейеров ETL. В зоне Analytics (Gold) активный период длится около 7 дней, и 95% запросов выполняются только в течение 30 дней.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Правило 90/10 для аналитических рабочих нагрузок&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Этот эффект устаревания приводит к правилу 90/10 в аналитических рабочих нагрузках:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Если общий активный и теплый период составляет 30 дней и приходится на 90% рабочих нагрузок, то, при годовом сроке хранения, более 90% рабочих нагрузок получают доступ менее чем к 10% данных.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/image-143.png" width="1041" height="1340" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Этот шаблон остается удивительно постоянным в разных отраслях и вариантах использования. Даже в организациях с большими наборами данных большинство аналитических рабочих нагрузок работает с последними, агрегированными данными, которые легко помещаются в возможности одноузловой обработки.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Эволюция оборудования и переосмысление масштабирования вверх&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Возможности одноузловых систем экспоненциально выросли со времен зарождения больших данных.&lt;/p&gt;
&lt;p&gt;Обоснование и мотивация стратегии масштабирования по горизонтали (scale-out), которая стала популярной с появлением Hadoop в середине 2000-х годов в области обработки данных, заключаются в необходимости объединения нескольких машин для решения проблем масштабирования, что позволяет эффективно обрабатывать большие наборы данных в разумные сроки и с приемлемым уровнем производительности.&lt;/p&gt;
&lt;p&gt;Интегрируя несколько машин в распределенные системы, мы фактически создаем единый большой блок, объединяя ресурсы, такие как ОЗУ, ЦП, дисковое пространство и пропускную способность, в одну большую виртуальную машину.&lt;/p&gt;
&lt;p&gt;Однако нам необходимо переоценить наши предположения о распределенной обработке и проблемах масштабирования, с которыми мы столкнулись в 2000-х годах, чтобы увидеть, остаются ли они актуальными сегодня.&lt;/p&gt;
&lt;p&gt;В 2006 году, когда появился Hadoop MapReduce, первые инстансы AWS EC2 (m1.small) имели всего 1 ЦП и менее 2 ГБ ОЗУ. Сегодня облачные провайдеры предлагают инстансы с 64+ ядрами и 256 ГБ+ ОЗУ, что кардинально меняет ситуацию с возможностями одноузловой обработки.&lt;/p&gt;
&lt;p&gt;Изучение эволюции сбалансированных инстансов EC2 с точки зрения памяти и ЦП (с соотношением 1:4) на протяжении многих лет выявляет экспоненциальный рост, поскольку эти инстансы со временем становятся все более мощными.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/image-144.png" width="1456" height="448" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;&lt;b&gt;Экономика масштабирования вверх (Scale-Up) против масштабирования по горизонтали (Scale-Out)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Можно предположить, что масштабирование по горизонтали на нескольких небольших инстансах более рентабельно, чем использование более крупных инстансов. Однако модели облачного ценообразования говорят об обратном.&lt;/p&gt;
&lt;p&gt;Стоимость за вычислительную единицу в облаке является постоянной, независимо от того, используете ли вы меньший или больший инстанс, поскольку стоимость увеличивается линейно.&lt;/p&gt;
&lt;p&gt;То есть стоимость более крупных вычислительных инстансов в облаке увеличивается линейно, и общая цена остается той же, независимо от того, используете ли вы один более крупный инстанс или несколько небольших инстансов, при условии, что общее количество ядер и памяти одинаково.&lt;/p&gt;
&lt;p&gt;Используя семейство инстансов m5 от AWS в качестве примера, независимо от того, масштабируетесь ли вы вверх с помощью одного инстанса m5.16xlarge или масштабируетесь по горизонтали с помощью восьми инстансов m5.2xlarge, цена за час останется той же.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/image-145.png" width="882" height="694" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Эта эволюция оборудования имеет важные последствия для решений по архитектуре системы, поскольку:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Современные инстансы могут обрабатывать рабочие нагрузки, которые ранее требовали десятков небольших узлов, и делают это с меньшей сложностью и накладными расходами.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Это поднимает критический вопрос:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;С точки зрения соотношения цены и производительности, если одноузловой движок запросов может эффективно обрабатывать большинство рабочих нагрузок, есть ли еще выгода от распределения обработки по нескольким узлам?&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/image-146.png" width="1156" height="742" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;&lt;b&gt;Аргумент производительности для одноузловой обработки&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Современные одноузловые движки обработки используют передовые методы для достижения впечатляющей производительности.&lt;/p&gt;
&lt;p&gt;Движки, такие как DuckDB и Apache DataFusion, достигают превосходной производительности благодаря сложным методам оптимизации, включая векторизованное выполнение, параллельную обработку и эффективное управление памятью.&lt;/p&gt;
&lt;p&gt;Многочисленные тесты показывают эти улучшения производительности:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Vantage сообщила, что при переходе с Postgres на DuckDB для анализа затрат на облако они увидели улучшение производительности в диапазоне от 4X до 200X.&lt;/li&gt;
&lt;li&gt;Тесты генерального директора Fivetran с использованием наборов данных TPC-DS показали, что DuckDB превосходит коммерческие хранилища данных для наборов данных размером менее 300 ГБ.&lt;/li&gt;
&lt;li&gt;Эксперимент с 1 миллиардом строк поддельных данных о заказах, сравнивающий DuckDB с Amazon Athena.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Почему стоит выбрать одноузловую обработку?&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Аргументы в пользу одноузловой обработки выходят за рамки простой производительности. Для большинства предприятий современные одноузловые движки предлагают несколько веских преимуществ:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Они значительно упрощают архитектуру системы, устраняя сложность распределенных систем. Это упрощение снижает эксплуатационные расходы, облегчает отладку и снижает порог входа для команд, работающих с данными.&lt;/li&gt;
&lt;li&gt;Они часто обеспечивают лучшее использование ресурсов. Без накладных расходов на сетевую связь и распределенную координацию больше вычислительной мощности можно выделить для фактической обработки данных. Эта эффективность напрямую приводит к экономии затрат и повышению производительности.&lt;/li&gt;
&lt;li&gt;Они предлагают отличную интеграцию с современными рабочими процессами обработки данных. Такие движки, как chDB и DuckDB, могут напрямую запрашивать данные из облачного хранилища, бесперебойно работать с популярными языками программирования и органично вписываться в существующие конвейеры обработки данных.&lt;/li&gt;
&lt;li&gt;Встраиваемая природа некоторых из этих движков обеспечивает бесшовную интеграцию с существующими системами — от расширений PostgreSQL, таких как pg_analytics и pg_duckdb, до различных современных инструментов Business Intelligence — расширяя аналитические возможности без нарушения установленных рабочих процессов.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Проблемы и ограничения&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Хотя одноузловая обработка предлагает много преимуществ, важно признать её ограничения.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Некоторые движки по-прежнему сталкиваются с проблемами полного использования всех доступных ядер ЦП на больших машинах, особенно по мере увеличения количества ядер. Пропускная способность иерархии памяти между ОЗУ и ЦП может стать узким местом для определенных рабочих нагрузок.&lt;/li&gt;
&lt;li&gt;При чтении из облачного хранилища, такого как S3, скорость передачи данных через одно соединение может быть ограничена, хотя это часто можно смягчить с помощью параллельных соединений и интеллектуальных стратегий кэширования. И, естественно, остаются рабочие нагрузки, включающие очень большие наборы данных, которые превышают доступную память и хранилище, требующие распределенной обработки.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Заключение&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Расцвет одноузловых движков обработки представляет собой прагматичный сдвиг в анализе данных. Поскольку возможности оборудования продолжают развиваться, а одноузловые движки становятся все более сложными, потребность в распределенной обработке, вероятно, продолжит снижаться для большинства организаций.&lt;/p&gt;
&lt;p&gt;Для подавляющего большинства компаний фреймворки одноузловой обработки предлагают более эффективное, экономичное и управляемое решение для их потребностей в анализе данных. По мере продвижения вперед главное — не автоматически тянуться к распределенным решениям, а тщательно оценивать фактические требования к рабочей нагрузке и выбирать правильный инструмент для работы.&lt;/p&gt;
&lt;p&gt;Будущее обработки данных вполне может быть менее связано с управлением кластерами и больше с использованием впечатляющих возможностей современных одноузловых систем.&lt;/p&gt;
&lt;p&gt;Спасибо автору ALIREZA SADEGHI и оригиналу: &lt;a href="https://www.pracdata.io/p/the-rise-of-single-node-processing"&gt;https://www.pracdata.io/p/the-rise-of-single-node-processing&lt;/a&gt;&lt;/p&gt;
</description>
</item>

<item>
<title>Полезный фрэймворк datafusion – SQL Engine на базе Arrow</title>
<guid isPermaLink="false">73</guid>
<link>https://gavrilov.info/all/polezny-freymvork-datafusion-sql-engine-na-baze-arrow/</link>
<pubDate>Wed, 18 Oct 2023 21:20:09 +0300</pubDate>
<author></author>
<comments>https://gavrilov.info/all/polezny-freymvork-datafusion-sql-engine-na-baze-arrow/</comments>
<description>
&lt;p&gt;&lt;a href="https://arrow.apache.org/datafusion/"&gt;https://arrow.apache.org/datafusion/&lt;/a&gt;&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;$ datafusion-cli
DataFusion CLI v17.0.0
❯ select * from 'data.csv';
+---+---+
| a | b |
+---+---+
| 1 | 2 |
+---+---+
1 row in set. Query took 0.007 seconds.&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;А можно даже с s3 напрямую читать:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;CREATE EXTERNAL TABLE test
STORED AS PARQUET
OPTIONS(
    'access_key_id' '******',
    'secret_access_key' '******',
    'region' 'us-east-2'
)
LOCATION 's3://bucket/path/file.parquet';&lt;/code&gt;&lt;/pre&gt;</description>
</item>


</channel>
</rss>