<?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 Data Engineer</title>
<link>https://gavrilov.info/tags/data-engineer/</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>StarRocks: Архитектура, Практика и место в современном Data Stack</title>
<guid isPermaLink="false">323</guid>
<link>https://gavrilov.info/all/starrocks-arhitektura-praktika-i-mesto-v-sovremennom-data-stack/</link>
<pubDate>Sun, 15 Mar 2026 19:06:01 +0300</pubDate>
<author></author>
<comments>https://gavrilov.info/all/starrocks-arhitektura-praktika-i-mesto-v-sovremennom-data-stack/</comments>
<description>
&lt;p&gt;&lt;b&gt;StarRocks&lt;/b&gt; — это аналитическая MPP-база данных нового поколения.&lt;br /&gt;
Если коротко, она пытается решить трилемму аналитики: объединить скорость &lt;b&gt;ClickHouse&lt;/b&gt; (за счет векторизации и C++), гибкость &lt;b&gt;Trino&lt;/b&gt; (поддержка сложных JOIN-ов) и простоту использования &lt;b&gt;MySQL&lt;/b&gt; (совместимый протокол).&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/logo_starr.svg" width="54" height="62" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Это короткое руководство проведет вас от понимания архитектуры до построения простого конвейера загрузки данных (ETL) в домашнем продакшене.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Часть 1. Архитектура: FE и BE&lt;/h3&gt;
&lt;p&gt;В отличие от PostgreSQL (монолит) или ClickHouse (где узлы часто одноранговые), StarRocks имеет четкое разделение ролей. Это критически важно для понимания масштабирования и эксплуатации.&lt;/p&gt;
&lt;h4&gt;1. FE (Frontend) — “Мозг”&lt;/h4&gt;
&lt;p&gt;Написан на Java.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Роль:&lt;/b&gt; Управляющий слой.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Функции:&lt;/b&gt;
&lt;ul&gt;
  &lt;li&gt;Принимает подключения клиентов (по протоколу MySQL).&lt;/li&gt;
  &lt;li&gt;Хранит метаданные (схемы таблиц, права доступа).&lt;/li&gt;
  &lt;li&gt;Парсит SQL и строит план выполнения запроса (Query Plan).&lt;/li&gt;
  &lt;li&gt;Управляет транзакциями загрузки данных.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Масштабирование:&lt;/b&gt; Обычно запускают 1 или 3 узла для обеспечения высокой доступности (HA).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Важно:&lt;/b&gt; Клиенты (DBeaver, BI, сurl) подключаются &lt;b&gt;только&lt;/b&gt; к FE.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;2. BE (Backend) — “Мускулы”&lt;/h4&gt;
&lt;p&gt;Написан на C++ (использует SIMD-инструкции процессора).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Роль:&lt;/b&gt; Слой хранения и вычислений.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Функции:&lt;/b&gt;
&lt;ul&gt;
  &lt;li&gt;Физически хранит данные (в колоночном формате).&lt;/li&gt;
  &lt;li&gt;Выполняет “тяжелую” работу: фильтрацию, агрегацию, JOIN-ы.&lt;/li&gt;
  &lt;li&gt;Управляет репликацией данных.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Масштабирование:&lt;/b&gt; Можно добавлять узлы линейно. Чем больше BE, тем быстрее выполняются запросы и тем больше данных можно хранить.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;b&gt;В Docker All-in-One:&lt;/b&gt; Оба компонента упакованы в один контейнер для удобства, но слушают разные порты:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;`9030`: FE (SQL интерфейс, сюда идет DBeaver).&lt;/li&gt;
&lt;li&gt;`8030`: FE (HTTP API для загрузки Stream Load, сюда идет curl).&lt;/li&gt;
&lt;li&gt;`8040`: BE (HTTP API метрик и логов).&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h3&gt;Часть 2. Быстрый старт (Docker Compose)&lt;/h3&gt;
&lt;p&gt;Мы поднимем стек StarRocks и MinIO (S3-совместимое хранилище), используя bridge-сеть для связности.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Файл `docker-compose.yml`&lt;/b&gt; (Полностью рабочий пример):&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;version: &amp;quot;3.9&amp;quot;

networks:
  starrocks-stack-network:
    driver: bridge

services:
  starrocks:
    image: starrocks/allin1-ubuntu:4.0-latest
    container_name: starrocks
    hostname: starrocks.local.com
    platform: &amp;quot;linux/amd64&amp;quot;
    restart: unless-stopped
    ports:
      - &amp;quot;9030:9030&amp;quot; # MySQL Protocol (SQL клиенты)
      - &amp;quot;8030:8030&amp;quot; # FE HTTP (Stream Load)
      - &amp;quot;8040:8040&amp;quot; # BE HTTP (Logs/Metrics)
    environment:
      - TZ=UTC
    networks:
      starrocks-stack-network:
    volumes:
      # Персистентность данных (чтобы данные не исчезли после рестарта)
      - ${HOME}/dv/starrocks/be/storage:/data/deploy/starrocks/be/storage
      - ${HOME}/dv/starrocks/be/log:/data/deploy/starrocks/be/log
      - ${HOME}/dv/starrocks/fe/meta:/data/deploy/starrocks/fe/meta
      - ${HOME}/dv/starrocks/fe/log:/data/deploy/starrocks/fe/log

  minio:
    image: quay.io/minio/minio
    container_name: minio
    platform: &amp;quot;linux/amd64&amp;quot;
    hostname: minio.local.com
    restart: unless-stopped
    ports:
      - &amp;quot;9000:9000&amp;quot; # S3 API
      - &amp;quot;9001:9001&amp;quot; # Web UI
    networks:
      starrocks-stack-network:
    environment:
      MINIO_ROOT_USER: root
      MINIO_ROOT_PASSWORD: rootroot
    volumes:
      - ${HOME}/dv/minio/data:/data
    command: server /data --console-address &amp;quot;:9001&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Запуск:&lt;br /&gt;
`docker-compose up -d`&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Часть 3. Моделирование данных (Table Design)&lt;/h3&gt;
&lt;p&gt;В StarRocks нельзя просто “создать таблицу”. Нужно выбрать тип ключа (&lt;b&gt;Key Model&lt;/b&gt;), который определит, как база будет хранить и обновлять данные.&lt;/p&gt;
&lt;p&gt;Подключение (DBeaver): `localhost:9030`, User: `root`, Password: (пусто).&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;CREATE DATABASE IF NOT EXISTS demo_db;
USE demo_db;&lt;/code&gt;&lt;/pre&gt;&lt;h4&gt;1. Primary Key Model (Для изменяемых данных)&lt;/h4&gt;
&lt;p&gt;Это “флагманская” возможность StarRocks. Она поддерживает быстрые &lt;b&gt;Upsert&lt;/b&gt; (вставка новых или обновление старых записей по ID) в реальном времени.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;CREATE TABLE IF NOT EXISTS users (
    user_id INT NOT NULL,
    username VARCHAR(50),
    email VARCHAR(100),
    register_date DATE, 
    city VARCHAR(50)
)
PRIMARY KEY (user_id) -- Уникальный ключ
DISTRIBUTED BY HASH(user_id) -- Распределение данных
PROPERTIES (
    &amp;quot;replication_num&amp;quot; = &amp;quot;1&amp;quot; -- Для локального теста ставим 1 реплику
);&lt;/code&gt;&lt;/pre&gt;&lt;h4&gt;2. Aggregate Key Model (Для витрин данных)&lt;/h4&gt;
&lt;p&gt;База автоматически агрегирует данные при вставке. Если вы вставите новую продажу с *существующими* датой и категорией, StarRocks не создаст новую строку, а прибавит суммы к уже существующей строке. Это экономит место и ускоряет `GROUP BY`.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;CREATE TABLE IF NOT EXISTS daily_sales (
    report_date DATE NOT NULL,
    category VARCHAR(50) NOT NULL,
    
    -- Метрики с функцией агрегации:
    total_amount BIGINT SUM DEFAULT &amp;quot;0&amp;quot;, 
    items_sold INT SUM DEFAULT &amp;quot;0&amp;quot;       
)
AGGREGATE KEY (report_date, category)
DISTRIBUTED BY HASH(report_date) BUCKETS 3
PROPERTIES (
    &amp;quot;replication_num&amp;quot; = &amp;quot;1&amp;quot;
);&lt;/code&gt;&lt;/pre&gt;&lt;hr /&gt;
&lt;h3&gt;Часть 4. загрузка данных users (Stream Load)&lt;/h3&gt;
&lt;p&gt;Для загрузки данных в продакшене мы используем &lt;b&gt;Service Account&lt;/b&gt; (Техническую учетную запись). Это стандарт безопасности: мы не используем `root` и не используем токены в конфигах (так как они требуют перезагрузки кластера для смены).&lt;/p&gt;
&lt;h4&gt;Шаг 1. Создание сервисного пользователя (SQL)&lt;/h4&gt;
&lt;p&gt;Выполнять под `root`:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;-- 1. Создаем пользователя-бота
CREATE USER IF NOT EXISTS 'etl_loader'@'%' IDENTIFIED BY 'SecretPass123!';

-- 2. Даем права ТОЛЬКО на вставку и чтение в базе demo_db
GRANT INSERT, SELECT ON demo_db.* TO 'etl_loader'@'%';

-- Права применяются мгновенно.&lt;/code&gt;&lt;/pre&gt;&lt;h4&gt;Шаг 2. Загрузка сложного JSON через CURL&lt;/h4&gt;
&lt;p&gt;Stream Load — это самый быстрый способ загрузки (до 100 МБ/сек на узел). Он поддерживает транзакционность (ACID).&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Пример файла `users.json`:&lt;/b&gt;&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;{
  &amp;quot;users&amp;quot;: [
    {&amp;quot;user_id&amp;quot;: 101, &amp;quot;username&amp;quot;: &amp;quot;alex&amp;quot;, &amp;quot;email&amp;quot;: &amp;quot;a@test.com&amp;quot;, &amp;quot;city&amp;quot;: &amp;quot;NY&amp;quot;},
    {&amp;quot;user_id&amp;quot;: 102, &amp;quot;username&amp;quot;: &amp;quot;bob&amp;quot;, &amp;quot;email&amp;quot;: &amp;quot;b@test.com&amp;quot;, &amp;quot;city&amp;quot;: &amp;quot;LA&amp;quot;}
  ]
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;b&gt;Команда загрузки (Terminal):&lt;/b&gt;&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;curl --location-trusted \
    -u etl_loader:SecretPass123! \
    -H &amp;quot;Expect: 100-continue&amp;quot; \
    -H &amp;quot;format: json&amp;quot; \
    -H &amp;quot;strip_outer_array: true&amp;quot; \
    -H &amp;quot;json_root: $.users&amp;quot; \
    -H &amp;quot;jsonpaths: [\&amp;quot;$.user_id\&amp;quot;, \&amp;quot;$.username\&amp;quot;, \&amp;quot;$.email\&amp;quot;, \&amp;quot;$.city\&amp;quot;]&amp;quot; \
    -H &amp;quot;columns: user_id, username, email, city&amp;quot; \
    -T &amp;quot;users.json&amp;quot; \
    -XPUT http://localhost:8030/api/demo_db/users/_stream_load&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ответ&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;{
    &amp;quot;TxnId&amp;quot;: 9596,
    &amp;quot;Label&amp;quot;: &amp;quot;a9a37ab6-3678-4c08-95b7-2fd8b6ae973e&amp;quot;,
    &amp;quot;Db&amp;quot;: &amp;quot;demo_db&amp;quot;,
    &amp;quot;Table&amp;quot;: &amp;quot;users&amp;quot;,
    &amp;quot;Status&amp;quot;: &amp;quot;Success&amp;quot;,
    &amp;quot;Message&amp;quot;: &amp;quot;OK&amp;quot;,
    &amp;quot;NumberTotalRows&amp;quot;: 2,
    &amp;quot;NumberLoadedRows&amp;quot;: 2,
    &amp;quot;NumberFilteredRows&amp;quot;: 0,
    &amp;quot;NumberUnselectedRows&amp;quot;: 0,
    &amp;quot;LoadBytes&amp;quot;: 177,
    &amp;quot;LoadTimeMs&amp;quot;: 153,
    &amp;quot;BeginTxnTimeMs&amp;quot;: 2,
    &amp;quot;StreamLoadPlanTimeMs&amp;quot;: 2,
    &amp;quot;ReadDataTimeMs&amp;quot;: 0,
    &amp;quot;WriteDataTimeMs&amp;quot;: 26,
    &amp;quot;CommitAndPublishTimeMs&amp;quot;: 121
}%&lt;/code&gt;&lt;/pre&gt;&lt;h4&gt;Шаг 3. Загрузка в Aggregate Table (Example)&lt;/h4&gt;
&lt;p&gt;Давайте “дольем” данные в таблицу продаж. Агрегация произойдет на лету.&lt;br /&gt;
Файл sales.json (простой список):&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;[
    {&amp;quot;dt&amp;quot;: &amp;quot;2023-11-01&amp;quot;, &amp;quot;cat&amp;quot;: &amp;quot;Electronics&amp;quot;, &amp;quot;amt&amp;quot;: 100, &amp;quot;qty&amp;quot;: 1},
    {&amp;quot;dt&amp;quot;: &amp;quot;2023-11-01&amp;quot;, &amp;quot;cat&amp;quot;: &amp;quot;Electronics&amp;quot;, &amp;quot;amt&amp;quot;: 50,  &amp;quot;qty&amp;quot;: 1}
]

curl --location-trusted \
    -u etl_loader:SecretPass123! \
    -H &amp;quot;format: json&amp;quot; \
    -H &amp;quot;Expect: 100-continue&amp;quot; \
    -H &amp;quot;strip_outer_array: true&amp;quot; \
    -H &amp;quot;jsonpaths: [\&amp;quot;$.dt\&amp;quot;, \&amp;quot;$.cat\&amp;quot;, \&amp;quot;$.amt\&amp;quot;, \&amp;quot;$.qty\&amp;quot;]&amp;quot; \
    -H &amp;quot;columns: report_date, category, total_amount, items_sold&amp;quot; \
    -T &amp;quot;sales.json&amp;quot; \
    -XPUT http://localhost:8030/api/demo_db/daily_sales/_stream_load&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Ответ:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;{
    &amp;quot;TxnId&amp;quot;: 9613,
    &amp;quot;Label&amp;quot;: &amp;quot;bce0721a-dc2d-4927-be93-e0979a57873d&amp;quot;,
    &amp;quot;Db&amp;quot;: &amp;quot;demo_db&amp;quot;,
    &amp;quot;Table&amp;quot;: &amp;quot;daily_sales&amp;quot;,
    &amp;quot;Status&amp;quot;: &amp;quot;Success&amp;quot;,
    &amp;quot;Message&amp;quot;: &amp;quot;OK&amp;quot;,
    &amp;quot;NumberTotalRows&amp;quot;: 2,
    &amp;quot;NumberLoadedRows&amp;quot;: 2,
    &amp;quot;NumberFilteredRows&amp;quot;: 0,
    &amp;quot;NumberUnselectedRows&amp;quot;: 0,
    &amp;quot;LoadBytes&amp;quot;: 143,
    &amp;quot;LoadTimeMs&amp;quot;: 52,
    &amp;quot;BeginTxnTimeMs&amp;quot;: 3,
    &amp;quot;StreamLoadPlanTimeMs&amp;quot;: 2,
    &amp;quot;ReadDataTimeMs&amp;quot;: 0,
    &amp;quot;WriteDataTimeMs&amp;quot;: 24,
    &amp;quot;CommitAndPublishTimeMs&amp;quot;: 20
}%&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;b&gt;Разбор заголовков:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;`-u ...`: Авторизация сервисным пользователем.&lt;/li&gt;
&lt;li&gt;`Expect: 100-continue`: Критически важно для надежности передачи больших файлов.&lt;/li&gt;
&lt;li&gt;`json_root: $.users`: Указывает базе, что данные лежат внутри ключа `users`.&lt;/li&gt;
&lt;li&gt;`strip_outer_array: true`: Говорит базе, что внутри лежит массив `[...]` и его нужно “развернуть” в отдельные строки.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3&gt;Часть 5. Совместимость и Trino Dialect&lt;/h3&gt;
&lt;p&gt;Одна из сильных сторон StarRocks — способность “притворяться” другими базами данных для облегчения миграции.&lt;/p&gt;
&lt;p&gt;Если у вас есть дашборды, написанные на диалекте &lt;b&gt;Trino (Presto)&lt;/b&gt;, вам не нужно переписывать все SQL-запросы.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Пример трансляции функций:&lt;/b&gt;&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;-- Функция Trino, которой нет в StarRocks
SELECT doy(date '2022-03-06'); 
-- Ошибка: No matching function...

-- Проверяем, как StarRocks переведет этот запрос
TRANSLATE TRINO select doy(date '2022-03-06');
-- Результат: SELECT dayofyear('2022-03-06')

-- Включаем режим автоматической трансляции в сессии
SET sql_dialect = 'trino'; 

-- Теперь запрос выполняется корректно, но это не правда. а вот так SELECT dayofyear('2022-03-06') работает. Может бага или у меня версия не та. 
SELECT doy(date '2022-03-06');   

-- Возвращаем нативный режим
SET sql_dialect = 'starrocks';&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;*(Примечание: Поддержка диалекта постоянно расширяется, но некоторые специфические функции могут требовать ручной замены).*&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Итог: Сравнение и Выбор решения ( грубо )&lt;/h3&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;b&gt;StarRocks&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;ClickHouse&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Trino (Presto)&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;OLAP-витрины с JOIN-ами и обновлениями данных&lt;/td&gt;
&lt;td style="text-align: center"&gt;Сбор логов, событий, метрик (Append-only)&lt;/td&gt;
&lt;td style="text-align: center"&gt;Федерация данных (запрос к S3 + Postgres + Kafka одновременно)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;JOIN производительность&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;⭐⭐⭐ (Excellent, CBO оптимизатор)&lt;/td&gt;
&lt;td style="text-align: center"&gt;⭐ (Слабо, требует денормализации)&lt;/td&gt;
&lt;td style="text-align: center"&gt;⭐⭐⭐ (Excellent)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Обновление (UPDATE)&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;⭐⭐⭐ (Работает как в OLTP, Primary Key)&lt;/td&gt;
&lt;td style="text-align: center"&gt;⭐ (Тяжелые асинхронные ALTER)&lt;/td&gt;
&lt;td style="text-align: center"&gt;❌ (Обычно только полная перезапись партиций), iceberg не в счёт :)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Язык Engine&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;C++ (SIMD Vectorized)&lt;/td&gt;
&lt;td style="text-align: center"&gt;C++ (SIMD Vectorized)&lt;/td&gt;
&lt;td style="text-align: center"&gt;Java (JVM)&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;Serving Layer&lt;/b&gt; (Быстрый доступ для BI)&lt;/td&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Storage Layer&lt;/b&gt; (Хранение логов)&lt;/td&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Query Engine&lt;/b&gt; (Ad-hoc запросы к Data Lake)&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;b&gt;Выбирайте StarRocks, если:&lt;/b&gt;&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Вам нужна “витрина” для BI (Superset/Tableau), где данные должны быть всегда свежими (Real-time updates).&lt;/li&gt;
&lt;li&gt;Ваш бизнес требует сложных аналитических запросов с множеством JOIN-ов, и ClickHouse не справляется/падает по памяти.&lt;/li&gt;
&lt;li&gt;Вы хотите использовать стандартный протокол MySQL без установки проприетарных драйверов.&lt;/li&gt;
&lt;/ol&gt;
</description>
</item>

<item>
<title>Битва титанов аналитики реального времени: StarRocks против ClickHouse</title>
<guid isPermaLink="false">320</guid>
<link>https://gavrilov.info/all/bitva-titanov-analitiki-realnogo-vremeni-starrocks-protiv-clickh/</link>
<pubDate>Fri, 06 Mar 2026 01:26:35 +0300</pubDate>
<author></author>
<comments>https://gavrilov.info/all/bitva-titanov-analitiki-realnogo-vremeni-starrocks-protiv-clickh/</comments>
<description>
&lt;p&gt;В мире больших данных, где счет идет на петабайты, а задержка измеряется миллисекундами, выбор правильного аналитического движка определяет успех продукта. Сегодня мы разберем восходящую звезду StarRocks и классического гиганта ClickHouse, а также посмотрим, как Netflix удалось укротить свои логи на экстремальных скоростях.&lt;/p&gt;
&lt;h3&gt;Часть 1: Обзор технологий и кейс Netflix&lt;/h3&gt;
&lt;h4&gt;StarRocks: Субсекундная аналитика нового поколения&lt;/h4&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/image.png-1.jpg" width="2560" height="1078" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;&lt;b&gt;StarRocks&lt;/b&gt; — это высокопроизводительный аналитический движок (MPP database) нового поколения, разработанный для сценариев, где скорость имеет решающее значение. Будучи проектом Linux Foundation, он позиционирует себя как самый быстрый открытый движок запросов для субсекундной аналитики как внутри собственного хранилища, так и поверх архитектуры Data Lakehouse.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Ключевые особенности StarRocks:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Универсальность:** Поддерживает почти любые сценарии — от многомерной OLAP-аналитики и realtime-дэшбордов до ad-hoc запросов аналитиков.&lt;/li&gt;
&lt;li&gt;Скорость:** Использует векторизованный движок исполнения, CBO (Cost-Based Optimizer) и пайплайновый параллелизм, что позволяет обгонять конкурентов на сложных запросах с JOIN-ами.&lt;/li&gt;
&lt;li&gt;Архитектура:** Native cloud-ready, легко масштабируется горизонтально. Умеет работать “on and off the lakehouse” — то есть быстро читать данные напрямую из S3/HDFS (форматы Parquet, ORC, Iceberg, Hudi) без необходимости их обязательной загрузки внутрь базы.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h4&gt;Кейс Netflix: Как оптимизировать логирование петабайтного масштаба с ClickHouse&lt;/h4&gt;
&lt;p&gt;*( адаптация материала из блога ClickHouse)* &lt;a href="https://clickhouse.com/blog/netflix-petabyte-scale-logging"&gt;https://clickhouse.com/blog/netflix-petabyte-scale-logging&lt;/a&gt;&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/Screenshot-from-2026-03-06-01-15-33.png" width="833" height="380" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;В Netflix масштаб диктует всё. Инженер Дэниел Муино поделился инсайтами о том, как их система логирования справляется с &lt;b&gt;5 петабайтами логов ежедневно&lt;/b&gt;, обрабатывая в среднем 10.6 миллионов событий в секунду и отвечая на запросы быстрее, чем за секунду.&lt;/p&gt;
&lt;p&gt;Для достижения такой производительности потребовалось не просто выбрать правильную базу данных (ClickHouse), но и внедрить три критических инженерных оптимизации.&lt;/p&gt;
&lt;h5&gt;Архитектура: Горячее и холодное&lt;/h5&gt;
&lt;p&gt;Netflix использует гибридный подход:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Горячий слой (ClickHouse):** Хранит недавние логи, где критична скорость для интерактивной отладки. Данные поступают через Kafka/Kinesis в ClickHouse практически мгновенно.&lt;/li&gt;
&lt;li&gt;Холодный слой (Apache Iceberg):** Обеспечивает экономичное долговременное хранение исторических данных на S3.&lt;/li&gt;
&lt;li&gt;Единый API автоматически решает, к какому слою обращаться, скрывая сложность от инженеров.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/image.png.jpg" width="2560" height="1403" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Результат: логи доступны для поиска через 20 секунд после генерации (при SLA в 5 минут), а сложные аналитические запросы выполняются почти мгновенно.&lt;/p&gt;
&lt;h5&gt;Три главные оптимизации&lt;/h5&gt;
&lt;p&gt;&lt;b&gt;1. Ingestion: Свой лексер вместо Regex&lt;/b&gt;&lt;br /&gt;
Изначально Netflix использовал регулярные выражения для группировки похожих логов (fingerprinting). На скорости 10 млн событий/сек это стало узким местом.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Решение:* Команда переписала логику, создав &lt;b&gt;сгенерированный лексер&lt;/b&gt; с помощью JFlex.&lt;/li&gt;
&lt;li&gt;Результат:* Рост пропускной способности в 8-10 раз. Время обработки одного события упало с 216 до 23 микросекунд.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;2. Сериализация: Отказ от JDBC&lt;/b&gt;&lt;br /&gt;
Стандартные JDBC-вставки через Java-клиент создавали оверхед на согласование схем. Переход на низкоуровневый формат `RowBinary` помог, но потребление CPU оставалось высоким.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Решение:* Дэниел реверс-инжинирил протокол Go-клиента ClickHouse (который поддерживает нативный формат) и написал &lt;b&gt;собственный энкодер&lt;/b&gt;. Он генерирует LZ4-сжатые блоки в нативном протоколе ClickHouse.&lt;/li&gt;
&lt;li&gt;Результат:* Снижение нагрузки на CPU и памяти при той же пропускной способности.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;3. Запросы: Шардирование карт тегов (Tag Maps)&lt;/b&gt;&lt;br /&gt;
Инженеры Netflix активно используют кастомные теги (фильтры по microservice_id, request_id). Изначально они хранились как `Map(String, String)`. В ClickHouse это реализовано как два параллельных массива, что требует линейного сканирования при поиске. При 25 000 уникальных ключей в час запросы тормозили.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Решение:* Шардирование карты. Ключи тегов хешируются в 31 меньшую карту. Запрос сразу “прыгает” в нужный шард вместо перебора всех ключей.&lt;/li&gt;
&lt;li&gt;Результат:* Время фильтрующих запросов упало с 3 секунд до 1.3, а сложных проекций — с 3 секунд до &lt;b&gt;700 мс&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3&gt;Часть 2: ClickHouse vs StarRocks — Битва за Lakehouse&lt;/h3&gt;
&lt;p&gt;Обе системы являются лидерами в мире OLAP (On-Line Analytical Processing), используют MPP-архитектуру и колоночное хранение. Однако их философия и степень готовности к современной концепции &lt;b&gt;Lakehouse&lt;/b&gt; (аналитика данных непосредственно в озере данных без копирования) различаются.&lt;/p&gt;
&lt;h4&gt;1. Архитектурные корни и специализация&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;ClickHouse:**
&lt;ul&gt;
  &lt;li&gt;ДНК:* Изначально создавался для Яндекс.Метрики. Король &lt;b&gt;единой широкой таблицы&lt;/b&gt;.&lt;/li&gt;
  &lt;li&gt;Сильная сторона:* Непревзойденная скорость записи и чтения на одной таблице. Идеален для логов (как у Netflix), телеметрии, событийных данных.&lt;/li&gt;
  &lt;li&gt;Слабая сторона:* JOIN-ы (соединения таблиц). ClickHouse умеет их делать, но исторически это не его конек. Оптимизатор запросов долгое время был рудиментарным, требуя от пользователя ручной оптимизации порядка таблиц.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;StarRocks:**
&lt;ul&gt;
  &lt;li&gt;ДНК:* Эволюционировал из Apache Doris. Создавался с прицелом на сложные сценарии аналитики.&lt;/li&gt;
  &lt;li&gt;Сильная сторона:* &lt;b&gt;CBO (Cost-Based Optimizer)&lt;/b&gt; уровня Oracle или Teradata. StarRocks блестяще справляется со сложными SQL-запросами, включая многотабличные JOIN-ы “звезда” и “снежинка”.&lt;/li&gt;
  &lt;li&gt;Специфика:* Ориентирован на обновление данных в реальном времени (Primary Key table engine) и векторизованную обработку сложных вычислений.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;2. Степень готовности к Lakehouse (Работа с S3, HDFS, Iceberg)&lt;/h4&gt;
&lt;p&gt;Здесь наблюдается главное стратегическое расхождение.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;StarRocks: Native Lakehouse Engine&lt;/b&gt;&lt;br /&gt;
StarRocks позиционирует себя как движок, который может вообще &lt;b&gt;не хранить данные у себя&lt;/b&gt;, а выступать только быстрым вычислительным слоем поверх S3/MinIO.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Кэширование:** Имеет продвинутый локальный кэш данных (Local Data Cache), который подтягивает горячие данные из S3 на диски воркеров, обеспечивая скорость, сравнимую с нативным хранением.&lt;/li&gt;
&lt;li&gt;Каталоги:** Бесшовная интеграция с Hive Metastore, AWS Glue, Iceberg, Hudi, Delta Lake. Вы просто подключаете каталог и пишете `SELECT` к таблицам в S3 без `CREATE TABLE`.&lt;/li&gt;
&lt;li&gt;Вердикт:&lt;b&gt; StarRocks **полностью готов&lt;/b&gt; к Lakehouse. Это один из лучших выборов для сценария “данные лежат в S3 в формате Parquet/Iceberg, а нам нужен быстрый SQL поверх них”.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;ClickHouse: Storage First, Lakehouse Second&lt;/b&gt;&lt;br /&gt;
ClickHouse исторически — это система хранения. Хотя поддержка S3 и Data Lakes активно развивается (особенно в 2024-2025 годах), подход отличается.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Интеграция:** ClickHouse может читать из S3 (`s3()` table function или S3 table engine). Поддерживает Iceberg и Hudi.&lt;/li&gt;
&lt;li&gt;Производительность:** Чтение “холодных” данных из S3 в ClickHouse часто медленнее, чем в StarRocks, из-за особенностей реализации сканирования и работы с метаданными внешних форматов.&lt;/li&gt;
&lt;li&gt;Кейс Netflix подтверждает:&lt;b&gt; Netflix использует ClickHouse **как горячее хранилище&lt;/b&gt;, копируя туда данные. А для лекхоуса (Iceberg) они используют отдельные движки (вероятно, Trino или Spark), а ClickHouse выступает именно как акселератор для свежих данных.&lt;/li&gt;
&lt;li&gt;Вердикт:&lt;b&gt; ClickHouse движется в сторону Lakehouse (разделение Storage и Compute, S3-backed MergeTree), но его главная суперсила по-прежнему раскрывается, когда данные **импортированы&lt;/b&gt; в его родной формат.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Пример использования ClickHouse (из статьи выше)&lt;/h4&gt;
&lt;p&gt;В примере Netflix мы видим классический паттерн использования ClickHouse, где он силен максимально:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;*“ClickHouse находится в сердце системы как горячий слой (hot tier). Он хранит недавние логи, где скорость критична... Для исторических данных Netflix использует Apache Iceberg.”*&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Это подтверждает тезис: ClickHouse идеален, когда вы загружаете данные в него (Ingest heavy). StarRocks же часто выигрывает там, где данные уже лежат в озере, и вы не хотите их никуда копировать, либо, когда вам нужны сложные JOIN-ы поверх этих данных.&lt;/p&gt;
&lt;hr /&gt;
&lt;h4&gt;Итог и рекомендации&lt;/h4&gt;
&lt;p&gt;Выбор между StarRocks и ClickHouse больше не стоит в плоскости “кто быстрее сканирует одну колонку”. Обе системы феноменально быстры. Вопрос в архитектуре ваших данных.&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;Выбирайте ClickHouse, если:&lt;/b&gt;
&lt;ul&gt;
  &lt;li&gt;Ваша главная задача — работа с логами, метриками, clickstream (как у Netflix).&lt;/li&gt;
  &lt;li&gt;У вас плоская структура данных (одна широкая таблица), и JOIN-ы редки.&lt;/li&gt;
  &lt;li&gt;Вам нужна максимальная скорость вставки (ingestion) и максимальное сжатие данных на диске.&lt;/li&gt;
  &lt;li&gt;У вас есть ресурсы на инженерию: ClickHouse гибок, но, как показал кейс Netflix, требует “прямых рук” для тонкой настройки (кастомные кодеки, шардирование тегов).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;b&gt;Выбирайте StarRocks, если:&lt;/b&gt;
&lt;ul&gt;
  &lt;li&gt;Вы строите &lt;b&gt;Data Lakehouse&lt;/b&gt;: данные лежат в S3 (Iceberg/Parquet), и вы хотите анализировать их без ETL/копирования.&lt;/li&gt;
  &lt;li&gt;У вас сложная модель данных (схема “Звезда” или “Снежинка”) и много JOIN-ов в запросах.&lt;/li&gt;
  &lt;li&gt;Вам нужны обновления данных (UPSERT/DELETE) в реальном времени с использованием Primary Keys.&lt;/li&gt;
  &lt;li&gt;Вы хотите упростить поддержку и получить оптимизатор запросов, который многое сделает за вас “из коробки”.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Приложение:&lt;/p&gt;
&lt;p&gt;Ниже представлен анализ списка компаний, использующих &lt;b&gt;StarRocks&lt;/b&gt;. Они разделены по сферам деятельности, а также ранжированы по глубине использования технологии и вкладу в развитие проекта.&lt;/p&gt;
&lt;h4&gt;1. Сферы деятельности компаний&lt;/h4&gt;
&lt;p&gt;Вот краткое описание того, чем занимается каждая компания из вашего списка:&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Технологии, Интернет и E-commerce:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Alibaba:** Крупнейший китайский холдинг электронной коммерции и облачных вычислений.&lt;/li&gt;
&lt;li&gt;Shopee:** Ведущая платформа электронной коммерции в Юго-Восточной Азии и Тайване.&lt;/li&gt;
&lt;li&gt;Trip.com:** Одно из крупнейших в мире онлайн-турагентств.&lt;/li&gt;
&lt;li&gt;Airbnb:** Онлайн-площадка для размещения, поиска и краткосрочной аренды жилья.&lt;/li&gt;
&lt;li&gt;Xiaohongshu (RedNote):** Китайская социальная сеть и платформа электронной коммерции (аналог Instagram + Pinterest).&lt;/li&gt;
&lt;li&gt;Zepto:** Сервис быстрой доставки продуктов (quick commerce) из Индии.&lt;/li&gt;
&lt;li&gt;Naver:** Ведущая южнокорейская интернет-компания (поисковик, карты и др.).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Социальные сети и Медиа:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pinterest:** Фотохостинг, социальная сеть для обмена идеями.&lt;/li&gt;
&lt;li&gt;Tencent (Games &amp; LLM):** Технологический гигант, владелец WeChat, крупнейший в мире издатель видеоигр.&lt;/li&gt;
&lt;li&gt;iQiyi:** Крупная китайская платформа онлайн-видео (аналог Netflix).&lt;/li&gt;
&lt;li&gt;SmartNews:** Агрегатор новостей (популярен в Японии и США).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Финтех и Криптовалюты:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Coinbase:** Крупнейшая американская криптовалютная биржа.&lt;/li&gt;
&lt;li&gt;Intuit:** Американская компания, разработчик финансового ПО (QuickBooks, TurboTax).&lt;/li&gt;
&lt;li&gt;TRM Labs:** Блокчейн-аналитика, порядочность в криптосфере и compliance.&lt;/li&gt;
&lt;li&gt;Yuno:** Финтех-оркестратор платежей.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;B2B SaaS и Корпоративное ПО:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Airtable:** Облачный сервис для работы с базами данных и таблицами (no-code).&lt;/li&gt;
&lt;li&gt;Celonis:** Лидер в области Process Mining (анализ бизнес-процессов).&lt;/li&gt;
&lt;li&gt;Cisco:** Мировой лидер в области сетевых технологий и кибербезопасности.&lt;/li&gt;
&lt;li&gt;Demandbase:** Платформа для ABM-маркетинга (Account-Based Marketing).&lt;/li&gt;
&lt;li&gt;Eightfold.ai:** Платформа для управления талантами на базе ИИ.&lt;/li&gt;
&lt;li&gt;Freshа:** Платформа для бронирования услуг в сфере красоты и здоровья.&lt;/li&gt;
&lt;li&gt;SplitMetrics:** Платформа для A/B тестирования и оптимизации мобильных приложений.&lt;/li&gt;
&lt;li&gt;Verisoul:** Платформа для выявления фейковых пользователей и ботов.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Транспорт и Логистика:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Didi:** Китайский агрегатор такси (аналог Uber).&lt;/li&gt;
&lt;li&gt;Grab:** Супер-приложение из Юго-Восточной Азии (такси, доставка еды, платежи).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Игры:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PlaySimple Games:** Разработчик мобильных словесных игр.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Сельское хозяйство:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HerdWatch:** ПО для управления фермерскими хозяйствами.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Энергетика:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Haezoom:** Южнокорейская платформа в сфере солнечной энергетики (Energy AI).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Ритейл (Merchandise):&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Fanatics:** Мировой лидер по продаже лицензионной спортивной атрибутики.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h4&gt;2. Ранжирование по степени использования (Use Case Depth)&lt;/h4&gt;
&lt;p&gt;Это ранжирование основано на публично доступных кейсах (case studies), объемах данных и критичности систем, переведенных на StarRocks.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Уровень 1: Heavy Users / Mission Critical (Ключевые внедрения)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Эти компании заменили устаревшие хранилища данных (Snowflake, ClickHouse, Druid) на StarRocks для критически важных задач с огромными объемами данных.&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Airbnb:&lt;/b&gt; Используют StarRocks для метрик реального времени и “умного” ценообразования (Minerva). Огромные объемы данных, строгие требования к задержке.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Tencent (Games &amp; LLM):&lt;/b&gt; Один из самых масштабных пользователей. Унифицировали аналитику (заменив Hive/Spark/Druid), что позволило анализировать данные сотен игр в реальном времени.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Trip.com:&lt;/b&gt; Полностью отказались от ClickHouse и частично от Hive в пользу StarRocks для ускорения отчетов. Обрабатывают петабайты данных, высокая конкуренция запросов.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Shopee:&lt;/b&gt; Используют StarRocks для Data Service (API), ускорив запросы в 3 раза по сравнению с Presto. Критически важно для работы их E-commerce платформы.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Didi:&lt;/b&gt; Масштабное использование для логистики в реальном времени и анализа поездок.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Fanatics:&lt;/b&gt; Сократили расходы на 90%, перейдя с Snowflake на связку StarRocks + Iceberg.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Coinbase:&lt;/b&gt; Заменили Snowflake для аналитики, обращенной к клиенту (customer-facing). Требовались быстрые JOIN-ы на терабайтных масштабах, чего не давали другие системы.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;b&gt;Уровень 2: Strategic Users (Важные продуктовые внедрения)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Компании, использующие StarRocks для конкретных, высоконагруженных продуктов или функций.&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Pinterest:&lt;/b&gt; Используют для аналитики, но акцент сделан на Lakehouse-архитектуре и join-ах больших таблиц.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Xiaohongshu (RedNote):&lt;/b&gt; Аналитика поведения пользователей в реальном времени (user behavior analysis) с высочайшей кардинальностью данных.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Fresha:&lt;/b&gt; Аналитика для партнеров (салонов красоты). Важна скорость отклика дэшбордов для тысяч внешних пользователей.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Grab:&lt;/b&gt; Аналитика для супер-приложения. Замена Druid/Pinot для более гибких SQL-запросов.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Celonis:&lt;/b&gt; Использование в движке Process Mining, где требуются сложные JOIN-операции, с которыми StarRocks справляется лучше колоночных аналогов.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;b&gt;Уровень 3: Adopters (Специфические сценарии)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Компании, использующие StarRocks для внутренних BI-систем, маркетинговой аналитики или замены медленных компонентов.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Airtable, Cisco, Intuit, Zepto, PlaySimple Games:** Вероятнее всего, использование для внутренней ускоренной аналитики и BI-отчетов, где традиционные DWH стали слишком медленными или дорогими.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h4&gt;3. Ранжирование по степени влияния на проект (Contribution &amp; Influence)&lt;/h4&gt;
&lt;p&gt;StarRocks — это Open Source проект. Влияние оценивается по вкладу в код (Pull Requests), участию в техническом комитете (TSC) и архитектурном развитии.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;1. Лидеры (Архитекторы и основные контрибьюторы):&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Alibaba и Tencent:** Эти техногиганты не просто используют проект, они предоставляют огромное количество коммитов, тестируют его на экстремальных нагрузках и формируют roadmap развития. Многие фичи для “реального времени” и интеграции с Data Lake пришли благодаря требованиям и коду инженеров этих компаний.&lt;/li&gt;
&lt;li&gt;Didi:** Активные контрибьюторы в области стабильности и оптимизации планировщика запросов под высокие нагрузки.&lt;/li&gt;
&lt;li&gt;Airbnb:** Их вклад значителен в области интеграции с экосистемой данных (например, улучшения для Apache Iceberg и метрик), так как они строят сложные платформы данных (Minerva).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;2. Инноваторы (Драйверы конкретных фич):&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Trip.com:&lt;b&gt; Сильно повлияли на развитие функций для работы с **Data Lakehouse&lt;/b&gt; (прямые запросы к Hive/Iceberg без импорта данных), так как их основной кейс — отказ от миграции данных.&lt;/li&gt;
&lt;li&gt;Shopee:&lt;b&gt; Влияют на развитие функционала **Materialized Views&lt;/b&gt; (материализованных представлений), так как активно используют их для ускорения API.&lt;/li&gt;
&lt;li&gt;Pinterest и Coinbase:** Их кейсы (быстрые JOIN-ы на S3) подталкивают развитие кеширования и оптимизатора для “холодных” данных.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;3. Евангелисты (Популяризаторы):&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Celonis, Fanatics, Grab:** Активно выступают на конференциях, пишут технические блоги о миграции с конкурентов (Snowflake, Druid), тем самым привлекая новых пользователей и валидируя технологию на западном рынке.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;b&gt;ClickHouse&lt;/b&gt; — это колоночная аналитическая СУБД с открытым кодом, позволяющая выполнять аналитические запросы в режиме реального времени на структурированных больших данных. Изначально разработанная в Яндексе для Яндекс.Метрики, она стала мировым стандартом для задач логирования, телеметрии и продуктовой аналитики благодаря феноменальной скорости вставки и сжатия данных.&lt;/p&gt;
&lt;h4&gt;1. Сферы деятельности компаний&lt;/h4&gt;
&lt;p&gt;Список компаний, использующих ClickHouse, охватывает почти все отрасли, где генерируются “Big Data”.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Технологии, Интернет и Облачные сервисы:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Yandex:** Родительская компания. Поисковик, такси, e-commerce, облачные сервисы.&lt;/li&gt;
&lt;li&gt;Cloudflare:** Глобальная сеть доставки контента (CDN) и защита от DDoS.&lt;/li&gt;
&lt;li&gt;Uber:** Мировой агрегатор такси и доставки.&lt;/li&gt;
&lt;li&gt;eBay:** Один из старейших и крупнейших аукционов и маркетплейсов в мире.&lt;/li&gt;
&lt;li&gt;VK (ВКонтакте):** Крупнейшая социальная сеть в СНГ.&lt;/li&gt;
&lt;li&gt;GitLab:** Платформа для DevOps и управления жизненным циклом ПО.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Стриминг, Медиа и Развлечения:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Spotify:** Глобальный аудио-стриминговый сервис.&lt;/li&gt;
&lt;li&gt;Netflix:** Крупнейший в мире онлайн-кинотеатр (стриминг видео).&lt;/li&gt;
&lt;li&gt;Twitch:** Видеостриминговый сервис, специализирующийся на компьютерных играх.&lt;/li&gt;
&lt;li&gt;Disney+ (Disney Streaming):** Стриминговая платформа медиа-конгломерата Disney.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Финансы и Финтех:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bloomberg:** Поставщик финансовой информации для профессиональных участников рынков.&lt;/li&gt;
&lt;li&gt;Deutsche Bank:** Крупнейший банковский концерн Германии.&lt;/li&gt;
&lt;li&gt;Revolut:** Британский финтех-стартап и необанк.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Мониторинг, Observability и SaaS:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Datadog:** Платформа мониторинга и безопасности для облачных приложений.&lt;/li&gt;
&lt;li&gt;Grafana Labs:** Разработчик популярнейшей платформы визуализации данных.&lt;/li&gt;
&lt;li&gt;Sentry:** Платформа для отслеживания ошибок в приложениях.&lt;/li&gt;
&lt;li&gt;Segment (Twilio):** Платформа клиентских данных (CDP).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Телеком:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Comcast:** Крупнейшая телекоммуникационная компания США.&lt;/li&gt;
&lt;li&gt;Verizon:** Один из лидеров американского рынка мобильной связи.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;h4&gt;2. Ранжирование по степени использования (Use Case Depth)&lt;/h4&gt;
&lt;p&gt;Это ранжирование отражает масштаб данных, критичность системы для бизнеса и сложность архитектуры.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Уровень 1: Heavy Users / Hyper-scale (Экстремальные нагрузки)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Компании, обрабатывающие триллионы строк, где ClickHouse является ядром инфраструктуры.&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Cloudflare:&lt;/b&gt; Пожалуй, один из самых впечатляющих кейсов в мире. Используют ClickHouse для аналитики HTTP-трафика и DNS-запросов. Обрабатывают &lt;b&gt;десятки миллионов событий в секунду&lt;/b&gt; (более 100 млрд строк в день) для предоставления аналитики клиентам в личном кабинете.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Yandex (Метрика):&lt;/b&gt; Исторический “reference implementation”. Крупнейшая система веб-аналитики в Европе, работающая на кластерах из сотен серверов. Именно для этой нагрузки (&gt;1 триллиона строк в базе) ClickHouse и был создан.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Uber:&lt;/b&gt; Используют ClickHouse для своей платформы логирования (более 4 петабайт данных), заменив Elasticsearch в ряде задач ради экономии ресурсов и скорости.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Lyft:&lt;/b&gt; Используют для аналитики поездок и Geo-данных в реальном времени, обрабатывая огромные потоки телеметрии с автомобилей и приложений.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Bytedance (TikTok):&lt;/b&gt; (До миграции части нагрузок на другие системы) Один из крупнейших пользователей в Китае, использовавший ClickHouse для анализа поведения пользователей (User Behavior Analysis) на гигантских масштабах.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;b&gt;Уровень 2: Strategic Users (Ключевой компонент продукта)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Компании, которые строят свой основной продукт или критически важные внутренние сервисы на базе ClickHouse.&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Sentry:&lt;/b&gt; Вся аналитика ошибок и производительности в их SaaS-продукте построена на ClickHouse. Они хранят миллиарды событий ошибок, позволяя разработчикам мгновенно фильтровать их.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;GitLab:&lt;/b&gt; Используют ClickHouse для feature “Observability” внутри своего продукта, предоставляя пользователям аналитику по их CI/CD пайплайнам.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Spotify:&lt;/b&gt; Используют для внутренней аналитики экспериментов (A/B тесты) и логов воспроизведения треков.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;eBay:&lt;/b&gt; Используют для OLAP-аналитики логов приложений и мониторинга, добиваясь снижения затрат по сравнению с традиционными коммерческими решениями.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Segment:&lt;/b&gt; Платформа позволяет клиентам делать сложные выборки по аудитории, и ClickHouse здесь выступает в роли “движка” для мгновенной сегментации пользователей.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;b&gt;Уровень 3: Adopters (Специализированные задачи)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Использование для конкретных департаментов, внутренней бизнес-разведки (BI) или замены старых компонентов.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Deutsche Bank:** Анализ рыночных тиков и высокочастотная финансовая аналитика.&lt;/li&gt;
&lt;li&gt;Comcast:** Мониторинг качества видеопотока и сети.&lt;/li&gt;
&lt;li&gt;Bloomberg:** Аналитика взаимодействия пользователей с терминалом Bloomberg.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;h4&gt;3. Ранжирование по степени влияния на проект (Contribution &amp; Influence)&lt;/h4&gt;
&lt;p&gt;ClickHouse имеет огромное сообщество. Влияние оценивается не только по использованию, но и по вкладу в кодовую базу (PR), разработке драйверов и организации митапов.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;1. Создатели и Архитекторы:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ClickHouse Inc:** После выделения в отдельную компанию в 2021 году, основные разработчики (включая Алексея Миловидова) работают здесь. Именно они определяют roadmap, развивают ClickHouse Cloud и ядро системы.&lt;/li&gt;
&lt;li&gt;Yandex:** Исторический создатель. До сих пор вносят огромный вклад, поддерживают свои форки и используют систему на пределе возможностей, что помогает выявлять баги производительности.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;2. Технологические Партнеры и Контрибьюторы:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cloudflare:** Внесли огромный вклад в оптимизацию работы с сетью, TLS и безопасность, так как их требования к защищенности и нагрузке экстремальны. Часто пишут глубокие технические статьи о внутренностях ClickHouse.&lt;/li&gt;
&lt;li&gt;Altinity:** Компания, оказывающая консалтинг и поддержку ClickHouse. Сделали огромный вклад в экосистему Kubernetes (ClickHouse Operator), драйверы и интеграцию с экосистемой Hadoop/MySQL.&lt;/li&gt;
&lt;li&gt;Contentsquare:** Активно участвуют в оптимизации ядра для специфических аналитических функций (session analysis).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;3. Евангелисты Экосистемы:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Uber и Lyft:** Публикуют детальные инженерные блоги о том, как переводить логирование с ELK стека на ClickHouse, чем вдохновили сотни других компаний на миграцию.&lt;/li&gt;
&lt;li&gt;Grafana Labs:** Разрабатывают и поддерживают официальный плагин ClickHouse для Grafana, делая СУБД доступной для визуализации миллионам пользователей.&lt;/li&gt;
&lt;/ul&gt;
</description>
</item>

<item>
<title>R2 SQL: Глубокое погружение в наш новый движок для распределенных запросов</title>
<guid isPermaLink="false">319</guid>
<link>https://gavrilov.info/all/r2-sql-glubokoe-pogruzhenie-v-nash-novy-dvizhok-dlya-raspredelen/</link>
<pubDate>Wed, 18 Feb 2026 21:56:56 +0300</pubDate>
<author></author>
<comments>https://gavrilov.info/all/r2-sql-glubokoe-pogruzhenie-v-nash-novy-dvizhok-dlya-raspredelen/</comments>
<description>
&lt;h4&gt;Введение&lt;/h4&gt;
&lt;p&gt;В современном мире объемы данных растут экспоненциально, и хранение петабайтов информации в объектных хранилищах (как Amazon S3 или Cloudflare R2) стало стандартом. Однако просто хранить данные мало — их нужно анализировать. Традиционно для этого требовалось поднимать сложные кластеры (например, Spark или Trino), что долго и дорого.&lt;/p&gt;
&lt;p&gt;Компания Cloudflare представила &lt;b&gt;R2 SQL&lt;/b&gt; — бессерверный (serverless) движок, который позволяет выполнять SQL-запросы прямо к данным, лежащим в объектном хранилище R2, без необходимости управлять инфраструктурой. Эта статья подробно описывает архитектуру этого решения: как они добились высокой скорости, используя формат таблиц Apache Iceberg, умное планирование запросов и свою глобальную сеть.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://blog.cloudflare.com/r2-sql-deep-dive/"&gt;Ссылка на оригинал статьи&lt;/a&gt; А ранее я уже писал про их анонс тут &lt;a href="https://gavrilov.info/all/cloudflare-anonsiruet-platformu-dannyh/"&gt;https://gavrilov.info/all/cloudflare-anonsiruet-platformu-dannyh/&lt;/a&gt;&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/Snimok-ekrana-2026-02-18-v-21.51.06.png" width="1582" height="540" alt="" /&gt;
&lt;/div&gt;
&lt;hr /&gt;
&lt;h4&gt;R2 SQL: Глубокое погружение в наш новый движок для распределенных запросов&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;Авторы:&lt;/b&gt; Yevgen Safronov, Nikita Lapkov, Jérôme Schneider. ( Привет Никита и Евген :)&lt;/p&gt;
&lt;p&gt;Как выполнить SQL-запросы над петабайтами данных… без сервера?&lt;br /&gt;
У нас есть ответ: &lt;b&gt;R2 SQL&lt;/b&gt;, бессерверный движок запросов, который может просеивать огромные наборы данных и возвращать результаты за секунды.&lt;/p&gt;
&lt;p&gt;В этом посте подробно описывается архитектура и методы, которые делают это возможным. Мы пройдемся по нашему &lt;b&gt;Планировщику запросов&lt;/b&gt; (Query Planner), который использует `R2 Data Catalog` для отсечения терабайтов данных еще до чтения первого байта, и объясним, как мы распределяем работу по глобальной сети Cloudflare, используя `Workers` и `R2` для массивного параллельного выполнения.&lt;/p&gt;
&lt;h5&gt;От каталога к запросу&lt;/h5&gt;
&lt;p&gt;Во время Developer Week 2025 мы запустили `R2 Data Catalog` — управляемый каталог `Apache Iceberg`, встроенный непосредственно в ваш бакет Cloudflare R2. Iceberg — это открытый формат таблиц, который предоставляет критически важные функции баз данных (такие как транзакции и эволюция схемы) для объектного хранилища петабайтного масштаба. Он дает вам надежный каталог ваших данных, но сам по себе не предоставляет способа их запрашивать.&lt;/p&gt;
&lt;p&gt;До сих пор чтение вашего каталога `R2 Data Catalog` требовало настройки отдельного сервиса, такого как `Apache Spark` или Trino. Эксплуатация этих движков в большом масштабе непроста: вам нужно создавать кластеры, управлять использованием ресурсов и отвечать за их доступность — ничто из этого не способствует главной цели: получению ценности из ваших данных.&lt;/p&gt;
&lt;p&gt;`R2 SQL` полностью устраняет этот этап. Это бессерверный движок запросов, который выполняет SQL-запросы на чтение (retrieval) к вашим таблицам Iceberg прямо там, где живут ваши данные.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;поясненИИе: Что такое Apache Iceberg?&lt;/b&gt;&lt;/summary&gt;&lt;/p&gt;
&lt;p&gt;Представьте, что у вас есть огромная куча файлов (CSV, Parquet, JSON) в облачном хранилище. Это “озеро данных”. Проблема в том, что если вы начнете менять один файл, пока кто-то другой его читает, все сломается. Трудно понять, какая версия данных актуальна.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Apache Iceberg&lt;/b&gt; — это слой управления поверх этих файлов. Он работает как библиотекарь: он не хранит сами книги (данные), но ведет идеальный учет (метаданные). Он точно знает: “Таблица ‘Пользователи’ сейчас состоит из вот этих 100 файлов”.&lt;br /&gt;
Это позволяет делать с обычными файлами в облаке то, что раньше умели только дорогие базы данных:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;ACID-транзакции:&lt;/b&gt; Гарантия того, что данные не запишутся “наполовину”.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Time Travel:&lt;/b&gt; Возможность сделать запрос “Как выглядела таблица вчера в 14:00?”.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Ecosystem:&lt;/b&gt; Единый стандарт, который понимают разные инструменты аналитики.&lt;/li&gt;
&lt;/ol&gt;
&lt;h5&gt;Проектирование движка запросов для петабайтов&lt;/h5&gt;
&lt;p&gt;Объектное хранилище фундаментально отличается от хранилища традиционной базы данных. База данных структурирована по своей природе; `R2 `— это океан объектов, где одна логическая таблица может состоять из миллионов отдельных файлов, больших и маленьких, и новые поступают каждую секунду.&lt;/p&gt;
&lt;p&gt;Apache Iceberg предоставляет мощный слой логической организации поверх этой реальности. Он работает, управляя состоянием таблицы как неизменяемой серией мгновенных снимков (snapshots), создавая надежное, структурированное представление таблицы путем манипулирования “легкими” файлами метаданных вместо перезаписи самих файлов данных.&lt;/p&gt;
&lt;p&gt;Однако эта логическая структура не меняет физической проблемы, лежащей в основе: эффективный движок запросов всё равно должен найти конкретные данные, необходимые ему, в этой огромной коллекции файлов. Это требует преодоления двух основных технических барьеров:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Проблема ввода-вывода (I/O problem):&lt;/b&gt; Главная проблема эффективности запросов — минимизация объема данных, считываемых из хранилища. Подход “в лоб” с чтением каждого объекта просто нежизнеспособен. Основная цель — читать только те данные, которые абсолютно необходимы.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Проблема вычислений (Compute problem):&lt;/b&gt; Объем данных, которые *действительно* нужно прочитать, все равно может быть огромным. Нам нужен способ выделить запросу, который может быть массивным, необходимое количество вычислительной мощности всего на несколько секунд, а затем мгновенно снизить его до нуля, чтобы избежать лишних трат.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Наша архитектура для `R2 SQL` разработана для решения этих двух проблем с помощью двухэтапного подхода: &lt;b&gt;Планировщик запросов&lt;/b&gt; (Query Planner), который использует метаданные для интеллектуального отсечения (pruning) пространства поиска, и система &lt;b&gt;Выполнения запросов&lt;/b&gt; (Query Execution), которая распределяет работу по глобальной сети Cloudflare для параллельной обработки данных.&lt;/p&gt;
&lt;h5&gt;Планировщик запросов (Query Planner)&lt;/h5&gt;
&lt;p&gt;Самый эффективный способ обработки данных — не читать их вовсе. Это ключевая стратегия планировщика `R2 SQL`. Вместо исчерпывающего сканирования каждого файла планировщик использует структуру метаданных, предоставляемую каталогом `R2 Data Catalog`, чтобы “подрезать” пространство поиска, то есть избежать чтения огромных массивов данных, не относящихся к запросу.&lt;/p&gt;
&lt;p&gt;Это расследование “сверху вниз”, где планировщик перемещается по иерархии слоев метаданных Iceberg, используя статистику (&lt;b&gt;stats&lt;/b&gt;) на каждом уровне для построения быстрого плана, точно указывающего, какие диапазоны байтов должен прочитать движок.&lt;/p&gt;
&lt;h6&gt;Что мы подразумеваем под “статистикой”?&lt;/h6&gt;
&lt;p&gt;Когда мы говорим, что планировщик использует “статы”, мы имеем в виду сводные метаданные, которые Iceberg хранит о содержимом файлов данных. Эта статистика создает грубую карту данных, позволяя планировщику принимать решения о том, какие файлы читать, а какие игнорировать, даже не открывая их.&lt;/p&gt;
&lt;p&gt;Есть два основных уровня статистики, которые планировщик использует для отсечения (pruning):&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Статистика уровня раздела (Partition-level stats):&lt;/b&gt; Хранится в списке манифестов (manifest list) Iceberg. Эти статы описывают диапазон значений разделов для всех данных в определенном файле манифеста Iceberg. Для раздела по `day(event_timestamp)` это будут самый ранний и самый поздний дни, присутствующие в файлах, отслеживаемых этим манифестом.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Статистика уровня столбца (Column-level stats):&lt;/b&gt; Хранится в файлах манифестов. Это более детальная статистика о каждом отдельном файле данных. Файлы данных в `R2 Data Catalog` отформатированы с использованием `Apache Parquet`. Для каждого столбца файла Parquet манифест хранит ключевую информацию, такую как:
&lt;ul&gt;
  &lt;li&gt;Минимальное и максимальное значения. Если запрос запрашивает `http_status = 500`, а статистика файла показывает, что в столбце `http_status` минимум 200 и максимум 404, этот файл можно пропустить целиком.&lt;/li&gt;
  &lt;li&gt;Количество null-значений. Это позволяет планировщику пропускать файлы, когда запрос ищет конкретно non-null значения (например, `WHERE error_code IS NOT NULL`), а метаданные файла сообщают, что все значения для `error_code` являются null.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h6&gt;Отсечение пространства поиска (Pruning)&lt;/h6&gt;
&lt;p&gt;Процесс отсечения — это расследование “сверху вниз”, которое происходит в три основных этапа:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Метаданные таблицы и текущий снимок (snapshot):&lt;/b&gt;  &lt;br /&gt;
Планировщик начинает с запроса к каталогу о местоположении текущих метаданных таблицы. Это JSON-файл, содержащий текущую схему таблицы, спецификации разделов и журнал всех исторических снимков. Затем планировщик выбирает последний снимок для работы.&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;b&gt;Список манифестов и отсечение разделов:&lt;/b&gt;  &lt;br /&gt;
Текущий снимок указывает на единый *список манифестов* (manifest list) Iceberg. Планировщик читает этот файл и использует статистику уровня разделов для каждой записи, чтобы выполнить первый, самый мощный шаг отсечения, отбрасывая любые манифесты, чьи диапазоны значений разделов не удовлетворяют запросу. Например, для таблицы, партиционированной по дням, планировщик может отбросить манифесты за ненужные даты.&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;b&gt;Манифесты и отсечение на уровне файлов:&lt;/b&gt;  &lt;br /&gt;
Для оставшихся манифестов планировщик читает каждый из них, чтобы получить список фактических файлов данных Parquet. Эти файлы манифестов содержат более детальную статистику уровня столбцов. Это позволяет выполнить второй шаг отсечения, отбрасывая целые файлы данных, которые не могут содержать строки, соответствующие фильтрам запроса.&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="4"&gt;
&lt;li&gt;&lt;b&gt;Отсечение групп строк (Row-group pruning) внутри файла:&lt;/b&gt;  &lt;br /&gt;
Наконец, для конкретных файлов данных, которые всё еще являются кандидатами, Планировщик использует статистику, хранящуюся внутри *футеров* (footers) файлов Parquet, чтобы пропускать целые группы строк (row groups).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Результатом этого многослойного отсечения является точный список файлов Parquet и групп строк внутри этих файлов. Они становятся рабочими единицами (work units), которые отправляются в систему Выполнения запросов.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;поясненИИе: Формат Parquet и Row Groups&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Apache Parquet&lt;/b&gt; — это колоночный формат хранения данных. В отличие от CSV, где данные хранятся строка за строкой, в Parquet данные хранятся столбец за столбцом. Это идеально для аналитики (когда вам нужно посчитать среднее по одной колонке, не читая остальные 50).&lt;/p&gt;
&lt;p&gt;Внутри себя файл Parquet делится на &lt;b&gt;Row Groups&lt;/b&gt; (группы строк). Представьте файл на 1 миллион строк. Он может быть разбит на 10 групп по 100,000 строк. У каждой группы есть свой мини-заголовок со статистикой (min/max значения).&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Пример:&lt;/b&gt; Вы ищете `id = 950,000`.&lt;br /&gt;
Движок читает футер файла и видит:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Row Group 1: id 1-100,000 -&gt; Пропускаем.&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;li&gt;Row Group 10: id 900,001-1,000,000 -&gt; &lt;b&gt;Читаем только эту часть файла&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Это называется “I/O skipping” и экономит огромное количество времени и денег на трафике.&lt;/p&gt;
&lt;h5&gt;Конвейер планирования (The Planning pipeline)&lt;/h5&gt;
&lt;p&gt;В `R2 SQL` описанное выше многослойное отсечение не является монолитным процессом. Для таблицы с миллионами файлов метаданные могут быть слишком большими, чтобы обработать их полностью до начала реальной работы. Ожидание полного плана внесет значительную задержку (latency).&lt;/p&gt;
&lt;p&gt;Вместо этого `R2 SQL` рассматривает планирование и выполнение как единый конкурентный конвейер (pipeline). Работа планировщика — производить поток рабочих единиц (work units), которые исполнитель (executor) потребляет, как только они становятся доступны.&lt;/p&gt;
&lt;h6&gt;Начало выполнения как можно раньше&lt;/h6&gt;
&lt;p&gt;С этого момента запрос обрабатывается в потоковом режиме. По мере того как Планировщик читает файлы манифестов (и, следовательно, файлы данных, на которые они указывают) и отсекает их, он немедленно отправляет любые подходящие файлы данных/группы строк как рабочие единицы в очередь выполнения.&lt;/p&gt;
&lt;p&gt;Такая конвейерная структура гарантирует, что вычислительные узлы могут начать дорогую работу по вводу-выводу данных практически мгновенно, задолго до того, как планировщик закончит свое полное расследование.&lt;/p&gt;
&lt;p&gt;На вершине этой модели конвейера планировщик добавляет критически важную оптимизацию: &lt;b&gt;преднамеренное упорядочивание&lt;/b&gt; (deliberate ordering). Файлы манифестов не стримятся в случайной последовательности. Вместо этого планировщик обрабатывает их в порядке, соответствующем условию `ORDER BY` вашего запроса, руководствуясь статистикой метаданных. Это гарантирует, что данные, которые с наибольшей вероятностью содержат желаемые результаты, обрабатываются первыми.&lt;/p&gt;
&lt;h6&gt;Ранняя остановка: как закончить, не читая всё&lt;/h6&gt;
&lt;p&gt;Благодаря тому, что Планировщик передает рабочие единицы в порядке, соответствующем `ORDER BY`, система выполнения сначала обрабатывает данные, которые с наибольшей вероятностью попадут в итоговый набор результатов.&lt;/p&gt;
&lt;p&gt;Например, для запроса типа `... ORDER BY timestamp DESC LIMIT 5`: по мере того как движок выполнения обрабатывает рабочие единицы и отправляет результаты обратно, планировщик одновременно делает две вещи:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Поддерживает ограниченную “кучу” (heap) из лучших 5 результатов, увиденных на данный момент.&lt;/li&gt;
&lt;li&gt;Следит за “ватерлинией” (high-water mark) самого потока. Благодаря метаданным он всегда знает абсолютно самый поздний `timestamp` любого файла данных, который *еще не был* обработан.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;В момент, когда самая старая временная метка в нашей “Топ-5 куче” оказывается новее, чем “ватерлиния” оставшегося потока (максимально возможная дата в еще не прочитанных файлах), &lt;b&gt;весь запрос может быть остановлен&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;В этот момент мы можем доказать, что ни одна оставшаяся рабочая единица не может содержать результат, который попал бы в топ-5. Конвейер останавливается, и пользователю возвращается полный, корректный результат, часто после чтения лишь крошечной доли потенциально подходящих данных.&lt;/p&gt;
&lt;hr /&gt;
&lt;h5&gt;Выполнение запросов (Query Execution)&lt;/h5&gt;
&lt;p&gt;Планировщик передает работу кусочками, называемыми &lt;b&gt;Row Groups&lt;/b&gt;. Сервер, который получает запрос пользователя, берет на себя роль &lt;b&gt;координатора запроса&lt;/b&gt;. Он распределяет работу между &lt;b&gt;воркерами&lt;/b&gt; (query workers) и агрегирует результаты.&lt;/p&gt;
&lt;p&gt;Сеть Cloudflare огромна. Координатор связывается с внутренним API Cloudflare, чтобы убедиться, что для выполнения выбираются только здоровые серверы. Соединения между координатором и воркерами проходят через `Cloudflare Argo Smart Routing` для обеспечения быстрой и надежной связи.&lt;/p&gt;
&lt;p&gt;Серверы, получающие задачи от координатора, становятся воркерами. Они служат точкой горизонтального масштабирования в `R2 SQL`. При большем количестве воркеров `R2 SQL` может обрабатывать запросы быстрее, распределяя работу между множеством серверов. Это особенно актуально для запросов, охватывающих большие объемы файлов.&lt;/p&gt;
&lt;h6&gt;Внутреннее устройство: Apache DataFusion&lt;/h6&gt;
&lt;p&gt;Внутри каждый воркер использует `Apache DataFusion` для выполнения SQL-запросов к группам строк. `DataFusion` — это аналитический движок запросов с открытым исходным кодом, написанный на &lt;b&gt;Rust&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;Разделы (partitions) в `DataFusion` идеально ложатся на модель данных `R2 SQL`, поскольку каждая группа строк (row group) может рассматриваться как независимый раздел. Благодаря этому каждая группа строк обрабатывается параллельно.&lt;br /&gt;
Поскольку группы строк обычно содержат как минимум 1000 строк, `R2 SQL` выигрывает от &lt;b&gt;векторизованного выполнения&lt;/b&gt;. Каждый поток DataFusion может выполнять SQL-запрос сразу на множестве строк за один проход, амортизируя накладные расходы на интерпретацию запроса.&lt;/p&gt;
&lt;h6&gt;Поддержка Parquet и Arrow&lt;/h6&gt;
&lt;p&gt;`DataFusion` имеет первоклассную поддержку Parquet. Используя ranged reads (чтение диапазонов) в R2, он способен считывать только части файлов Parquet, содержащие запрошенные столбцы, пропуская остальные.&lt;/p&gt;
&lt;p&gt;Оптимизатор `DataFusion` также позволяет нам “проталкивать” фильтры (push down filters) на самые низкие уровни плана запроса. Другими словами, мы можем применять фильтры прямо в момент чтения значений из файлов Parquet.&lt;/p&gt;
&lt;p&gt;Когда воркер заканчивает вычисления, он возвращает результаты координатору через протокол &lt;b&gt;gRPC&lt;/b&gt;. `R2 SQL` использует `Apache Arrow` для внутреннего представления результатов. Это формат в оперативной памяти (in-memory), который эффективно представляет массивы структурированных данных. Arrow также определяет формат сериализации `Arrow IPC`, который идеально подходит для передачи данных между процессами по сети.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;поясненИИе: Векторизация и Apache Arrow&lt;/b&gt;&lt;/summary&gt;&lt;br /&gt;
&lt;b&gt;Векторизованное выполнение (Vectorized execution):&lt;/b&gt; Традиционные базы данных обрабатывали одну строку за раз (Row-at-a-time). Это медленно, потому что процессор постоянно переключается. Векторизация означает обработку данных “пачками” (например, сложить сразу 1000 чисел из колонки А с 1000 чисел из колонки Б). Это использует современные возможности CPU (SIMD инструкции) и работает в разы быстрее.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Apache Arrow:&lt;/b&gt; Это стандарт того, как хранить эти “пачки” данных в оперативной памяти, чтобы процессору было максимально удобно их читать.&lt;br /&gt;
Главный плюс Arrow: &lt;b&gt;Zero-copy&lt;/b&gt;. Если один инструмент (DataFusion) передает данные другому (по сети координатору), и оба понимают Arrow, им не нужно тратить время на перекодирование (сериализацию/десериализацию) данных. Они просто “передают указатель” или копируют сырые байты как есть.&lt;/p&gt;
&lt;h5&gt;Будущие планы&lt;/h5&gt;
&lt;p&gt;Хотя `R2 SQL` и так хорош в фильтрации, мы планируем быстро добавлять новые возможности:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Поддержка сложных агрегаций (GROUP BY) в распределенном и масштабируемом виде.&lt;/li&gt;
&lt;li&gt;Инструменты для визуализации выполнения запросов (explain analyze), чтобы помочь разработчикам улучшать производительность.&lt;/li&gt;
&lt;li&gt;Поддержка многих конфигурационных опций Apache Iceberg.&lt;/li&gt;
&lt;li&gt;Возможность запрашивать каталоги прямо из панели управления Cloudflare (Dashboard).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Мы также исследуем различные виды индексов, чтобы сделать запросы еще быстрее, и планируем добавить полнотекстовый поиск, геопространственные запросы и многое другое.&lt;/p&gt;
&lt;h5&gt;Попробуйте сейчас!&lt;/h5&gt;
&lt;p&gt;Это ранние дни для `R2 SQL`, но он уже доступен в открытой бете! Переходите к нашему руководству по началу работы, чтобы создать сквозной конвейер данных. Мы ждем вашей обратной связи в нашем Discord для разработчиков.&lt;/p&gt;
&lt;p&gt;***&lt;/p&gt;
&lt;h4&gt;Итог и СоображенИИя&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;Итог:&lt;/b&gt; Cloudflare выпустила мощный инструмент, который превращает их объектное хранилище (R2) в полноценную аналитическую базу данных. Используя открытые стандарты (Iceberg, Parquet, Arrow, DataFusion) и свою глобальную сеть периферийных вычислений (Edge), они решили главную проблему Big Data — необходимость платить за простой серверов. Здесь вы платите только за время выполнения конкретного SQL-запроса.&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; Cloudflare делает с Big Data то же, что ранее сделала с CDN и защитой от DDoS — делает сложные энтерпрайз-технологии доступными “по кнопке”. Использование открытого стека (Rust + Arrow + DataFusion) — это сейчас золотой стандарт построения современных СУБД (по этому пути идут такие гиганты как InfluxDB 3.0, LanceDB и др.). Cloudflare не изобретает велосипед, а собирает очень быструю ракету из лучших деталей.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Убийца Snowflake/Databricks для “бедных”?&lt;/b&gt; Для огромных корпораций Snowflake и Databricks останутся стандартом из-за богатого функционала. Но для стартапов и среднего бизнеса, у которых данные лежат в R2 (чтобы не платить за egress трафик AWS), появление R2 SQL делает переезд на сторонние аналитические платформы бессмысленным. Зачем гонять данные туда-сюда, если можно выполнить SQL прямо “на месте”?&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Синергия с ИИ:&lt;/b&gt; Упоминание планов на “индексы” и “геопространственные запросы” намекает на векторный поиск в будущем. Если Cloudflare добавит возможность делать векторный поиск по данным в R2 так же нативно, это станет киллер-фичей для всех, кто строит RAG (Retrieval-Augmented Generation) приложения на базе LLM. Хранишь документы в R2 -&gt; R2 SQL ищет контекст -&gt; Workers AI генерируют ответ. Весь цикл внутри одной экосистемы с минимальными задержками.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Еще можно почитать про &lt;a href="https://vegafusion.io"&gt;https://vegafusion.io&lt;/a&gt; и про формат &lt;a href="https://lance.org"&gt;https://lance.org&lt;/a&gt; – он как раз и добавит векторочков.&lt;/p&gt;
</description>
</item>

<item>
<title>Data Stack 2.0: Закат Lambda-архитектуры и восход Fluss с Lance</title>
<guid isPermaLink="false">317</guid>
<link>https://gavrilov.info/all/data-stack-2-0-zakat-lambda-arhitektury-i-voshod-fluss-s-lance/</link>
<pubDate>Fri, 13 Feb 2026 01:59:35 +0300</pubDate>
<author></author>
<comments>https://gavrilov.info/all/data-stack-2-0-zakat-lambda-arhitektury-i-voshod-fluss-s-lance/</comments>
<description>
&lt;h2&gt;Data Stack 2.0: Закат Lambda-архитектуры и восход Fluss с Lance&lt;/h2&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/Snimok-ekrana-2026-02-13-v-01.58.40.png" width="1796" height="340" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;В мире инфраструктуры данных происходит “тектонический сдвиг”, описанный в отчетах &lt;a href="https://a16z.com/emerging-architectures-for-modern-data-infrastructure/"&gt;a16z.com&lt;/a&gt;. Индустрия отходит от сложной Lambda-архитектуры (где batch и streaming живут отдельно) к унифицированным решениям, которые называют &lt;b&gt;Streamhouse&lt;/b&gt;.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/Snimok-ekrana-2026-02-13-v-01.59.13.png" width="1476" height="412" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Два ключевых игрока, меняющих правила игры в этом переходе:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Apache Fluss&lt;/b&gt; — управляемое хранилище для потоковой обработки (Streaming Storage).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Lance&lt;/b&gt; — формат данных нового поколения для AI и Data Lake.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;1. Проблема: Почему одной Kafka больше недостаточно?&lt;/h3&gt;
&lt;p&gt;Долгое время Apache Kafka была стандартом де-факто для передачи данных. Однако, как отмечают эксперты Ververica в статье &lt;a href="https://www.ververica.com/blog/a-world-without-kafka"&gt;Мир без Kafka&lt;/a&gt;, Kafka была спроектирована как *распределенный лог*, а не как база данных.&lt;/p&gt;
&lt;p&gt;Перевод есть тут, у меня: &lt;a href="https://gavrilov.info/all/mir-bez-kafka-pochemu-kafka-ne-podhodit-dlya-analitiki-realnogo/"&gt;https://gavrilov.info/all/mir-bez-kafka-pochemu-kafka-ne-podhodit-dlya-analitiki-realnogo/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Фундаментальные ограничения брокеров сообщений (Kafka/Pulsar) для аналитики:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Слабая работа с обновлениями (Updates):&lt;/b&gt; Kafka — это `append-only` система. Реализация `UPDATE` или `DELETE` требует использования *Compact Topics*, что не дает гарантий мгновенной консистентности и сложно в эксплуатации.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Медленное чтение истории:&lt;/b&gt; Чтобы найти запись годичной давности, вам часто нужно прочитать весь лог последовательно (Scan). Сложность операции — $O(N)$.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Row-based природа:&lt;/b&gt; Данные хранятся строками (Message bytes). Для аналитики (OLAP), где нам нужен средний чек по столбцу `price`, системе приходится распаковывать и читать *все* поля сообщения, что неэффективно.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. Apache Fluss: Недостающее звено для Flink&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://fluss.apache.org"&gt;Apache Fluss&lt;/a&gt; создан, чтобы решить проблему “разделения” между потоком и таблицей. Это нативное хранилище для Apache Flink, которое поддерживает &lt;a href="https://www.ververica.com/blog/introducing-fluss"&gt;концепцию Fluss&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Архитектурные прорывы:&lt;/h4&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Гибридная модель чтения (Stream-Table Duality):&lt;/b&gt; Fluss позволяет читать данные и как бесконечный поток (Log), и как изменяемую таблицу с первичными ключами (Primary Key Table). Это делает реализацию &lt;b&gt;CDC (Change Data Capture)&lt;/b&gt; тривиальной: обновления перезаписывают старые значения по ключу.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Колоночная проекция (Columnar Projection):&lt;/b&gt; В отличие от Kafka, Fluss может отдавать аналитическому движку (Flink) только нужные колонки. Это снижает нагрузку на сеть (`I/O`) в разы.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Real-Time Lookups:&lt;/b&gt; Fluss поддерживает точечные запросы (Point Lookup) по первичному ключу с задержкой порядка миллисекунд.  &lt;br /&gt;
$$Latency_{Fluss} \ll Latency_{Kafka Scan}$$  &lt;br /&gt;
Это позволяет использовать его как *Serverless State* для приложений, избавляясь от необходимости ставить рядом Redis или RocksDB.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Tiered Storage в Data Lake:&lt;/b&gt; Fluss работает в паре с &lt;b&gt;Apache Paimon&lt;/b&gt; (ранее Flink Table Store). Горячие данные живут в Fluss (на быстрых дисках/RAM), а по мере устаревания автоматически конвертируются в формат Lakehouse (Paimon/Parquet/ ну или Iceberg) и уходят в S3.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;3. Lance: Новый стандарт для AI в Data Lake&lt;/h3&gt;
&lt;p&gt;Если Fluss отвечает за доставку и горячее состояние, то &lt;b&gt;Lance&lt;/b&gt; меняет подход к хранению холодных данных для задач машинного обучения (ML).&lt;/p&gt;
&lt;p&gt;Традиционный формат &lt;b&gt;Parquet&lt;/b&gt; великолепен для аналитики (сканирование больших диапазонов), но ужасен для AI, где требуется &lt;b&gt;случайный доступ (Random Access)&lt;/b&gt; для формирования батчей обучения.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://lance.org"&gt;Lance&lt;/a&gt; решает эти проблемы:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Случайный доступ:** Lance позволяет извлекать строки по индексу в ~100 раз быстрее Parquet.&lt;/li&gt;
&lt;li&gt;Векторный поиск:** Это формат со встроенным векторным индексом (IVF-PQ). Вы можете хранить эмбеддинги прямо в файлах на S3 и выполнять поиск ближайших соседей (ANN) без отдельной VectorDB (вроде Pinecone или Milvus).&lt;/li&gt;
&lt;li&gt;Zero-Copy версионирование:** Эффективное управление версиями датасетов без дублирования данных.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;4. Сборка пазла: Как это работает вместе&lt;/h3&gt;
&lt;p&gt;Современный &lt;b&gt;Streamhouse&lt;/b&gt; (см. &lt;a href="https://bigdataschool.ru/blog/news/flink/fluss-for-flink/"&gt;примеры архитектуры]&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;выглядит как-то так:&lt;/p&gt;
&lt;p&gt;Схема потока данных (Workflow):&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Ingestion:&lt;/b&gt;  &lt;br /&gt;
Приложения (на Go, Java, Python) пишут данные.&lt;/li&gt;

&lt;ul&gt;
  &lt;li&gt;Важно:* Поскольку Fluss совместим с протоколом Kafka, можно использовать существующие &lt;b&gt;Kafka-клиенты&lt;/b&gt; в Go-сервисах для записи в Fluss, не дожидаясь нативных библиотек. Но это пока только теория. Сходу я не нашел примеров быстро, но можно использовать GO и Arrow Flight SQL.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;b&gt;Streaming Storage (Fluss):&lt;/b&gt;  &lt;br /&gt;
Fluss принимает данные, индексирует первичные ключи и хранит “горячее” окно (например, 24 часа).&lt;/li&gt;

&lt;ul&gt;
  &lt;li&gt;Flink* выполняет `JOIN` и агрегации прямо поверх Fluss, используя `Lookup Join` (обогащение данных без сохранения большого стейта внутри Flink).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;b&gt;Archiving &amp; AI (Paimon/Lance):&lt;/b&gt;  &lt;br /&gt;
Исторические данные сбрасываются в S3.&lt;/li&gt;

&lt;ul&gt;
  &lt;li&gt;Для классической BI-аналитики используется формат &lt;b&gt;Apache Paimon&lt;/b&gt; или Iceberg.&lt;/li&gt;
  &lt;li&gt;Для ML-задач данные конвертируются или хранятся в &lt;b&gt;Lance&lt;/b&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="4"&gt;
&lt;li&gt;&lt;b&gt;Unified Analytics (Trino):&lt;/b&gt;  &lt;br /&gt;
Движок &lt;a href="https://lance.org/integrations/trino/config/"&gt;Trino&lt;/a&gt; позволяет делать SQL-запросы ко всем слоям одновременно. Аналитик пишет один `SELECT`, а Trino забирает свежие данные из Fluss, а исторические — из S3 (Lance/Parquet/iceberg).&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Пример интеграции (концептуальный)&lt;/h4&gt;
&lt;p&gt;Поскольку прямого клиента Go для Fluss нет, использование в микросервисах чаще всего выглядит как работа через Kafka-протокол или HTTP-прокси, а основная логика ложится на Flink (Java/Python/ или еще чего):&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;// Flink SQL example: Создание таблицы, управляемой Fluss
CREATE TABLE user_behavior (
    user_id BIGINT,
    item_id BIGINT,
    action STRING,
    ts TIMESTAMP(3),
    PRIMARY KEY (user_id) NOT ENFORCED
) WITH (
    'connector' = 'fluss',
    'bootstrap.servers' = '...:9092', // Fluss совместим с Kafka-адресацией
    'table.log.consistency' = 'eventual' // Оптимизация под высокую пропускную способность
);&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Надо пробовать и тестировать... все таки еще инкубационный и это только теория.&lt;/p&gt;
&lt;h3&gt;5. Выводы и рекомендации&lt;/h3&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Не используйте Kafka как базу данных.&lt;/b&gt; Если вашей архитектуре требуются частые обновления (`UPSERT`) и точечные запросы (`Lookup`), &lt;a href="https://fluss.apache.org"&gt;Apache Fluss&lt;/a&gt; — это более подходящий инструмент в экосистеме Flink.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Lance для AI.&lt;/b&gt; Если вы строите RAG (Retrieval-Augmented Generation) или RecSys, рассмотрите формат Lance вместо связки “Parquet + внешняя VectorDB”. Это упростит инфраструктуру.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Следите за совместимостью.&lt;/b&gt; Интеграции Lance с Trino и Fluss с не-JVM языками (например, Go, Rust или еще чего) находятся в активной разработке. Используйте проверенные пути (Kafka Protocol для Ingestion, DataFusion/Java/Python для Querying).&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Полезные ресурсы для изучения:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://a16z.com/emerging-architectures-for-modern-data-infrastructure/"&gt;Emerging Architectures for Modern Data Infrastructure (a16z&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.ververica.com/blog/introducing-fluss"&gt;Introducing Fluss (Ververica&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bigdataschool.ru/blog/news/flink/fluss-for-flink/"&gt;Fluss for Flink (BigDataSchool&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/lance-format/lance-trino/issues/29#issuecomment-3893178604"&gt;Lance &amp; Trino Integration Issue (GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
</item>

<item>
<title>Мир без Kafka: Почему Kafka не подходит для аналитики реального времени, что идет на смену)</title>
<guid isPermaLink="false">318</guid>
<link>https://gavrilov.info/all/mir-bez-kafka-pochemu-kafka-ne-podhodit-dlya-analitiki-realnogo/</link>
<pubDate>Thu, 12 Feb 2026 13:50:00 +0300</pubDate>
<author></author>
<comments>https://gavrilov.info/all/mir-bez-kafka-pochemu-kafka-ne-podhodit-dlya-analitiki-realnogo/</comments>
<description>
&lt;p&gt;Статья описывает переход от традиционных систем обмена сообщениями, таких как Apache Kafka, к специализированным решениям для потоковой аналитики, таким как &lt;b&gt;Apache Fluss&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;Основные тезисы:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Проблема Kafka:&lt;/b&gt; Kafka — это система хранения на основе *записей* (record-based), не имеющая нативной поддержки схем и аналитических возможностей. Это приводит к избыточному чтению данных и перегрузке сети при аналитических запросах, когда нужны только конкретные колонки, а не всё сообщение целиком.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Эволюция требований:&lt;/b&gt; Рынок перешел от простого перемещения данных (ingestion) к сложной аналитике реального времени и AI, что требует более эффективного хранения и доступа к данным.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Решение (Apache Fluss):&lt;/b&gt;
&lt;ul&gt;
  &lt;li&gt;Табличная структура:** Данные хранятся как таблицы (Log Tables для логов и PK Tables для изменяемых данных), что обеспечивает строгую типизацию.&lt;/li&gt;
  &lt;li&gt;Колоночное хранение:** Использование формата Apache Arrow позволяет читать только нужные колонки (projection pushdown) и эффективнее сжимать данные, что снижает нагрузку на диск и сеть.&lt;/li&gt;
  &lt;li&gt;Интеграция с Lakehouse:** Fluss нативно поддерживает многоуровневое хранение (горячие данные в Fluss, теплые/холодные в S3/Iceberg/Paimon) без лишнего копирования, обеспечивая прозрачный доступ к историческим и оперативным данным.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Вывод:&lt;/b&gt; Fluss в связке с Flink предлагает более дешевую, быструю и удобную архитектуру для современной аналитики реального времени, устраняя недостатки Kafka в этой области.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;b&gt;Ссылка на оригинал:&lt;/b&gt;&lt;br /&gt;
&lt;a href="https://www.ververica.com/blog/a-world-without-kafka"&gt;Why Kafka Falls Short for Real-Time Analytics (and What Comes Next&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;У Apache Kafka был замечательный период: она обеспечивала работу событийно-ориентированных архитектур более десяти лет. Но ландшафт изменился, обнажив явные &lt;b&gt;ограничения Kafka для аналитики в реальном времени&lt;/b&gt; по мере того, как сценарии использования современной &lt;b&gt;потоковой аналитики&lt;/b&gt; и принятия решений становятся всё более требовательными. Kafka все чаще пытаются заставить выполнять функции в &lt;b&gt;архитектуре аналитики реального времени&lt;/b&gt;, для поддержки которых она никогда не проектировалась. Чтобы решить сегодняшние проблемы конвейеров потоковой передачи данных и аналитические требования, необходимы новые возможности. Пришло время для «новичка на районе».&lt;/p&gt;
&lt;p&gt;Во время перехода от пакетной обработки к &lt;b&gt;потоковой передаче данных в реальном времени&lt;/b&gt; значительное внимание и импульс получил проект с открытым исходным кодом, разработанный внутри LinkedIn: &lt;b&gt;Apache Kafka&lt;/b&gt;. Цель состояла в том, чтобы упростить перемещение данных из точки А в точку Б масштабируемым и устойчивым способом, используя модель издатель/подписчик. Kafka позволила компаниям создавать ранние &lt;b&gt;конвейеры потоковой передачи данных&lt;/b&gt; и открыть новый класс событийно-ориентированных сценариев использования. Постоянно растущая экосистема коннекторов и интеграций ускорила внедрение и утвердила Kafka в качестве предпочтительного &lt;b&gt;слоя потокового хранения&lt;/b&gt;. Однако, по мере того как &lt;b&gt;архитектуры аналитики реального времени&lt;/b&gt; эволюционировали за пределы простого приема данных (ingestion), ограничения Kafka для аналитических нагрузок становились всё более очевидными.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/image-233.png" width="1200" height="674" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;С архитектурной точки зрения Kafka — это не аналитический движок. Это устойчивая и масштабируемая &lt;b&gt;система хранения на основе записей (record-based storage system)&lt;/b&gt; для свежих данных в реальном времени — часто называемая «горячим слоем». Следовательно, аналитические нагрузки должны выполняться за пределами кластера Kafka, постоянно перемещая данные между системами хранения и обработки, что увеличивает сетевой трафик и накладные операционные расходы. Кроме того, Kafka нативно не обеспечивает соблюдение схем для данных, публикуемых в топиках.&lt;/p&gt;
&lt;p&gt;Хотя эта гибкость была приемлема для ранних сценариев использования потоковой передачи, современные &lt;b&gt;платформы аналитики реального времени&lt;/b&gt; требуют схем для обеспечения согласованности, управления и качества данных. В качестве компенсации появились реестры схем (Schema Registries) для обеспечения контрактов между издателями и подписчиками, добавляя сложности аналитическим архитектурам на основе Kafka.&lt;/p&gt;
&lt;p&gt;И последнее, но не менее важное (и, возможно, самый важный аспект): Kafka — это система хранения на основе записей. Это хорошо подходит для использования в качестве очереди сообщений, например, для приема данных в реальном времени или событийно-ориентированных архитектур, но имеет значительные ограничения при решении текущих и будущих задач проектов реального времени. Движки обработки, такие как Spark и Flink, должны потреблять все данные топика, даже если требуется только часть данных события (столбцы). Результатом является ненужный сетевой трафик, снижение производительности обработки и чрезмерные требования к хранилищу.&lt;/p&gt;
&lt;p&gt;Компоненты потокового хранения на основе записей по-прежнему будут занимать свое место в архитектуре данных. Такие решения, как Kafka и Pulsar, хорошо подходят для случаев, требующих чтения полных записей. Архитектурные паттерны, основанные на микросервисах, могут использовать вышеуказанные решения для обмена данными, отделяя функции от транспортировки сообщений для повышения производительности, надежности и масштабируемости. Чтение полных записей также полезно для конвейеров приема данных (ingestion pipelines), в которых данные будут храниться в системах долгосрочного хранения, таких как объектное хранилище (Object Storage), для исторических и архивных целей. Узкие места и ограничения возникают, когда они используются для аналитических нагрузок, требующих возможностей, выходящих за рамки простого слоя транспорта данных.&lt;/p&gt;
&lt;h3&gt;Эволюция потоковых данных&lt;/h3&gt;
&lt;p&gt;Сегодняшний разговор движим единственным аспектом: Эволюция. Другими словами, новые потребности требуют новых подходов к управлению данными. Kafka удовлетворила первоначальные потребности в потоковой передаче данных. В этой первой волне в основном доминировали конвейеры приема данных в реальном времени и дискретная (SEP, Simple Event Processing) аналитика. По сути, способность перемещать данные из точки А в точку Б и, в некоторых случаях, выполнять простую подготовку и обработку данных между ними. Kafka, в сочетании со Spark Streaming или специальными коннекторами, справлялась с этими ранними сценариями использования.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/image-234.png" width="1200" height="674" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Перенесемся вперед: вторая волна привнесла сложность в потоковый конвейер. Помимо дискретной подготовки данных, сценарии использования на этом этапе требовали расширенных аналитических функций, таких как агрегация, обогащение и сложная обработка событий (CEP). Микро-батчинг (micro-batching) оказался недостаточным. Требуется новый архитектурный подход, основанный на колоночном хранении с эффективным проталкиванием проекций (projection pushdown) и прозрачным многоуровневым хранением данных (data tiering), в сочетании с движками обработки с задержкой менее секунды. `Apache Fluss` и `Apache Flink` могут выполнить это обещание и вместе составляют будущее и третью волну по шкале зрелости.&lt;/p&gt;
&lt;p&gt;Каждая техническая статья сегодня упоминает AI/ML. Эта эволюция «третьей волны» позволяет компаниям создавать AI-конвейеры реального времени, которые внедряют передовые аналитические методы (такие как Generative AI) в потоковые данные. Это увеличивает потребность в современных системах хранения данных в реальном времени с расширенными функциями, которые распределяют данные как по быстрым потоковым, так и по историческим слоям, обеспечивая интегрированный, унифицированный доступ к бизнес-данным.&lt;/p&gt;
&lt;h3&gt;Новичок на районе&lt;/h3&gt;
&lt;p&gt;`Apache Fluss` — это современная система хранения потоковых данных в реальном времени для аналитики. Она консолидирует многолетний опыт и уроки, извлеченные из предшественников, отвечая текущим и будущим потребностям организаций. Fluss родился в эпоху, когда для питания моделей машинного обучения требуется больше данных, Лейкхаусы (Lakehouses) являются частью корпоративной экосистемы, а облачная инфраструктура является предпочтительной стратегией для компаний.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/Snimok-ekrana-2026-02-15-v-13.48.31.png" width="696" height="382" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Но хранение данных — это лишь часть архитектурной головоломки. `Apache Flink` предоставляет возможности и устойчивость для обработки огромных объемов данных в реальном времени с задержкой менее секунды, обеспечивая скорость, необходимую для будущих потоковых приложений. Не ограничиваясь Flink, дополнительные движки обработки и библиотеки разрабатывают интеграции с Fluss, тем самым укрепляя экосистему.&lt;/p&gt;
&lt;p&gt;Ниже приведены основные функции современной аналитики реального времени.&lt;/p&gt;
&lt;h4&gt;Поток как таблица (Stream as Table)&lt;/h4&gt;
&lt;p&gt;Fluss хранит данные как схематизированные таблицы. Этот подход подходит для большинства сценариев использования в реальном времени, включая те, которые опираются как на структурированные, так и на полуструктурированные данные. Структурируя потоковые данные, компании могут улучшить управление, повысить качество данных и гарантировать, что издатели и потребители используют общий язык. Fluss определяет два типа таблиц:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Log Tables (Лог-таблицы)** работают только на добавление (append-only), аналогично топикам Kafka. Такие сценарии использования, как мониторинг логов, кликстримы (clickstreams), показания датчиков, журналы транзакций и другие, являются хорошими примерами данных только для добавления. События неизменяемы и не должны изменяться или обновляться.&lt;/li&gt;
&lt;li&gt;Primary Key (PK) Tables (Таблицы с первичным ключом)** — это изменяемые таблицы, определенные ключом. Записи сначала вставляются, а затем обновляются или удаляются с течением времени в соответствии с журналом изменений (changelog), который они представляют. Таблица PK хранит последние изменения всей таблицы, обеспечивая паттерн доступа «поиск записи» (record lookup). Сценарии использования журнала изменений, такие как балансы счетов, корзина покупок и управление запасами, могут извлечь выгоду из этого подхода. Kafka не может выполнять такое поведение, требуя внешних баз данных типа «ключ-значение» или NoSQL для отслеживания текущего статуса записи, что приводит к сложным и трудным в обслуживании решениям.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/image-235.png" width="1200" height="556" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Вкратце, PK Tables обеспечивают уникальность записей на основе первичного ключа, операций `INSERT`, `UPDATE` и `DELETE`, а также предоставляют широкие возможности изменения записей. С другой стороны, Log Tables работают только на добавление; обновления записей не требуются.&lt;/p&gt;
&lt;h4&gt;Колоночное хранение (Columnar Storage)&lt;/h4&gt;
&lt;p&gt;То, как Fluss хранит данные на диске, возможно, является наиболее фундаментальным архитектурным сдвигом по сравнению с другими решениями. В отличие от Kafka, Fluss использует формат `Apache Arrow` для хранения данных в колоночном формате, что дает следующие преимущества:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Улучшенное использование хранилища**, так как хранение данных в колоночном формате требует меньше дискового пространства. Степень сжатия зависит от множества характеристик данных, но первоначальные тесты показывают многообещающее улучшение в 5 раз при использовании Apache Arrow в качестве базового формата хранения. Меньше хранилища = меньше затрат. Kafka предоставляет лишь несколько вариантов сжатия данных, которые не сравнимы с теми, что доступны в Apache Arrow «из коробки».&lt;/li&gt;
&lt;li&gt;Эффективные запросы с использованием обрезки столбцов (column pruning).** В общем случае запрашивается или доступно менее половины атрибутов данного бизнес-события, т.е. только те имена столбцов, которые вы добавляете в ваше выражение `SELECT FROM`. Проталкивание проекции (projection pushdown) — это метод, который удаляет ненужные атрибуты (также известный как column pruning) при извлечении данных из системы хранения. Kafka работает по принципу «все или ничего» из-за своего формата хранения на основе записей.&lt;/li&gt;
&lt;li&gt;И колоночное сжатие, и проталкивание проекции улучшат сетевой трафик — перемещение меньшего количества данных приведет к тому, что сетевые администраторы станут счастливее. С Kafka компании постоянно сталкиваются с перегрузкой сети и потенциально высокими расходами на исходящий трафик (egress costs).&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/image-236.png" width="1200" height="674" alt="" /&gt;
&lt;/div&gt;
&lt;h4&gt;Унификация с Lakehouse&lt;/h4&gt;
&lt;p&gt;Kafka была создана в эпоху Data Lake (Озер данных). С самого начала проектирования Fluss создавался для Lakehouse. Это создает большую разницу. Компании поняли, что Озера данных (или во многих случаях «Болота данных» — Data Swamps) трудно поддерживать в рабочем состоянии и окупать инвестиции в лицензии, оборудование и персонал для создания решений больших данных. К счастью, Лейкхаусы преодолевают эти проблемы. Лейкхаусы утверждают, что данные должны быть широко и легко доступны независимо от их возраста. Пакетные события и события реального времени перекрываются, и движки обработки должны иметь возможность прозрачно обращаться к обоим слоям.&lt;/p&gt;
&lt;p&gt;Вот возможности тиринга данных (распределения по уровням) и унифицированного просмотра, которые может предоставить Fluss, в дополнение к слою горячих/свежих данных:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Теплый слой (Warm layer):** для данных возрастом от минут до часов, в основном хранящихся в решениях объектного хранения (Object Storage).&lt;/li&gt;
&lt;li&gt;Холодный слой (Cold layer):** для данных возрастом от дней до лет. Решения Lakehouse, такие как `Apache Paimon` и `Iceberg`, являются предпочтительными платформами для этих исторических данных, питающих модели ML, ретроспективную аналитику и комплаенс.&lt;/li&gt;
&lt;li&gt;Zero-copy data tiering (Тиринг данных без копирования):** старение данных из горячего слоя (таблицы Fluss) в теплые/холодные слои (Object Storage и Lakehouse). Это означает, что доступна единственная копия единицы данных, либо в слое реального времени, либо в историческом слое. Fluss управляет переключением между слоями, облегчая запросы и доступ. Подход Kafka опирается на дублирование данных с помощью задания потребителя/издателя, что приводит к увеличению затрат на хранение и необходимости конвертировать топики Kafka в табличный формат Lakehouse.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/image-237.png" width="1200" height="674" alt="" /&gt;
&lt;/div&gt;
&lt;h3&gt;Светлое будущее впереди&lt;/h3&gt;
&lt;p&gt;Аналитика данных в реальном времени становится краеугольным камнем современных компаний. Цифровые бизнес-модели должны обеспечивать лучший пользовательский опыт и своевременные ответы на взаимодействия с клиентами, что заставляет компании создавать системы для использования и управления данными в реальном времени, создавая увлекательный и впечатляющий («wow») опыт. Действовать сейчас — это не просто вопрос технической осуществимости; для большинства предприятий это становится уникальным преимуществом для выживания в высококонкурентной глобальной рыночной среде.&lt;/p&gt;
&lt;p&gt;Fluss помогает компаниям преодолеть разрыв между мирами реального времени и аналитики, предлагая унифицированный доступ как к свежим данным в реальном времени, так и к историческим, холодным данным. Вкратце, Fluss обеспечивает беспрепятственный доступ к данным независимо от возраста набора данных и упрощает сложные архитектуры аналитики данных, которые тянулись годами, в основном из-за отсутствия наиболее подходящих компонентов и фреймворков.&lt;/p&gt;
&lt;p&gt;В то время как Fluss служит слоем хранения в реальном времени для аналитики, Лейкхаусу предоставляется управление, простота и масштабируемость, которые защищают современные архитектуры в будущем.&lt;/p&gt;
&lt;p&gt;С операционной стороны он предлагает значительные преимущества за счет снижения сложности управления, хранения и обслуживания как данных реального времени, так и пакетных данных. Эта эффективность трансформируется в прямую экономию средств, достигаемую в первую очередь за счет оптимизированного формата таблиц Fluss, двухуровневой системы хранения, основанной на температуре данных, и, наконец, минимизации общего использования ЦП конвейера с помощью проталкивания предикатов (predicate pushdown) и обрезки столбцов. В совокупности эти архитектурные элементы снижают накладные операционные расходы, связанные с обслуживанием платформы, ускоряют внедрение новых сценариев использования и облегчают бесшовную интеграцию с существующей ИТ-инфраструктурой предприятия.&lt;/p&gt;
</description>
</item>

<item>
<title>Рейтинг Open Source Графовых СУБД для AdTech</title>
<guid isPermaLink="false">305</guid>
<link>https://gavrilov.info/all/reyting-open-source-grafovyh-subd-dlya-adtech/</link>
<pubDate>Sun, 14 Dec 2025 14:24:45 +0300</pubDate>
<author></author>
<comments>https://gavrilov.info/all/reyting-open-source-grafovyh-subd-dlya-adtech/</comments>
<description>
&lt;p&gt;Для задач &lt;b&gt;AdTech сегментации&lt;/b&gt; (профилирование пользователей, identity resolution, поиск look-alike аудиторий) набор требований к графовой базе данных специфичен: нужна высокая скорость операций чтения/записи (real-time bidding/serving) и горизонтальная масштабируемость (миллиарды событий и связей).&lt;/p&gt;
&lt;p&gt;Учитывая популярность текущего стека (&lt;b&gt;ClickHouse, Trino, Qdrant&lt;/b&gt;), идеальная графовая база должна уметь интегрироваться в аналитический контур (через Trino или прямые коннекторы) и дополнять ClickHouse (который хранит логи событий), взяв на себя хранение топологии связей.&lt;/p&gt;
&lt;p&gt;Ниже представлен небольшой обзор и рейтинг Open Source решений на 2024-2025 год с фокусом на масштабируемость.&lt;/p&gt;
&lt;hr /&gt;
&lt;h4&gt;Рейтинг Open Source Графовых СУБД для AdTech&lt;/h4&gt;
&lt;p&gt;Разделим 12 решений на 3 эшелона по пригодности для высоконагруженной сегментации.&lt;/p&gt;
&lt;h5&gt;1 эшелон: Лидеры производительности и масштабирования (Native Distributed)&lt;/h5&gt;
&lt;p&gt;Эти базы изначально создавались для кластеров и больших объемов данных.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;1. NebulaGraph&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Тип:&lt;/b&gt; Native Distributed Graph Database.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Язык запросов:&lt;/b&gt; nGQL (SQL-подобный).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Архитектура:&lt;/b&gt; Разделение Compute (GraphD) и Storage (StorageD). Shared-nothing.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Плюсы для вас:&lt;/b&gt; Это топ-1 выбор для AdTech масштаба Tencent или Meituan. Спокойно переваривает сотни миллиардов вершин и триллионы ребер. Обеспечивает миллисекундный отклик при обходе графа (hops) на большую глубину.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Минусы:&lt;/b&gt; Более крутая кривая обучения, чем у Neo4j. Сообщество меньше, но растет.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Связь со стеком:&lt;/b&gt; Отлично дополнит ClickHouse (CH хранит атрибуты, Nebula — связи). Есть коннекторы для Spark/Flink. А через Spark можно дойти до Trino.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;2. Dgraph&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Тип:&lt;/b&gt; Native Distributed Graph.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Язык запросов:&lt;/b&gt; GraphQL (модифицированный DQL).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Архитектура:&lt;/b&gt; Распределенная, использует BadgerDB (KV store) под капотом. Поддерживает шардинг и репликацию “из коробки” в open source версии.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Плюсы:&lt;/b&gt; Горизонтальное масштабирование. Очень удобна для фронтенд-разработчиков благодаря GraphQL. Высокая пропускная способность.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Минусы:&lt;/b&gt; Специфичный язык запросов, если вы привыкли к SQL/Cypher. В последние годы темпы разработки ядра немного снизились относительно конкурентов.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;3. Memgraph&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Тип:&lt;/b&gt; In-Memory Graph Database (написана на C++).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Язык запросов:&lt;/b&gt; Cypher (совместим с Neo4j).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Архитектура:&lt;/b&gt; Работает в оперативной памяти (с возможностью сброса на диск).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Плюсы:&lt;/b&gt; &lt;b&gt;Самая быстрая&lt;/b&gt; для задач реального времени (вычисление фичей для RTB). Полная совместимость с экосистемой Neo4j (драйверы, протокол Bolt). Поддерживает Python/Rust процедуры. Отличная работа с Streaming данными (Kafka).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Минусы:&lt;/b&gt; Ограничена объемом RAM (хотя есть disk-spill, это снижает скорость).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Связь со стеком:&lt;/b&gt; Отлично стыкуется с моделями AI (Qdrant), так как позиционируется для “Graph AI”.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;2 эшелон: Классика и Универсалы&lt;/h5&gt;
&lt;p&gt;&lt;b&gt;4. Neo4j (Community Edition)&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Тип:&lt;/b&gt; Native Graph.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Язык:&lt;/b&gt; Cypher (стандарт индустрии).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Плюсы:&lt;/b&gt; Огромное сообщество, лучшая документация, куча плагинов (APOC).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Главный минус для AdTech:&lt;/b&gt; Open Source версия (Community) ограничена &lt;b&gt;одним узлом&lt;/b&gt;. Нет встроенного кластеризации и шардинга (доступно только в Enterprise за большие деньги). Для “технического задела на вырост” в Open Source варианте — это бутылочное горлышко.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;5. ArangoDB&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Тип:&lt;/b&gt; Multi-model (Graph, Document, Key/Value).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Язык:&lt;/b&gt; AQL (похож на SQL).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Плюсы:&lt;/b&gt; Гибкость. Можно хранить сложные JSON-документы (как в Mongo) и связывать их.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Минусы:&lt;/b&gt; При глубоких обходах графа (“друзья друзей друзей”) проигрывает специализированным Native Graph базам по скорости. Это компромиссное решение.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;6. JanusGraph&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Тип:&lt;/b&gt; Layered Graph Database.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Плюсы:&lt;/b&gt; Работает поверх мощных бэкендов (Cassandra, HBase, ScyllaDB) и использует Elasticsearch для индексации. Масштабируемость ограничена только бэкендом.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Минусы:&lt;/b&gt; Очень “тяжелая” инфраструктура (JVM based). Сложна в настройке и эксплуатации. Медленнее на простых запросах из-за сетевых хопов между слоями. Часто считается “устаревающей” архитектурой по сравнению с Nebula/Dgraph.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;7. Apache AGE (PostgreSQL Extension)&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Тип:&lt;/b&gt; Extension.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Суть:&lt;/b&gt; Превращает PostgreSQL в графовую БД с поддержкой Cypher.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Плюсы:&lt;/b&gt; Если вы знаете Postgres, вы знаете AGE. Не нужно новой инфраструктуры.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Минусы:&lt;/b&gt; Производительность ограничена движком Postgres. Сложно масштабировать горизонтально на запись (проблема шардинга PG).&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;3 эшелон: Нишевые и Новые игроки&lt;/h5&gt;
&lt;p&gt;&lt;b&gt;8. HugeGraph&lt;/b&gt; (Baidu) — аналог JanusGraph, популярен в Китае, очень мощный, но документация местами страдает.&lt;br /&gt;
&lt;b&gt;9. OrientDB&lt;/b&gt; — мультимодельная, была популярна, но сейчас развитие замедлилось.&lt;br /&gt;
&lt;b&gt;10. FalkorDB&lt;/b&gt; — форк закрывшегося RedisGraph (Redis module). Очень быстрый, использует разреженные матрицы. Интересен, если уже есть Redis.&lt;br /&gt;
&lt;b&gt;11. Cayley&lt;/b&gt; — написана на Go (Google), простая, работает с триплетами (Linked Data), но для сложной AdTech логики может не хватить функционала.&lt;br /&gt;
&lt;b&gt;12. TerminusDB&lt;/b&gt; — интересная база с концепцией “Git для данных”, но специфична для версионирования знаний, а не высоконагруженной сегментации.&lt;/p&gt;
&lt;h4&gt;Сравнительная таблица (ТОП-7 для выбора)&lt;/h4&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;td style="text-align: center"&gt;Масштабирование (Open Source)&lt;/td&gt;
&lt;td style="text-align: center"&gt;Скорость (Read/Traverse)&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;NebulaGraph&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;nGQL (SQL-like)&lt;/td&gt;
&lt;td style="text-align: center"&gt;Distributed Native&lt;/td&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Отличное&lt;/b&gt; (Sharding+Replication)&lt;/td&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;Big Data, AdTech, Fraud&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Memgraph&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;Cypher&lt;/td&gt;
&lt;td style="text-align: center"&gt;In-Memory (C++)&lt;/td&gt;
&lt;td style="text-align: center"&gt;Вертикальное / Репликация&lt;/td&gt;
&lt;td style="text-align: center"&gt;🚀 &lt;b&gt;Топ-1 (Low Latency)&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;Низкая (как Docker)&lt;/td&gt;
&lt;td style="text-align: center"&gt;Real-time features, Streaming&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Dgraph&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;GraphQL&lt;/td&gt;
&lt;td style="text-align: center"&gt;Distributed Native&lt;/td&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;td style="text-align: center"&gt;App Backend, 360 Customer View&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Neo4j (CE)&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;Cypher&lt;/td&gt;
&lt;td style="text-align: center"&gt;Native&lt;/td&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Нет&lt;/b&gt; (только 1 нода)&lt;/td&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;R&amp;D, малые проекты&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;ArangoDB&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;AQL&lt;/td&gt;
&lt;td style="text-align: center"&gt;Multi-model&lt;/td&gt;
&lt;td style="text-align: center"&gt;Хорошее (Cluster mode)&lt;/td&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;Гибридные данные (Docs+Graph)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;JanusGraph&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;Gremlin&lt;/td&gt;
&lt;td style="text-align: center"&gt;Layered (over NoSQL)&lt;/td&gt;
&lt;td style="text-align: center"&gt;Бесконечное (зависит от Backend)&lt;/td&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;Если уже есть HBase/Cassandra&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Apache AGE&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;Cypher&lt;/td&gt;
&lt;td style="text-align: center"&gt;Postgres Ext&lt;/td&gt;
&lt;td style="text-align: center"&gt;Только Read Replicas&lt;/td&gt;
&lt;td style="text-align: center"&gt;Средняя&lt;/td&gt;
&lt;td style="text-align: center"&gt;Низкая (если знают PG)&lt;/td&gt;
&lt;td style="text-align: center"&gt;Гибрид SQL + Graph&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h4&gt;Интеграция с текущим стеком (Qdrant, Trino или ClickHouse)&lt;/h4&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Qdrant + Graph DB = GraphRAG / Semantic Search:&lt;/b&gt;
&lt;ul&gt;
  &lt;li&gt;Сегментация пользователей часто требует поиска не только по связям (“кто кликал то же, что и я”), но и по похожести векторов (“чей профиль похож на мой”).&lt;/li&gt;
  &lt;li&gt;Memgraph&lt;b&gt; и **Neo4j&lt;/b&gt; имеют встроенные модули для работы с векторами, но так как у вас уже есть &lt;b&gt;Qdrant&lt;/b&gt;, вам нужна база, которая *не пытается заменить Qdrant*, а позволяет хранить ID векторов в узлах графа.&lt;/li&gt;
  &lt;li&gt;NebulaGraph** позволяет хранить embedding в свойствах узла, но поиск лучше делегировать Qdrant.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;b&gt;Trino:&lt;/b&gt;
&lt;ul&gt;
  &lt;li&gt;Вам захочется делать SQL-запросы сразу к ClickHouse (события) и Графу (профиль).&lt;/li&gt;
  &lt;li&gt;У &lt;b&gt;Neo4j&lt;/b&gt; и &lt;b&gt;NebulaGraph&lt;/b&gt; есть коннекторы, позволяющие Trino (через JDBC или нативные коннекторы) запрашивать данные. Это мощнейшая связка для аналитиков. Отдельно нативного конектора к Trino пока не найти, но скоро может появится поддержка iceberg &lt;a href="https://github.com/vesoft-inc/nebula/discussions/5902"&gt;https://github.com/vesoft-inc/nebula/discussions/5902&lt;/a&gt; или пока можно использоваться связку через Spark.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;b&gt;ClickHouse:&lt;/b&gt;
&lt;ul&gt;
  &lt;li&gt;Паттерн: ClickHouse хранит “сырые” логи (миллиарды строк). Агрегаты и связи (User Graph) пересчитываются и заливаются в Графовую БД для быстрого lookup.&lt;/li&gt;
  &lt;li&gt;NebulaGraph** имеет Exchange (инструмент на основе Spark) для массовой заливки данных из Warehouse.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h4&gt;Итоговая рекомендация&lt;/h4&gt;
&lt;p&gt;Учитывая, что вы хотите &lt;b&gt;Open Source&lt;/b&gt; и вам нужен &lt;b&gt;технический задел (масштабирование)&lt;/b&gt; для AdTech:&lt;/p&gt;
&lt;h5&gt;🏆 Выбор №1: NebulaGraph&lt;/h5&gt;
&lt;p&gt;Это наиболее близкий аналог “ClickHouse в мире графов”.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Почему:** Он создан для хранения миллиардов вершин (пользователей/устройств) и работы в кластере. У него shared-nothing архитектура, которая необходима для роста. Язык nGQL будет понятен вашим аналитикам, знающим SQL (ClickHouse/Trino).&lt;/li&gt;
&lt;li&gt;Для AdTech:** Идеально решает проблемы *Identity Resolution* (склеивание cookie, device_id, user_id и других атрибутов в единый граф) на больших объемах.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;🥈 Выбор №2: Memgraph&lt;/h5&gt;
&lt;p&gt;Если ваши графы помещаются в память (сотни миллионов узлов, но не десятки миллиардов) и критична задержка (latency) менее 10 мс для *real-time* принятия решений.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Почему:** Он безумно быстр. Он совместим с Cypher (легко нанимать людей или переезжать с Neo4j). Написан на C++, очень эффективен.&lt;/li&gt;
&lt;li&gt;Интеграция:** Идеально, если вы планируете стримить данные из Kafka, обновлять граф и сразу выдавать сегменты.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;🥉 Выбор №3: Apache AGE (или ArangoDB)&lt;/h5&gt;
&lt;p&gt;Только если объем графа невелик, и вы хотите минимизировать зоопарк технологий, оставаясь в рамках “почти SQL” решений. Но для серьезного AdTech они не рекомендуется как *основное* хранилище графа пользователей.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Совет:&lt;/b&gt; Начните пилот (PoC) с &lt;b&gt;NebulaGraph&lt;/b&gt;. Попробуйте загрузить туда выгрузку из ClickHouse и сравнить скорость выполнения запросов “найти всех пользователей, связанных через устройство X на глубину 3 шага” с тем, как это делается сейчас (вероятно, через JOINs в реляционке или CH). Если сложность эксплуатации Nebula покажется высокой, можно посмотреть в сторону &lt;b&gt;Memgraph&lt;/b&gt; как более легкой альтернативы и применять их не на одном большом графе например, а на нескольких малых в реальном времени, а готовые расчеты уже хранить в привычных местах.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Еще можно почитать:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://bigdataschool.ru/blog/memgraph-vs-neo4j/"&gt;Сравнение Memgraph и Neo4j bigdataschool.ru&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bigdataschool.ru/blog/neo4j-vs-tigergraph-what-to-choose.html"&gt;Сравнение Neo4j и TigerGraph (для понимания коммерческого рынка bigdataschool.ru&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wiki.merionet.ru/articles/10-lucsix-resenii-dlia-raboty-s-grafovymi-bazami-dannyx"&gt;Обзор графовых БД wiki.merionet.ru&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Вот еще мысль и про языки немного. Если проект большой с единым графом для разных нужд, то NebulaGraph выглядит лучшим решением, но архитектурно можно выбрать много средних и малых графов. Для второго подхода хорошо Memgraph с его языком Cypher&lt;/p&gt;
&lt;hr /&gt;
&lt;h4&gt;1. Семейство Cypher (OpenCypher / ISO GQL)&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;Базы:&lt;/b&gt; *Neo4j, Memgraph, FalkorDB, Apache AGE.*&lt;/p&gt;
&lt;p&gt;Cypher — это «SQL для графов». Это декларативный язык, использующий ASCII-арт для визуализации связей в коде (например, `(User)-[:CLICKS]-&gt;(Ad)`).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Функциональность:&lt;/b&gt; Очень богатая. Поддерживает сложные паттерны (Pattern Matching), агрегации, пути переменной длины. В апреле 2024 года ISO утвердила стандарт &lt;b&gt;GQL&lt;/b&gt; (Graph Query Language), который во многом основан на Cypher.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Плюсы:&lt;/b&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;b&gt;Интуитивность:&lt;/b&gt; Код читается как предложение на английском. Самая низкая кривая входа.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Экосистема:&lt;/b&gt; Стандарт де-факто. Если вы знаете Cypher, вы можете переключаться между Neo4j, Memgraph и AGE без переобучения.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Выразительность:&lt;/b&gt; Идеален для глубокой аналитики и поиска сложных паттернов (Fraud Detection).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Минусы:&lt;/b&gt;
&lt;ul&gt;
  &lt;li&gt;Изначально создавался для одноузловых систем. В распределенных системах (шардинг) некоторые конструкции Cypher могут быть сложны для оптимизации движком.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Оценка для стека:&lt;/b&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;b&gt;Memgraph/Neo4j:&lt;/b&gt; Работает идеально.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Apache AGE:&lt;/b&gt; Cypher оборачивается внутри SQL запросов Postgres, что немного громоздко, но функционально.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;FalkorDB:&lt;/b&gt; Реализует подмножество Cypher, очень быстро благодаря Redis, но функционал беднее, чем у Neo4j.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;2. Семейство Gremlin (Apache TinkerPop)&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;Базы:&lt;/b&gt; *JanusGraph, HugeGraph, OrientDB (частично), Azure CosmosDB.*&lt;/p&gt;
&lt;p&gt;Gremlin — это императивный язык обхода графа (Traversals). Вы пишете не «что найти» (как в SQL/Cypher), а «куда идти» шаг за шагом.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Функциональность:&lt;/b&gt; Тьюринговская полнота. Можно написать алгоритм любой сложности прямо внутри запроса. Это скорее язык программирования потоков данных, чем язык запросов.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Плюсы:&lt;/b&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;b&gt;Контроль:&lt;/b&gt; Вы точно указываете базе, как обходить граф. Это важно для сверхбольших графов (как в JanusGraph/HugeGraph), где неверный план запроса может “положить” кластер.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Абстракция:&lt;/b&gt; Работает поверх любой БД, поддерживающей TinkerPop.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Минусы:&lt;/b&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;b&gt;Сложность:&lt;/b&gt; Кривая обучения очень крутая. Код получается вербозным и сложным для отладки («write once, read never»).&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Устаревание:&lt;/b&gt; С появлением стандарта ISO GQL популярность Gremlin падает. Для новых проектов в 2025 году его выбирают редко, если только не привязаны к JanusGraph.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Пример AdTech:&lt;/b&gt; «Найти всех пользователей, кликнувших на этот баннер» на Gremlin будет длинной цепочкой вызовов методов (`g.V().has(‘Banner’...).out(‘CLICKS’)...`).&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;3. nGQL (NebulaGraph Query Language)&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;Базы:&lt;/b&gt; *NebulaGraph.*&lt;/p&gt;
&lt;p&gt;Собственный язык Nebula, который синтаксически мимикрирует под SQL, но логически работает с графами.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Функциональность:&lt;/b&gt; Заточена под распределенный Massive Parallel Processing (MPP).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Плюсы:&lt;/b&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;b&gt;SQL-подход:&lt;/b&gt; Разработчикам, привыкшим к MySQL/ClickHouse, синтаксис `GO FROM ... OVER ...` будет понятнее, чем Gremlin.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Скорость:&lt;/b&gt; Спроектирован так, чтобы не позволять писать «плохие» запросы, которые убивают распределенный кластер. Вынуждает думать о том, где лежат данные (VID).&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Пайпы:&lt;/b&gt; Удобный синтаксис передачи результата одного шага в другой через `|` (как в Bash).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Минусы:&lt;/b&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;b&gt;Vendor Lock-in:&lt;/b&gt; Это не стандарт. Переехать с Nebula на другую базу потребует переписывания всех запросов.&lt;/li&gt;
  &lt;li&gt;Не поддерживает полную гибкость Pattern Matching, как Cypher (хотя добавили поддержку `MATCH`, она менее производительна, чем нативный `GO`).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;4. DQL (ранее GraphQL+-)&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;Базы:&lt;/b&gt; *Dgraph.*&lt;/p&gt;
&lt;p&gt;Это модифицированный GraphQL.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Функциональность:&lt;/b&gt; Идеальна для API. Вы запрашиваете данные в формате JSON-дерева, и база возвращает JSON.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Плюсы:&lt;/b&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;b&gt;Frontend-first:&lt;/b&gt; Фронтендерам не нужен бэкенд-прослойка, они могут (теоретически) ходить в базу почти напрямую.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Работа с атрибутами:&lt;/b&gt; Поскольку Dgraph — это по сути распределенный Key-Value, DQL очень быстро достает атрибуты нод.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Минусы:&lt;/b&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;b&gt;Слабая аналитика:&lt;/b&gt; Графовые алгоритмы и сложные обходы (traversals) на DQL писать сложнее и менее эффективно, чем на Cypher/nGQL. Это язык выборки данных, а не язык аналитики графов.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;5. AQL (ArangoDB Query Language)&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;Базы:&lt;/b&gt; *ArangoDB.*&lt;/p&gt;
&lt;p&gt;Гибридный язык, объединяющий возможности SQL (JOINs), работы с JSON (как в Mongo) и графовых обходов.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Функциональность:&lt;/b&gt; Одна из самых мощных среди “универсалов”. Позволяет в одном запросе сделать JOIN трех коллекций, отфильтровать JSON и пройтись по графу друзей.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Плюсы:&lt;/b&gt; Гибкость.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Минусы:&lt;/b&gt; Синтаксис `FOR u IN users FILTER ...` специфичен и многословен. Для чистых графовых задач (deep hopping) он медленнее нативных решений [ArangoDB vs Native Graph].&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;6. Другие / Устаревающие&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;OrientDB (SQL-extended):&lt;/b&gt; Пытались расширить SQL для графов. Сейчас проект стагнирует, язык считается тупиковой ветвью эволюции по сравнению с Cypher/GQL.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;SQL Graph (MS SQL / PG SQL):&lt;/b&gt; В [статье про SQL Server](&lt;a href="https://learn.microsoft.com/ru-ru/sql/relational-databases/graphs/sql-graph-sample?view=sql-server-ver17)"&gt;https://learn.microsoft.com/ru-ru/sql/relational-databases/graphs/sql-graph-sample?view=sql-server-ver17)&lt;/a&gt; показан синтаксис `MATCH`, который Microsoft внедрила в T-SQL. Это попытка “догнать” Cypher, оставаясь в рамках реляционной модели. Удобно, если вы намертво привязаны к MS SQL, но неудобно для сложной аналитики.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Cayley (Gizmo/MQL):&lt;/b&gt; Очень нишевый язык на базе Go или JS. Для AdTech продакшена слишком экзотичен.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h4&gt;Сводная таблица сравнения&lt;/h4&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;td style="text-align: center"&gt;Для AdTech/High-load&lt;/td&gt;
&lt;td style="text-align: center"&gt;Стандартность (2025)&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;nGQL&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;NebulaGraph&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; (Tencent scale)&lt;/td&gt;
&lt;td style="text-align: center"&gt;Низкая (Vendor specific)&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;Cypher&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Memgraph&lt;/b&gt;, Neo4j, AGE&lt;/td&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Низкий&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;Хорошо (Memgraph) / Средне (Neo4j)&lt;/td&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Высокая&lt;/b&gt; (основа ISO GQL)&lt;/td&gt;
&lt;td style="text-align: center"&gt;Самый удобный для аналитиков и Data Science.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;DQL&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Dgraph&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;Низкий (для Web-dev)&lt;/td&gt;
&lt;td style="text-align: center"&gt;Хорошо (для OLTP)&lt;/td&gt;
&lt;td style="text-align: center"&gt;Низкая&lt;/td&gt;
&lt;td style="text-align: center"&gt;Лучший выбор, если граф — это бэкенд для UI.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: right"&gt;&lt;b&gt;Gremlin&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;JanusGraph, HugeGraph&lt;/td&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;Падает (Legacy)&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;AQL&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;ArangoDB&lt;/td&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;td style="text-align: center"&gt;Хорош, если нужна “Document Store + Graph” в одном.&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h4&gt;Итоговая рекомендация&lt;/h4&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Если приоритет — производительность на масштабе (AdTech, сегментация 100M+ пользователей):&lt;/b&gt;  &lt;br /&gt;
Вам нужен &lt;b&gt;NebulaGraph&lt;/b&gt; и его &lt;b&gt;nGQL&lt;/b&gt;.&lt;/li&gt;

&lt;ul&gt;
  &lt;li&gt;*Почему:* В AdTech сценариях (как у Meituan/Tencent) критичны latency на “хопах” (hops). nGQL архитектурно заставляет писать запросы так, чтобы они эффективно параллелились. Он менее удобен, чем Cypher, но более предсказуем в нагрузке.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;b&gt;Если приоритет — Real-time аналитика, ML-фичи и скорость разработки:&lt;/b&gt;  &lt;br /&gt;
Вам нужен &lt;b&gt;Memgraph&lt;/b&gt; на &lt;b&gt;Cypher&lt;/b&gt;.&lt;/li&gt;

&lt;ul&gt;
  &lt;li&gt;*Почему:* Вы получаете совместимость с самой популярной экосистемой (Neo4j), стандартный язык Cypher (легко найти специалистов) и скорость C++ in-memory движка.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;b&gt;Если приоритет — дешевое горизонтальное масштабирование “для бедных” (в хорошем смысле):&lt;/b&gt;  &lt;br /&gt;
Вам нужен &lt;b&gt;Dgraph&lt;/b&gt; (DQL) или &lt;b&gt;NebulaGraph&lt;/b&gt;.&lt;/li&gt;

&lt;ul&gt;
  &lt;li&gt;У &lt;b&gt;Dgraph&lt;/b&gt; отличный шардинг из коробки и DQL закрывает 90% задач продуктовой разработки, но может буксовать на тяжелой аналитике.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;b&gt;От чего стоит отказаться:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Neo4j Community:&lt;/b&gt; Язык Cypher прекрасен, но ограничения лицензии (отсутствие кластера) убьют проект на росте.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;JanusGraph/HugeGraph (Gremlin):&lt;/b&gt; В 2025 году начинать проект на Gremlin — это создавать себе технический долг, так как индустрия движется в сторону ISO GQL (Cypher Style).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Apache AGE:&lt;/b&gt; Пока слишком сыро для High-load, проблемы с горизонтальным масштабированием Postgres никуда не деваются.&lt;/li&gt;
&lt;/ul&gt;
</description>
</item>

<item>
<title>Обзор pg_clickhouse: Как объединить мощь ClickHouse и удобство PostgreSQL</title>
<guid isPermaLink="false">302</guid>
<link>https://gavrilov.info/all/obzor-pg-clickhouse-kak-obedinit-mosch-clickhouse-i-udobstvo-pos/</link>
<pubDate>Fri, 12 Dec 2025 23:27:54 +0300</pubDate>
<author></author>
<comments>https://gavrilov.info/all/obzor-pg-clickhouse-kak-obedinit-mosch-clickhouse-i-udobstvo-pos/</comments>
<description>
&lt;p&gt;Недавно компания ClickHouse представила новый инструмент — расширение &lt;b&gt;pg_clickhouse&lt;/b&gt;. Это событие стало ответом на одну из самых частых болей разработчиков: сложность миграции аналитических запросов из классических реляционных баз данных в колоночные аналитические СУБД.&lt;/p&gt;
&lt;p&gt;Оригинал статьи: &lt;a href="https://clickhouse.com/blog/introducing-pg_clickhouse"&gt;A Postgres extension for querying ClickHouse&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;или берем сразу тут: &lt;a href="https://github.com/ClickHouse/pg_clickhouse/releases"&gt;https://github.com/ClickHouse/pg_clickhouse/releases&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;В этой статье мы разберем, что представляет собой этот инструмент, в чем его фундаментальный смысл для архитектуры приложений и куда проект хочет двигаться дальше.&lt;/p&gt;
&lt;h3&gt;Проблема: Данные переехали, а запросы остались&lt;/h3&gt;
&lt;p&gt;Типичный сценарий роста стартапа выглядит так: приложение строится на PostgreSQL. В какой-то момент данных (логов, метрик, транзакций) становится так много, что аналитические отчеты начинают тормозить. Обычные реплики для чтения (read replicas) перестают спасать.&lt;/p&gt;
&lt;p&gt;Команда принимает решение внедрить ClickHouse. Перенос данных сейчас решается просто (например, с помощью ClickPipes), но возникает другая проблема:&lt;br /&gt;
&lt;b&gt;Как быть с тысячами строк SQL-кода в ORM, дашбордах и скриптах, которые написаны под синтаксис Postgres?&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Переписывание всей логики приложения под диалект ClickHouse — это месяцы работы и риск новых багов. Именно эту проблему решает `pg_clickhouse`.&lt;/p&gt;
&lt;h3&gt;Что такое pg_clickhouse?&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;pg_clickhouse&lt;/b&gt; — это расширение для PostgreSQL (Foreign Data Wrapper — FDW), которое позволяет создавать в Postgres «внешние таблицы», фактически ссылающиеся на таблицы в ClickHouse.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Суть технологии:&lt;/b&gt; Вы пишете запросы на привычном SQL диалекте PostgreSQL, обращаясь к этим таблицам. Расширение на лету транслирует запрос в диалект ClickHouse, отправляет его на исполнение в аналитическую базу и возвращает результат обратно в Postgres.&lt;/p&gt;
&lt;p&gt;Для приложения это выглядит прозрачно: таблицы ClickHouse могут находиться просто в отдельной схеме (schema). Достаточно изменить путь поиска (`search_path`), и старые запросы начнут работать с данными, лежащими в ClickHouse.&lt;/p&gt;
&lt;h3&gt;В чем «соль»: Технология Pushdown&lt;/h3&gt;
&lt;p&gt;Главная ценность и сложность такого расширения заключается не просто в соединении двух баз, а в эффективности этого соединения. Этот механизм называется &lt;b&gt;Pushdown&lt;/b&gt; (спуск или делегирование вычислений).&lt;/p&gt;
&lt;p&gt;Если вы делаете запрос `SELECT sum(price) FROM orders`, есть два пути его выполнения:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Плохой путь:&lt;/b&gt; Postgres выкачивает *все* миллионы строк из ClickHouse и сам считает сумму. Это уничтожает весь смысл аналитической базы.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Путь pg_clickhouse:&lt;/b&gt; Расширение понимает, что это агрегация, и отправляет в ClickHouse команду «посчитай сумму». Обратно по сети возвращается только одна цифра.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Умная трансляция функций&lt;/h4&gt;
&lt;p&gt;Авторы `pg_clickhouse` пошли дальше простой трансляции. Они научили расширение переводить специфические функции Postgres в аналоги ClickHouse, даже если синтаксис кардинально отличается.&lt;/p&gt;
&lt;p&gt;*Пример:*&lt;br /&gt;
В Postgres есть функция для расчета медианы: `percentile_cont(0.5) WITHIN GROUP (ORDER BY price)`.&lt;br /&gt;
В ClickHouse такой синтаксис не поддерживается.&lt;br /&gt;
`pg_clickhouse` автоматически переписывает это в нативную функцию ClickHouse: `quantile(0.5)(price)`.&lt;/p&gt;
&lt;p&gt;Также поддерживается трансляция конструкции `FILTER (WHERE ...)` в специфичные для ClickHouse комбинаторы `-If` (например, `sumIf`).&lt;/p&gt;
&lt;h4&gt;Ускорение подзапросов (Semi-Join)&lt;/h4&gt;
&lt;p&gt;В версии 0.1.0 была реализована поддержка &lt;b&gt;SEMI JOIN Pushdown&lt;/b&gt;. Это критически важно для запросов с конструкцией `WHERE ... IN (SELECT ...)` или `EXISTS`. Тесты на бенчмарке TPC-H показали, что благодаря этому время выполнения сложных запросов сократилось с нескольких секунд (или даже минут) до миллисекунд, так как фильтрация теперь происходит на стороне ClickHouse.&lt;/p&gt;
&lt;h3&gt;Планы развития (Roadmap)&lt;/h3&gt;
&lt;p&gt;Проект находится в стадии активной разработки (версия 0.1.0), и команда ClickHouse нацелена на полное покрытие аналитических сценариев.&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;Полное покрытие TPC-H и ClickBench:&lt;/b&gt; Оптимизация планировщика, чтобы все стандартные аналитические бенчмарки выполнялись с максимальным pushdown-ом.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Расширенная поддержка функций:&lt;/b&gt; Трансляция *всех* агрегатных и обычных функций PostgreSQL в их эквиваленты в ClickHouse.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;DML операции:&lt;/b&gt; Поддержка легковесных удалений (`DELETE`) и обновлений (`UPDATE`), а также пакетной вставки данных через `COPY`.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Управление настройками:&lt;/b&gt; Возможность передавать настройки ClickHouse (settings) через команды создания пользователей или серверов в Postgres.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Passthrough-режим:&lt;/b&gt; Возможность отправить произвольный SQL-запрос (на диалекте ClickHouse) и получить результат в виде таблицы, обходя парсер Postgres.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Заключение&lt;/h3&gt;
&lt;p&gt;`pg_clickhouse` — это попытка построить «лучшее из двух миров»: взять скорость колоночной СУБД и объединить её с богатой экосистемой и инструментарием PostgreSQL. Это позволяет разработчикам плавно мигрировать нагрузку, не переписывая приложение с нуля, и оставляет Postgres в качестве единой точки входа для данных.&lt;/p&gt;
</description>
</item>

<item>
<title>Сравнительный анализ self-hosted S3-совместимых хранилищ</title>
<guid isPermaLink="false">299</guid>
<link>https://gavrilov.info/all/sravnitelny-analiz-self-hosted-s3-sovmestimyh-hranilisch/</link>
<pubDate>Mon, 08 Dec 2025 00:50:17 +0300</pubDate>
<author></author>
<comments>https://gavrilov.info/all/sravnitelny-analiz-self-hosted-s3-sovmestimyh-hranilisch/</comments>
<description>
&lt;p&gt;Четкое сравнение семи self-hosted S3-совместимых решений для хранения данных.&lt;/p&gt;
&lt;p&gt;Оригинал тут: &lt;a href="https://www.repoflow.io/blog/benchmarking-self-hosted-s3-compatible-storage-a-practical-performance-comparison"&gt;Команда RepoFlow. 9 августа 2025 г.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Локальное (self-hosted) объектное хранилище — это отличный выбор для разработчиков и команд, которые хотят иметь полный контроль над хранением и доступом к своим данным. Независимо от того, заменяете ли вы Amazon S3, размещаете внутренние файлы, создаете CI-конвейер или обслуживаете репозитории пакетов, уровень хранения может значительно повлиять на скорость и стабильность.&lt;/p&gt;
&lt;p&gt;Мы протестировали семь популярных решений для объектного хранения, поддерживающих протокол S3. Цель состояла в том, чтобы сравнить их производительность в идентичных условиях, используя реальные операции загрузки и скачивания.&lt;/p&gt;
&lt;h3&gt;Тестируемые решения&lt;/h3&gt;
&lt;p&gt;Каждое из следующих решений было развернуто с помощью Docker на одном и том же сервере без монтирования томов и без специальной настройки:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;`MinIO`&lt;/li&gt;
&lt;li&gt;`Ceph`&lt;/li&gt;
&lt;li&gt;`SeaweedFS`&lt;/li&gt;
&lt;li&gt;`Garage`&lt;/li&gt;
&lt;li&gt;`Zenko` (Scality Cloudserver)&lt;/li&gt;
&lt;li&gt;`LocalStack`&lt;/li&gt;
&lt;li&gt;`RustFS`&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Скорость последовательного скачивания&lt;/h3&gt;
&lt;p&gt;Средняя скорость скачивания одного файла разного размера.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/Snimok-ekrana-2025-12-08-v-00.42.26.png" width="1270" height="656" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;[Изображение: График скорости последовательного скачивания для малых файлов размером 50 КБ и 200 КБ. По оси Y — скорость в МБ/с, по оси X — размер файла. Сравниваются Garage, Localstack, Minio, Zenko, Ceph, RustFS, SeaweedFS.]&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/Snimok-ekrana-2025-12-08-v-00.42.57.png" width="1264" height="650" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;[Изображение: График скорости последовательного скачивания для больших файлов размером 10 МБ, 50 МБ, 100 МБ и 1 ГБ. По оси Y — скорость в МБ/с, по оси X — размер файла. Сравниваются те же решения.]&lt;/p&gt;
&lt;h3&gt;Скорость последовательной загрузки&lt;/h3&gt;
&lt;p&gt;Средняя скорость загрузки одного файла разного размера.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/Snimok-ekrana-2025-12-08-v-00.43.18.png" width="1278" height="648" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;[Изображение: График скорости последовательной загрузки для малых файлов размером 50 КБ и 200 КБ. По оси Y — скорость в МБ/с, по оси X — размер файла. Сравниваются те же решения.]&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/Snimok-ekrana-2025-12-08-v-00.43.34.png" width="1252" height="636" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;[Изображение: График скорости последовательной загрузки для больших файлов размером 10 МБ, 50 МБ, 100 МБ и 1 ГБ. По оси Y — скорость в МБ/с, по оси X — размер файла. Сравниваются те же решения.]&lt;/p&gt;
&lt;h3&gt;Производительность листинга&lt;/h3&gt;
&lt;p&gt;Измеряет время, необходимое для получения списка всех 2000 тестовых объектов в бакете с использованием разных размеров страницы (100, 500 и 1000 результатов на запрос).&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/Snimok-ekrana-2025-12-08-v-00.44.02.png" width="1280" height="648" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;[Изображение: График производительности листинга. По оси Y — время в мс, по оси X — количество результатов на страницу (100, 500, 1000). Сравниваются те же решения.]&lt;/p&gt;
&lt;h3&gt;Скорость параллельной загрузки&lt;/h3&gt;
&lt;p&gt;Измеряет время, необходимое для параллельной загрузки нескольких файлов одинакового размера. Скорость загрузки рассчитывается по формуле:&lt;/p&gt;
&lt;p&gt;(number of files × file size) ÷ total time&lt;/p&gt;
&lt;h4&gt;Скорость параллельной загрузки – файлы 1 МБ&lt;/h4&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/Snimok-ekrana-2025-12-08-v-00.44.22.png" width="1304" height="748" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;[Изображение: График скорости параллельной загрузки файлов размером 1 МБ. По оси Y — скорость в МБ/с, по оси X — количество параллельных потоков (5, 10, 20). Сравниваются те же решения.]&lt;/p&gt;
&lt;h4&gt;Скорость параллельной загрузки – файлы 10 МБ&lt;/h4&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/Snimok-ekrana-2025-12-08-v-00.45.06.png" width="1254" height="650" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;[Изображение: График скорости параллельной загрузки файлов размером 10 МБ. По оси Y — скорость в МБ/с, по оси X — количество параллельных потоков (5, 10, 20). Сравниваются те же решения.]&lt;/p&gt;
&lt;h4&gt;Скорость параллельной загрузки – файлы 100 МБ&lt;/h4&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/Snimok-ekrana-2025-12-08-v-00.45.23.png" width="1278" height="652" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;[Изображение: График скорости параллельной загрузки файлов размером 100 МБ. По оси Y — скорость в МБ/с, по оси X — количество параллельных потоков (5, 10, 20). Сравниваются те же решения.]&lt;/p&gt;
&lt;h3&gt;Скорость параллельного скачивания&lt;/h3&gt;
&lt;p&gt;Измеряет время, необходимое для параллельного скачивания нескольких файлов одинакового размера. Скорость скачивания рассчитывается по формуле:&lt;/p&gt;
&lt;p&gt;(number of files × file size) ÷ total time&lt;/p&gt;
&lt;h4&gt;Скорость параллельного скачивания – файлы 1 МБ&lt;/h4&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/Snimok-ekrana-2025-12-08-v-00.45.45.png" width="1278" height="650" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;[Изображение: График скорости параллельного скачивания файлов размером 1 МБ. По оси Y — скорость в МБ/с, по оси X — количество параллельных потоков (5, 10, 20). Сравниваются те же решения.]&lt;/p&gt;
&lt;h4&gt;Скорость параллельного скачивания – файлы 10 МБ&lt;/h4&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/Snimok-ekrana-2025-12-08-v-00.46.02.png" width="1280" height="644" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;[Изображение: График скорости параллельного скачивания файлов размером 10 МБ. По оси Y — скорость в МБ/с, по оси X — количество параллельных потоков (5, 10, 20). Сравниваются те же решения.]&lt;/p&gt;
&lt;h4&gt;Скорость параллельного скачивания – файлы 100 МБ&lt;/h4&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/Snimok-ekrana-2025-12-08-v-00.46.17.png" width="1284" height="670" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;[Изображение: График скорости параллельного скачивания файлов размером 100 МБ. По оси Y — скорость в МБ/с, по оси X — количество параллельных потоков (5, 10, 20). Сравниваются те же решения.]&lt;/p&gt;
&lt;h3&gt;Как проводились тесты&lt;/h3&gt;
&lt;p&gt;Для каждого решения мы:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Загружали и скачивали файлы 7 различных размеров: 50 КБ, 200 КБ, 1 МБ, 10 МБ, 50 МБ, 100 МБ и 1 ГБ.&lt;/li&gt;
&lt;li&gt;Повторяли каждую загрузку и скачивание 20 раз для получения стабильных средних значений.&lt;/li&gt;
&lt;li&gt;Измеряли среднюю скорость загрузки и скачивания в мегабайтах в секунду (МБ/с).&lt;/li&gt;
&lt;li&gt;Выполняли все тесты на одной и той же машине, используя стандартный Docker-контейнер для каждой системы хранения, без внешних томов, монтирования или кешей.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Все решения тестировались в одноузловой конфигурации для обеспечения согласованности. Хотя некоторые системы (например, `Ceph`) спроектированы для лучшей производительности в кластерной среде, мы использовали одинаковые условия для всех решений, чтобы гарантировать справедливое сравнение.&lt;/p&gt;
&lt;h3&gt;Заключительные мысли&lt;/h3&gt;
&lt;p&gt;Эти результаты показывают, как каждое решение вело себя в нашей конкретной тестовой среде с одним узлом. Их следует рассматривать как относительное сравнение соотношений производительности, а не как абсолютные жесткие значения, которые будут применимы в любой конфигурации.&lt;/p&gt;
&lt;p&gt;При выборе подходящего решения для хранения данных учитывайте типичные размеры файлов, которые вы будете хранить, поскольку одни системы лучше справляются с маленькими файлами, а другие преуспевают с большими. Также подумайте об основных возможностях, которые вам требуются, таких как масштабируемость, репликация, долговечность или встроенный графический интерфейс. Наконец, помните, что производительность может сильно отличаться между одноузловыми и многоузловыми кластерами.&lt;/p&gt;
&lt;p&gt;Наши тесты предоставляют базовый уровень для понимания того, как эти системы соотносятся в идентичных условиях, но ваша реальная производительность будет зависеть от вашего конкретного оборудования, рабочей нагрузки и конфигурации.&lt;/p&gt;
</description>
</item>

<item>
<title>Просто duckdb 🦆 ну красота же 😍</title>
<guid isPermaLink="false">296</guid>
<link>https://gavrilov.info/all/prosto-duckdb-nu-krasota-zhe/</link>
<pubDate>Mon, 24 Nov 2025 21:21:17 +0300</pubDate>
<author></author>
<comments>https://gavrilov.info/all/prosto-duckdb-nu-krasota-zhe/</comments>
<description>
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;echo &amp;quot;cnt\n1\n2\n3&amp;quot; | duckdb -c &amp;quot;SELECT count(distinct cnt) FROM read_csv('/dev/stdin')&amp;quot;
┌─────────────────────┐
│ count(DISTINCT cnt) │
│        int64        │
├─────────────────────┤
│          3          │
└─────────────────────┘

echo &amp;quot;cnt\n1\n2\n3&amp;quot; | duckdb -c &amp;quot;SELECT sum(cnt) FROM read_csv('/dev/stdin')&amp;quot; 
┌──────────┐
│ sum(cnt) │
│  int128  │
├──────────┤
│    6     │
└──────────┘&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;А тут еще много всякой дополнительно утиной косметики &lt;a href="https://query.farm/duckdb_extensions.html"&gt;https://query.farm/duckdb_extensions.html&lt;/a&gt;&lt;/p&gt;
</description>
</item>

<item>
<title>Обработка логов Trino из Kafka с помощью Vector для удаления полей</title>
<guid isPermaLink="false">295</guid>
<link>https://gavrilov.info/all/obrabotka-logov-trino-iz-kafka-s-pomoschyu-vector-dlya-udaleniya/</link>
<pubDate>Fri, 21 Nov 2025 01:27:16 +0300</pubDate>
<author></author>
<comments>https://gavrilov.info/all/obrabotka-logov-trino-iz-kafka-s-pomoschyu-vector-dlya-udaleniya/</comments>
<description>
&lt;p&gt;В современных архитектурах данных, построенных на Kafka, часто возникает задача обработки или фильтрации потока событий “на лету”. Один из распространенных кейсов — удаление чувствительной информации из логов перед их передачей в следующую систему (например, в SIEM или систему долгосрочного хранения).&lt;/p&gt;
&lt;p&gt;Kafka: &lt;a href="https://hub.docker.com/r/apache/kafka"&gt;https://hub.docker.com/r/apache/kafka&lt;/a&gt;&lt;br /&gt;
Vector: &lt;a href="https://vector.dev/docs"&gt;https://vector.dev/docs&lt;/a&gt;&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/Snimok-ekrana-2025-11-21-v-00.28.37.png" width="1662" height="720" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Рассмотрим реальный пример:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Кластер &lt;b&gt;Trino&lt;/b&gt; (или Presto) пишет подробные логи о каждом выполненном запросе в топик Kafka.&lt;/li&gt;
&lt;li&gt;Эти логи содержат как полезные метаданные (пользователь, время, объем данных), так и полную &lt;b&gt;текстовую версию самого SQL-запроса&lt;/b&gt; в поле, например, `query`.&lt;/li&gt;
&lt;li&gt;Задача&lt;b&gt;: Переложить эти логи в другой топик Kafka, но уже &lt;/b&gt;без** поля `query`, чтобы система-подписчик не имела доступа к потенциально конфиденциальной информации в текстах запросов.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Для решения этой задачи мы воспользуемся &lt;b&gt;Vector&lt;/b&gt; — легковесным и сверхбыстрым инструментом для обработки данных.&lt;/p&gt;
&lt;h4&gt;План действий&lt;/h4&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Создадим два топика в Kafka: `trino-logs-raw` (для сырых логов) и `trino-logs-cleaned` (для очищенных).&lt;/li&gt;
&lt;li&gt;Настроим Vector для чтения из первого топика, удаления поля `query` и всех служебных метаданных.&lt;/li&gt;
&lt;li&gt;Настроим Vector на запись результата во второй топик.&lt;/li&gt;
&lt;li&gt;Запустим всю цепочку в Docker и протестируем.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Шаг 1: Подготовка Kafka&lt;/h4&gt;
&lt;p&gt;Предполагается, что у вас уже запущен Kafka-брокер в Docker. На основе нашего примера, у вас есть контейнер с именем `broker1`, который является частью Docker-сети `minimal_iceberg_net`.&lt;/p&gt;
&lt;p&gt;Откройте терминал и подключитесь к контейнеру Kafka, чтобы создать топики:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;Создадим сеть 

docker network create my_net 

Запускаем брокер broker:

docker run -d \
  --name broker3 \
  --network=my_net \
  -p 8893:9092 \
  -e KAFKA_NODE_ID=3 \
  -e KAFKA_PROCESS_ROLES='broker,controller' \
  -e KAFKA_CONTROLLER_QUORUM_VOTERS='3@broker3:9093' \
  -e KAFKA_LISTENERS='INTERNAL://0.0.0.0:29092,EXTERNAL://0.0.0.0:9092,CONTROLLER://broker3:9093' \
  -e KAFKA_ADVERTISED_LISTENERS='INTERNAL://broker3:29092,EXTERNAL://localhost:8893' \
  -e KAFKA_LISTENER_SECURITY_PROTOCOL_MAP='INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT,CONTROLLER:PLAINTEXT' \
  -e KAFKA_INTER_BROKER_LISTENER_NAME='INTERNAL' \
  -e KAFKA_CONTROLLER_LISTENER_NAMES='CONTROLLER' \
  -e KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=1 \
  -e KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR=1 \
  -e KAFKA_TRANSACTION_STATE_LOG_MIN_ISR=1 \
  apache/kafka:latest


docker exec --workdir /opt/kafka/bin/ -it broker3 sh&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Теперь, находясь внутри контейнера, выполните команды:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;# Создаем &amp;quot;сырой&amp;quot; топик для входящих логов Trino
./kafka-topics.sh --create --topic trino-logs-raw --bootstrap-server localhost:29092 --partitions 1 --replication-factor 1

# Создаем &amp;quot;чистый&amp;quot; топик для обработанных логов
./kafka-topics.sh --create --topic trino-logs-cleaned --bootstrap-server localhost:29092 --partitions 1 --replication-factor 1&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;*Обратите внимание: я использую внутренний порт брокера `29092`, который узнали ранее.*&lt;/p&gt;
&lt;p&gt;Выйдите из контейнера командой `exit`.&lt;/p&gt;
&lt;h4&gt;Шаг 2: Конфигурация Vector&lt;/h4&gt;
&lt;p&gt;На вашей локальной машине создайте структуру папок:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;vector-trino-processor/
└── config/
    └── vector.toml&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Поместите в файл `vector.toml` следующую конфигурацию. Это сердце нашего решения.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;# vector-trino-processor/config/vector.toml

# ==================================
#          ИСТОЧНИК ДАННЫХ
# ==================================
# Читаем сырые логи из Kafka
[sources.trino_raw_logs]
  type = &amp;quot;kafka&amp;quot;
  # Подключаемся к брокеру по имени контейнера и внутреннему порту
  bootstrap_servers = &amp;quot;broker3:29092&amp;quot;
  # Указываем, какой топик слушать
  topics = [&amp;quot;trino-logs-raw&amp;quot;]
  group_id = &amp;quot;vector-trino-cleaner&amp;quot;
  # Vector автоматически распарсит входящие сообщения как JSON
  decoding.codec = &amp;quot;json&amp;quot;

# ==================================
#             ТРАНСФОРМАЦИЯ
# ==================================
# Удаляем поле `query` и служебные метаданные Vector
[transforms.clean_trino_log]
  type = &amp;quot;remap&amp;quot;
  # Получаем данные от нашего источника
  inputs = [&amp;quot;trino_raw_logs&amp;quot;]
  # Скрипт на языке Vector Remap Language (VRL)
  source = '''
  # 1. Удаляем чувствительное поле &amp;quot;query&amp;quot; из лога.
  del(.query)

  # 2. Удаляем все служебные поля, которые Vector добавляет
  #    при чтении из Kafka, чтобы на выходе был чистый JSON.
  del(.headers)
  del(.message_key)
  del(.offset)
  del(.partition)
  del(.source_type)
  del(.timestamp)
  del(.topic)
  '''

# ==================================
#           ПРИЕМНИК ДАННЫХ
# ==================================
# Пишем очищенные логи в новый топик Kafka
[sinks.trino_cleaned_logs]
  type = &amp;quot;kafka&amp;quot;
  # Принимаем на вход данные, прошедшие трансформацию
  inputs = [&amp;quot;clean_trino_log&amp;quot;]
  bootstrap_servers = &amp;quot;broker3:29092&amp;quot;
  # Указываем топик для записи
  topic = &amp;quot;trino-logs-cleaned&amp;quot;
  # Кодируем итоговое событие обратно в JSON
  encoding.codec = &amp;quot;json&amp;quot;&lt;/code&gt;&lt;/pre&gt;&lt;h4&gt;Шаг 3: Запуск и Тестирование&lt;/h4&gt;
&lt;p&gt;Нам понадобится три терминала.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;В Терминале №1 — Запустим Vector&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Перейдите в папку `vector-trino-processor` и выполните команду:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;docker run \
  -d \
  --name vector-processor \
  -v &amp;quot;$(pwd)/config:/etc/vector/&amp;quot; \
  --network=my_net \
  --rm \
  timberio/vector:latest-alpine --config /etc/vector/vector.toml&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Эта команда:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Запускает контейнер Vector в фоновом режиме (`-d`).&lt;/li&gt;
&lt;li&gt;Дает ему имя `vector-processor`.&lt;/li&gt;
&lt;li&gt;Монтирует ваш локальный конфиг (`-v`).&lt;/li&gt;
&lt;li&gt;Подключает его к той же сети, что и Kafka (`--network`).&lt;/li&gt;
&lt;li&gt;Явно указывает, какой файл конфигурации использовать (`--config`).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;В Терминале №2 — Симулируем отправку лога Trino&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Запустим интерактивный Kafka-продюсер.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;docker exec --workdir /opt/kafka/bin -it broker3 ./kafka-console-producer.sh --topic trino-logs-raw --bootstrap-server localhost:29092&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Теперь вставьте в этот терминал JSON, имитирующий лог от Trino, и нажмите Enter:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;{&amp;quot;user&amp;quot;:&amp;quot;yuriy&amp;quot;,&amp;quot;source&amp;quot;:&amp;quot;trino-cli&amp;quot;,&amp;quot;queryId&amp;quot;:&amp;quot;20231120_123456_00001_abcde&amp;quot;,&amp;quot;query&amp;quot;:&amp;quot;SELECT * FROM sensitive_table a JOIN other_table b ON a.id = b.id WHERE a.credit_card = '1234-5678-9012-3456'&amp;quot;,&amp;quot;state&amp;quot;:&amp;quot;FINISHED&amp;quot;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;b&gt;В Терминале №3 — Проверяем результат&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Запустим Kafka-консьюмер, который будет слушать &lt;b&gt;очищенный&lt;/b&gt; топик `trino-logs-cleaned`.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;docker exec --workdir /opt/kafka/bin -it broker3 ./kafka-console-consumer.sh --topic trino-logs-cleaned --bootstrap-server localhost:29092 --from-beginning&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Вы практически мгновенно увидите результат работы Vector — тот же самый лог, но уже &lt;b&gt;без поля `query`&lt;/b&gt;:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;{&amp;quot;user&amp;quot;:&amp;quot;yuriy&amp;quot;,&amp;quot;source&amp;quot;:&amp;quot;trino-cli&amp;quot;,&amp;quot;queryId&amp;quot;:&amp;quot;20231120_123456_00001_abcde&amp;quot;,&amp;quot;state&amp;quot;:&amp;quot;FINISHED&amp;quot;}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Мы построили простой, но мощный конвейер для обработки данных в режиме реального времени, решив поставленную задачу с минимальными усилиями.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/Snimok-ekrana-2025-11-21-v-01.25.17.png" width="1652" height="470" alt="" /&gt;
&lt;/div&gt;
</description>
</item>

<item>
<title>dbt открывает исходный код MetricFlow: Управляемые метрики для AI и аналитики</title>
<guid isPermaLink="false">292</guid>
<link>https://gavrilov.info/all/dbt-otkryvaet-ishodny-kod-metricflow-upravlyaemye-metriki-dlya-a/</link>
<pubDate>Sat, 01 Nov 2025 01:03:55 +0300</pubDate>
<author></author>
<comments>https://gavrilov.info/all/dbt-otkryvaet-ishodny-kod-metricflow-upravlyaemye-metriki-dlya-a/</comments>
<description>
&lt;p&gt;Компания dbt Labs объявила о важном изменении в своей стратегии: `MetricFlow`, ключевая технология, лежащая в основе `dbt Semantic Layer`, становится полностью открытой. Проект переводится под лицензию Apache 2.0, что позволяет любому использовать, изменять и встраивать его в свои продукты. Это стратегический шаг, направленный на создание единого отраслевого стандарта для определения бизнес-метрик, особенно в свете бурного развития AI-систем.&lt;/p&gt;
&lt;p&gt;Оригинал тут: &lt;a href="https://www.getdbt.com/blog/open-source-metricflow-governed-metrics"&gt;https://www.getdbt.com/blog/open-source-metricflow-governed-metrics&lt;/a&gt;&lt;br /&gt;
А гит тут: &lt;a href="https://github.com/dbt-labs/metricflow"&gt;https://github.com/dbt-labs/metricflow&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Еще кстати есть &lt;a href="https://github.com/memiiso/opendbt"&gt;https://github.com/memiiso/opendbt&lt;/a&gt; ( Make dbt great again! :) Может они сольются с метриками, интересно.&lt;/p&gt;
&lt;h3&gt;Проблема: почему семантический слой стал критически важен&lt;/h3&gt;
&lt;p&gt;Концепция семантического слоя, который служит промежуточным слоем для определения бизнес-логики (метрик, измерений, связей), не нова. Она уже много лет используется в BI-системах для обеспечения согласованности отчетов. Однако с появлением больших языковых моделей (LLM) и инструментов в стиле “Chat with your data” проблема вышла на новый уровень.&lt;/p&gt;
&lt;p&gt;Когда AI-агент или LLM пытается ответить на вопрос, обращаясь напрямую к базе данных, он вынужден самостоятельно генерировать SQL-запрос. При этом модель “угадывает”, какие таблицы нужно соединить (`JOIN`), как правильно отфильтровать данные, какую использовать гранулярность по времени и какие оконные функции применить.&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; Две разные модели (или даже одна и та же, но с другим запросом) могут сгенерировать разный SQL для расчета, казалось бы, одной и той же метрики. Это приводит к разным цифрам в отчетах.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Ошибки:&lt;/b&gt; LLM может не знать о тонкостях бизнес-логики, например, о том, что при расчете выручки нужно учитывать возвраты или использовать специальный финансовый календарь.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Потеря доверия:&lt;/b&gt; Когда пользователи получают противоречивые или неверные данные, доверие ко всей системе аналитики быстро падает.&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;Метрики не должны быть вероятностными, зависящими от “догадок” LLM при каждом вызове. &lt;b&gt;Они должны быть детерминированными.&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;`MetricFlow` решает именно эту задачу.&lt;/p&gt;
&lt;h3&gt;Что такое MetricFlow и как он работает&lt;/h3&gt;
&lt;p&gt;`MetricFlow` — это движок, который преобразует семантические определения бизнес-понятий в готовый к выполнению и оптимизированный SQL-код. Аналитик один раз определяет метрику “Валовая маржа” на языке `MetricFlow`, и после этого любая система (BI-инструмент, AI-агент, Python-скрипт) может запросить эту метрику по имени, будучи уверенной, что получит корректный и одинаковый результат.&lt;/p&gt;
&lt;h3&gt;Ключевые изменения и их значение&lt;/h3&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Лицензия Apache 2.0:&lt;/b&gt; Это одно из главных нововведений. Apache 2.0 — это разрешительная лицензия, которая позволяет другим компаниям свободно встраивать `MetricFlow` в свои коммерческие и открытые продукты. Это снимает барьеры для принятия технологии и способствует ее распространению как стандарта.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Сотрудничество с Open Semantic Interchange (OSI):&lt;/b&gt; dbt Labs будет развивать `MetricFlow` совместно с такими партнерами, как Snowflake и Salesforce, в рамках инициативы OSI. Цель — создать единый стандарт для семантической совместимости между разными платформами, чтобы метрики, определенные один раз, одинаково работали во всех инструментах.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Как MetricFlow обеспечивает надежность AI&lt;/h3&gt;
&lt;p&gt;`MetricFlow` предоставляет открытый стандарт для метаданных и расширяемый движок, который превращает намерение (“покажи валовую маржу”) в SQL-запрос для хранилища данных.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Пример работы:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Предположим, пользователь задает AI-агенту вопрос:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Покажи валовую маржу (%) по месяцам за прошлый квартал для Северной Америки (за вычетом скидок и возвратов, по финансовому календарю).”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Без семантического слоя LLM пришлось бы конструировать сложный запрос с нуля. С `MetricFlow` процесс выглядит так:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Агент распознает намерение и запрашивает у `MetricFlow` метрику `gross_margin_pct` с нужными измерениями (`region`, `fiscal_month`) и фильтрами.&lt;/li&gt;
&lt;li&gt;`MetricFlow`, на основе заранее созданных определений, строит план запроса:
&lt;ul&gt;
  &lt;li&gt;Находит нужные таблицы: `orders`, `discounts`, `returns`, `cogs` (себестоимость).&lt;/li&gt;
  &lt;li&gt;Применяет правильные `JOIN` между ними.&lt;/li&gt;
  &lt;li&gt;Применяет фильтр по региону (`North America`).&lt;/li&gt;
  &lt;li&gt;Группирует данные по месяцам финансового, а не календарного, года.&lt;/li&gt;
  &lt;li&gt;Рассчитывает числитель (выручка) и знаменатель (себестоимость) с учетом того, что популяция данных для них должна быть одинаковой.&lt;/li&gt;
  &lt;li&gt;Вычисляет итоговое соотношение.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;`MetricFlow` компилирует этот план в оптимизированный SQL-запрос, специфичный для диалекта конкретного хранилища (Snowflake, BigQuery, Databricks и т.д.).&lt;/li&gt;
&lt;li&gt;Запрос выполняется в хранилище, и результат возвращается пользователю.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;При этом весь сгенерированный SQL доступен для проверки, что обеспечивает &lt;b&gt;прозрачность и объяснимость&lt;/b&gt; вычислений.&lt;/p&gt;
&lt;h3&gt;Основные возможности движка:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Единое определение, выполнение где угодно:&lt;/b&gt; Метрики и измерения определяются один раз, а `MetricFlow` компилирует их в SQL для разных диалектов.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Оптимизация производительности:&lt;/b&gt; Движок строит эффективные запросы, чтобы избежать лишних сканирований и снизить нагрузку на хранилище данных.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Поддержка сложных вычислений:&lt;/b&gt; `MetricFlow` из коробки обрабатывает сложные соединения, оконные функции, расчеты по когортам и полуаддитивные метрики (например, остатки на счетах, которые нельзя просто суммировать по времени).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;`MetricFlow` vs. `dbt Semantic Layer`&lt;/h3&gt;
&lt;p&gt;Важно понимать различие между двумя компонентами:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;`MetricFlow`&lt;/b&gt; — это движок с открытым исходным кодом для &lt;b&gt;определения и вычисления&lt;/b&gt; метрик. Это “сердце” системы, которое выполняет всю сложную работу по генерации SQL.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;`dbt Semantic Layer`&lt;/b&gt; — это коммерческий продукт dbt Labs, построенный *поверх* `MetricFlow`. Он добавляет функциональность корпоративного уровня:
&lt;ul&gt;
  &lt;li&gt;Управление доступом (`RBAC`).&lt;/li&gt;
  &lt;li&gt;Версионирование определений метрик.&lt;/li&gt;
  &lt;li&gt;Аудит и отслеживание происхождения данных (`lineage`).&lt;/li&gt;
  &lt;li&gt;Надежные API и коннекторы для интеграции с BI- и AI-инструментами.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Таким образом, `MetricFlow` становится общедоступным строительным блоком, а `dbt Semantic Layer` — готовым решением для его безопасного и управляемого внедрения в компаниях.&lt;/p&gt;
&lt;h3&gt;Итог&lt;/h3&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;dbt Labs сделала `MetricFlow` (движок для расчета метрик) полностью открытым под лицензией Apache 2.0.&lt;/b&gt; Это позволяет всем желающим использовать его без ограничений.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Главная цель — создать открытый стандарт для определения бизнес-метрик.&lt;/b&gt; Это особенно актуально для AI-систем, которые часто ошибаются при самостоятельной генерации SQL.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;`MetricFlow` позволяет AI и BI-инструментам запрашивать данные по имени метрики (например, `revenue`), получая детерминированный и корректный SQL-запрос.&lt;/b&gt; Это повышает надежность и согласованность данных.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Этот шаг способствует совместимости инструментов (`interoperability`) и снижает зависимость от конкретного вендора (`vendor lock-in`).&lt;/b&gt; Метрики, определенные один раз, будут работать одинаково в разных системах.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Коммерческий продукт `dbt Semantic Layer` продолжит развиваться&lt;/b&gt; как решение для управления жизненным циклом метрик в корпоративной среде (безопасность, контроль версий, аудит).&lt;/li&gt;
&lt;/ol&gt;
</description>
</item>

<item>
<title>Сравнение Apache Iceberg, Delta Lake и Apache Hudi: Глубокий анализ (2025)</title>
<guid isPermaLink="false">291</guid>
<link>https://gavrilov.info/all/sravnenie-apache-iceberg-delta-lake-i-apache-hudi-glubokiy-anali/</link>
<pubDate>Sat, 01 Nov 2025 00:53:55 +0300</pubDate>
<author></author>
<comments>https://gavrilov.info/all/sravnenie-apache-iceberg-delta-lake-i-apache-hudi-glubokiy-anali/</comments>
<description>
&lt;p&gt;С ростом популярности архитектуры &lt;b&gt;Data Lakehouse&lt;/b&gt; усилился интерес к трём основным открытым проектам в этой области: &lt;b&gt;Apache Hudi&lt;/b&gt;, &lt;b&gt;Delta Lake&lt;/b&gt; и &lt;b&gt;Apache Iceberg&lt;/b&gt;. Все три технологии продолжают активно развиваться, и в этой статье представлено актуальное сравнение их возможностей по состоянию на октябрь 2025 года.&lt;/p&gt;
&lt;p&gt;Оригинал тут: &lt;a href="https://www.onehouse.ai/blog/apache-hudi-vs-delta-lake-vs-apache-iceberg-lakehouse-feature-comparison"&gt;https://www.onehouse.ai/blog/apache-hudi-vs-delta-lake-vs-apache-iceberg-lakehouse-feature-comparison&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;b&gt;Примечание:&lt;/b&gt; Если выбор формата вызывает сложности, обратите внимание на проект &lt;b&gt;Apache XTable&lt;/b&gt; (Incubating), который обеспечивает интероперабельность между Hudi, Delta и Iceberg, позволяя использовать несколько форматов одновременно.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Сравнение возможностей&lt;/h3&gt;
&lt;h4&gt;Функциональность записи&lt;/h4&gt;
&lt;table cellpadding="0" cellspacing="0" border="0" class="e2-text-table"&gt;
&lt;tr&gt;
&lt;td&gt;Функция&lt;/td&gt;
&lt;td&gt;Apache Hudi (v1.0.2)&lt;/td&gt;
&lt;td&gt;Delta Lake (v4.0.0)&lt;/td&gt;
&lt;td&gt;Apache Iceberg (v1.10.0)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;ACID-транзакции&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Copy-on-Write&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Merge-on-Read&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅ Полнофункциональный&lt;/td&gt;
&lt;td&gt;❌ Векторы удалений (эксперимент.)&lt;/td&gt;
&lt;td&gt;❌ Векторы удалений (огранич.)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Эффективная bulk-загрузка&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅ Bulk_Insert&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Индексирование&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅ 8+ типов индексов&lt;/td&gt;
&lt;td style="text-align: left"&gt;❌ Bloom-фильтр проприетарный&lt;/td&gt;
&lt;td&gt;✅ Метаданные для статистики&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Частичные обновления&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅ Partial Updates&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Миграция таблиц&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅ Bootstrap&lt;/td&gt;
&lt;td&gt;✅ Convert to Delta&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Управление конкуренцией&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅ OCC, MVCC, NBCC&lt;/td&gt;
&lt;td&gt;✅ OCC&lt;/td&gt;
&lt;td&gt;✅ OCC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Неблокирующая конкуренция&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅ NBCC&lt;/td&gt;
&lt;td&gt;❌ OCC с перезапуском&lt;/td&gt;
&lt;td&gt;❌ OCC с перезапуском&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Менеджеры блокировок&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅ ФС, DynamoDB, Hive, Zookeeper&lt;/td&gt;
&lt;td&gt;✅ Только внешний DynamoDB&lt;/td&gt;
&lt;td&gt;✅ Каталог или внешние провайдеры&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Дедупликация&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅ Ключи, Precombine&lt;/td&gt;
&lt;td&gt;❌ Нет первичных ключей&lt;/td&gt;
&lt;td&gt;❌ Нет первичных ключей&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Зависимость от каталога&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;❌ Не требуется&lt;/td&gt;
&lt;td&gt;❌ Не требуется&lt;/td&gt;
&lt;td&gt;✅ Обязателен&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;b&gt;Ключевые отличия:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Hudi&lt;/b&gt; предлагает наиболее продвинутые механизмы управления конкуренцией, включая неблокирующий контроль (NBCC)&lt;/li&gt;
&lt;li&gt;Только &lt;b&gt;Hudi&lt;/b&gt; поддерживает настоящий Merge-on-Read без компромиссов производительности&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Hudi&lt;/b&gt; предоставляет встроенные инструменты для дедупликации через первичные ключи&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Метаданные таблиц&lt;/h3&gt;
&lt;table cellpadding="0" cellspacing="0" border="0" class="e2-text-table"&gt;
&lt;tr&gt;
&lt;td&gt;Функция&lt;/td&gt;
&lt;td&gt;Apache Hudi&lt;/td&gt;
&lt;td&gt;Delta Lake&lt;/td&gt;
&lt;td&gt;Apache Iceberg&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Масштабируемость метаданных&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅ LSM-дерево + HFile (100x ускорение)&lt;/td&gt;
&lt;td&gt;❌ Parquet чекпойнты (медленно)&lt;/td&gt;
&lt;td&gt;❌ Avro манифесты (медленно)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left"&gt;&lt;b&gt;Управление индексами&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅ Асинхронное многомодальное&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Эволюция схемы&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅ Добавление, переупоряд., удаление&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Эволюция партиций&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅ Кластеризация + индексы выражений&lt;/td&gt;
&lt;td style="text-align: left"&gt;✅ Эволюция партиций&lt;/td&gt;
&lt;td style="text-align: center"&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Первичные ключи&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td style="text-align: right"&gt;❌ Только в проприетарной версии&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Статистика столбцов&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅ HFile (до 50x ускорение)&lt;/td&gt;
&lt;td&gt;✅ Parquet чекпойнт&lt;/td&gt;
&lt;td&gt;✅ Avro манифест&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;&lt;b&gt;Важные особенности:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Hudi&lt;/b&gt; использует оптимизированный формат HFile для метаданных, что значительно ускоряет поиск&lt;/li&gt;
&lt;li&gt;Только &lt;b&gt;Hudi&lt;/b&gt; поддерживает настоящие первичные ключи как в реляционных БД&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Hudi&lt;/b&gt; предлагает более гибкий подход к партиционированию через кластеризацию&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Функциональность чтения&lt;/h3&gt;
&lt;table cellpadding="0" cellspacing="0" border="0" class="e2-text-table"&gt;
&lt;tr&gt;
&lt;td&gt;Функция&lt;/td&gt;
&lt;td&gt;Apache Hudi&lt;/td&gt;
&lt;td&gt;Delta Lake&lt;/td&gt;
&lt;td&gt;Apache Iceberg&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Time Travel&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Merge-on-Read запросы&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅ Snapshot Query&lt;/td&gt;
&lt;td&gt;❌ Сложная поддержка&lt;/td&gt;
&lt;td&gt;✅ Все запросы мержат векторы удалений&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Инкрементальные запросы&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅ + CDC запросы&lt;/td&gt;
&lt;td&gt;✅ CDF (эксперимент.)&lt;/td&gt;
&lt;td&gt;❌ Только аппенды&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;CDC запросы&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅ + before/after images&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Вторичные индексы&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Предикаты для пропуска данных&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅ Индексы выражений&lt;/td&gt;
&lt;td&gt;✅ Логические предикаты&lt;/td&gt;
&lt;td&gt;✅ Трансформации таблиц&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3&gt;Сервисы таблиц&lt;/h3&gt;
&lt;table cellpadding="0" cellspacing="0" border="0" class="e2-text-table"&gt;
&lt;tr&gt;
&lt;td&gt;Функция&lt;/td&gt;
&lt;td&gt;Apache Hudi&lt;/td&gt;
&lt;td&gt;Delta Lake&lt;/td&gt;
&lt;td&gt;Apache Iceberg&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Авторазмер файлов&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌ Ручное управление&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Компактизация&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅ Управляемая&lt;/td&gt;
&lt;td&gt;❌ 2-этапное обслуживание&lt;/td&gt;
&lt;td&gt;❌ Ручное обслуживание&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Очистка&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅ Управляемая&lt;/td&gt;
&lt;td&gt;❌ VACUUM вручную&lt;/td&gt;
&lt;td&gt;❌ Ручное удаление снапшотов&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Кластеризация&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅ Авто + Z-order/Hilbert&lt;/td&gt;
&lt;td&gt;❌ Z-order в OSS, авто – проприетар.&lt;/td&gt;
&lt;td&gt;❌ Z-order вручную&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3&gt;Поддержка экосистемы&lt;/h3&gt;
&lt;p&gt;Все три формата имеют широкую поддержку в экосистеме данных:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Apache Spark, Flink, Trino, DBT&lt;/b&gt; – полная поддержка чтения/записи во всех форматах&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Kafka Connect&lt;/b&gt; – Hudi и Iceberg имеют нативную поддержку, Delta – только проприетарную&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Облачные платформы&lt;/b&gt; (AWS, GCP, Azure) – все три формата поддерживаются с некоторыми ограничениями&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Snowflake&lt;/b&gt; – нативная поддержка Iceberg, Hudi через XTable&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Производительность: TPC-DS бенчмарки&lt;/h3&gt;
&lt;p&gt;Согласно независимым тестам:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Hudi&lt;/b&gt; и &lt;b&gt;Delta&lt;/b&gt; показывают сопоставимую производительность&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Iceberg&lt;/b&gt; consistently отстаёт по скорости выполнения запросов&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;b&gt;Важно:&lt;/b&gt; При сравнении производительности учитывайте, что Hudi по умолчанию оптимизирован для mutable-нагрузок (upsert), в то время как Delta и Iceberg – для append-only. Для честного сравнения используйте `bulk-insert` режим в Hudi.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Ключевые дифференцирующие возможности&lt;/h3&gt;
&lt;h3&gt;Инкрементальные пайплайн&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;Hudi&lt;/b&gt; предлагает наиболее зрелую поддержку инкрементальной обработки с трекингом всех изменений (вставки, обновления, удаления) и предоставлением их в виде change streams. Это позволяет строить эффективные ETL-пайплайны без перевычисления полных наборов данных.&lt;/p&gt;
&lt;h3&gt;Управление конкуренцией&lt;/h3&gt;
&lt;p&gt;В то время как все три системы поддерживают оптимистический контроль конкуренции (OCC), только &lt;b&gt;Hudi&lt;/b&gt; предлагает:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Неблокирующий контроль конкуренции (NBCC)&lt;/li&gt;
&lt;li&gt;Файл-уровневую гранулярность блокировок&lt;/li&gt;
&lt;li&gt;Возможность работы с асинхронными сервисами таблиц без остановки записи&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Merge-on-Read&lt;/h3&gt;
&lt;p&gt;Только &lt;b&gt;Hudi&lt;/b&gt; предоставляет полнофункциональный Merge-on-Read, который позволяет:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Балансировать между производительностью записи и чтения&lt;/li&gt;
&lt;li&gt;Использовать row-ориентированные форматы для стриминга и column-ориентированные для аналитики&lt;/li&gt;
&lt;li&gt;Выполнять компактизацию асинхронно&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Кластеризация vs Эволюция партиций&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Iceberg&lt;/b&gt;: Partition Evolution – изменение схемы партиционирования для новых данных&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Hudi&lt;/b&gt;: Гибридный подход – coarse-grained партиционирование + fine-grained кластеризация с возможностью эволюции без перезаписи данных&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Многомодальное индексирование&lt;/h3&gt;
&lt;p&gt;Только &lt;b&gt;Hudi&lt;/b&gt; предлагает асинхронную подсистему индексирования, поддерживающую:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bloom, hash, bitmap, R-tree индексы&lt;/li&gt;
&lt;li&gt;10-100x ускорение point lookup запросов&lt;/li&gt;
&lt;li&gt;10-30x общее ускорение запросов в реальных нагрузках&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Реальные кейсы использования&lt;/h3&gt;
&lt;h3&gt;Peloton&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Увеличение частоты ингестии с 1 раза в день до каждых 10 минут&lt;/li&gt;
&lt;li&gt;Снижение времени выполнения снапшот-заданий с 1 часа до 15 минут&lt;/li&gt;
&lt;li&gt;Экономия затрат через оптимизацию использования EMR-кластеров&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;ByteDance/TikTok&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Обработка таблиц объемом 400+ PB&lt;/li&gt;
&lt;li&gt;Ежедневный прирост данных на уровне PB&lt;/li&gt;
&lt;li&gt;Пропускная способность &gt;100 GB/s на таблицу&lt;/li&gt;
&lt;li&gt;Выбор Hudi из-за открытости экосистемы и поддержки глобальных индексов&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Walmart&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Использование Merge-on-Read для снижения задержек&lt;/li&gt;
&lt;li&gt;Нативная поддержка удалений для GDPR/CCPA compliance&lt;/li&gt;
&lt;li&gt;Row versioning для обработки out-of-order данных&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Инновации сообщества&lt;/h3&gt;
&lt;p&gt;Многие ключевые функции data lakehouse были впервые реализованы в Hudi:&lt;/p&gt;
&lt;table cellpadding="0" cellspacing="0" border="0" class="e2-text-table"&gt;
&lt;tr&gt;
&lt;td&gt;Инновация Hudi&lt;/td&gt;
&lt;td&gt;Год&lt;/td&gt;
&lt;td&gt;Аналог в других проектах&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Транзакционные обновления&lt;/td&gt;
&lt;td&gt;2017&lt;/td&gt;
&lt;td&gt;Delta OSS (2019)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Merge-on-Read&lt;/td&gt;
&lt;td&gt;2017&lt;/td&gt;
&lt;td&gt;Iceberg (2021)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Инкрементальные запросы&lt;/td&gt;
&lt;td&gt;2017&lt;/td&gt;
&lt;td&gt;Delta Change Feed (2022)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Z-order/Hilbert кривые&lt;/td&gt;
&lt;td&gt;2021&lt;/td&gt;
&lt;td&gt;Delta OSS (2022)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Многомодальное индексирование&lt;/td&gt;
&lt;td&gt;2022&lt;/td&gt;
&lt;td&gt;❌ Нет аналогов&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Контроль конкуренции без блокировок&lt;/td&gt;
&lt;td&gt;2024&lt;/td&gt;
&lt;td&gt;❌ Нет аналогов&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h3&gt;Заключение&lt;/h3&gt;
&lt;h3&gt;Критерии выбора&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;Выбирайте Apache Hudi если:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ваши workload’ы содержат значительное количество обновлений и удалений&lt;/li&gt;
&lt;li&gt;Требуется низкая задержка от конца в конец&lt;/li&gt;
&lt;li&gt;Нужны продвинутые возможности управления конкуренцией&lt;/li&gt;
&lt;li&gt;Важна производительность point lookup запросов&lt;/li&gt;
&lt;li&gt;Требуется гибкое управление layout данных через кластеризацию&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Рассмотрите Delta Lake если:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Вы используете экосистему Databricks&lt;/li&gt;
&lt;li&gt;Workload’ы преимущественно append-only&lt;/li&gt;
&lt;li&gt;Достаточно базовых возможностей управления конкуренцией&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Apache Iceberg может подойти если:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Основная задача – работа с очень большими объемами данных в cloud storage&lt;/li&gt;
&lt;li&gt;Требуется скрытое партиционирование с эволюцией&lt;/li&gt;
&lt;li&gt;Workload’ы в основном аналитические с минимальными обновлениями&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Итоговые рекомендации&lt;/h3&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Для зрелых production-нагрузок&lt;/b&gt; с frequent updates, high concurrency и low latency требованиями &lt;b&gt;Apache Hudi&lt;/b&gt; предлагает наиболее полный набор возможностей.&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;b&gt;Не ограничивайтесь сравнением “галочек”&lt;/b&gt; – оценивайте производительность на своих данных и workload’ах.&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;b&gt;Рассмотрите Apache XTable&lt;/b&gt; если невозможно определиться с одним форматом или требуется интероперабельность между системами.&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="4"&gt;
&lt;li&gt;&lt;b&gt;Учитывайте roadmap проекта&lt;/b&gt; – Hudi продолжает лидировать в инновациях, что может быть важно для долгосрочных инвестиций.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Технологии data lakehouse продолжают быстро развиваться, и выбор должен основываться на конкретных требованиях ваших use cases, а не только на текущем состоянии функциональности.&lt;/p&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>Новая эра трансформации данных: dbt против Bruin и aaC</title>
<guid isPermaLink="false">272</guid>
<link>https://gavrilov.info/all/novaya-era-transformacii-dannyh-dbt-protiv-bruin-i-aac/</link>
<pubDate>Sat, 23 Aug 2025 16:04:02 +0300</pubDate>
<author></author>
<comments>https://gavrilov.info/all/novaya-era-transformacii-dannyh-dbt-protiv-bruin-i-aac/</comments>
<description>
&lt;p&gt;В мире данных произошла тихая, но фундаментальная революция. На смену традиционному подходу &lt;b&gt;ETL (Extract, Transform, Load)&lt;/b&gt;, где данные преобразовывались до загрузки в хранилище, пришла новая парадигма — &lt;b&gt;ELT (Extract, Load, Transform)&lt;/b&gt;. Благодаря мощности современных облачных хранилищ (таких как Snowflake, BigQuery, Databricks, Starburst\Trino) стало выгоднее сначала загружать сырые данные, а уже затем трансформировать их непосредственно в хранилище.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/demo.gif" width="1200" height="900" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Этот сдвиг породил потребность в инструментах, которые специализируются на последнем шаге — трансформации (T). Именно в этой нише dbt (data build tool) стал безоговорочным лидером, но на его поле появляются и новые сильные игроки, такие как Bruin. Давайте разберемся, что это за инструменты, какой подход они олицетворяют и в чем их ключевые различия.&lt;/p&gt;
&lt;h4&gt;Подход «Аналитика как код»&lt;/h4&gt;
&lt;p&gt;И dbt, и Bruin являются яркими представителями движения &lt;b&gt;“Analytics as Code”&lt;/b&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; Все трансформации данных описываются в виде кода (в основном SQL), который хранится в системе контроля версий, такой как Git. Это позволяет отслеживать изменения, совместно работать и откатываться к предыдущим версиям.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Модульность и переиспользование (DRY – Don’t Repeat Yourself):&lt;/b&gt; Сложные трансформации разбиваются на небольшие, логически завершенные модели, которые могут ссылаться друг на друга. Это делает код чище, понятнее и позволяет повторно использовать уже написанную логику.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Тестирование:&lt;/b&gt; Код трансформаций должен быть протестирован. Инструменты позволяют автоматически проверять качество данных после преобразований: на уникальность ключей, отсутствие `NULL` значений, соответствие заданным условиям и т.д.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Документация и прозрачность:&lt;/b&gt; Процесс трансформации становится самодокументируемым. Инструменты могут автоматически генерировать документацию и строить графы зависимостей моделей (data lineage), показывая, как данные текут и преобразуются от источника к конечному виду. &lt;a href="https://www.element61.be/en/resource/when-use-dbt-or-delta-live-tables"&gt;element61.be&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;CI/CD (Continuous Integration / Continuous Deployment):&lt;/b&gt; Изменения в коде трансформаций могут автоматически тестироваться и разворачиваться в продуктивную среду, что значительно ускоряет циклы разработки.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;b&gt;Решаемые проблемы:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;“Черные ящики” ETL:&lt;/b&gt; Заменяют сложные, трудноподдерживаемые и непрозрачные ETL-процессы на понятный и документированный код.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Рассинхронизация команд:&lt;/b&gt; Стирают границы между инженерами данных и аналитиками, позволяя аналитикам, владеющим SQL, самостоятельно создавать надежные модели данных.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Низкое качество данных:&lt;/b&gt; Встроенные механизмы тестирования помогают обеспечить надежность и согласованность данных.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;h4&gt;dbt (data build tool): Золотой стандарт трансформации&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;dbt&lt;/b&gt; — это инструмент с открытым исходным кодом, который позволяет аналитикам и инженерам трансформировать данные в их хранилищах с помощью простых SQL-запросов. Важно понимать, что dbt &lt;b&gt;не извлекает и не загружает данные&lt;/b&gt;. Он специализируется исключительно на шаге &lt;b&gt;“T”&lt;/b&gt; в ELT  &lt;a href="https://vutr.substack.com/p/why-is-dbt-so-popular"&gt;vutr.substack.com&lt;/a&gt;. &lt;a href="https://github.com/dbt-labs/dbt-core"&gt;dbt git&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Он работает как компилятор и исполнитель: вы пишете модели данных в `.sql` файлах, используя шаблонизатор Jinja для добавления логики (циклы, условия, макросы). Затем dbt компилирует этот код в чистый SQL и выполняет его в вашем хранилище данных &lt;a href="https://www.element61.be/en/resource/when-use-dbt-or-delta-live-tables"&gt;element61.be&lt;/a&gt;.&lt;/p&gt;
&lt;h5&gt;Плюсы dbt&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Огромное сообщество и экосистема:&lt;/b&gt; dbt стал де-факто стандартом индустрии. Существует огромное количество статей, курсов, готовых пакетов (библиотек) и экспертов.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Фокус на SQL:&lt;/b&gt; Низкий порог входа для аналитиков, которые уже знают SQL. Это демократизирует процесс трансформации данных.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Мощное тестирование и документирование:&lt;/b&gt; Встроенные команды для тестирования данных и автоматической генерации проектной документации с графом зависимостей.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Зрелость и надежность:&lt;/b&gt; Инструмент проверен временем и используется тысячами компаний по всему миру.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Гибкость:&lt;/b&gt; Благодаря шаблонизатору Jinja можно создавать очень сложные и переиспользуемые макросы, адаптируя dbt под любые нужды.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;Минусы dbt&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Только трансформация:&lt;/b&gt; dbt не занимается извлечением (E) и загрузкой (L). Для этого вам понадобятся отдельные инструменты (например, Fivetran, Airbyte), что усложняет стек технологий.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Кривая обучения:&lt;/b&gt; Хотя основы просты, освоение продвинутых возможностей Jinja, макросов и структуры проекта требует времени.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Зависимость от Python-моделей:&lt;/b&gt; Хотя недавно появилась поддержка моделей на Python, она все еще не так нативна и проста, как основной SQL-подход, и требует дополнительных настроек.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;h4&gt;Bruin Data: Универсальный боец&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;Bruin&lt;/b&gt; — это более новый игрок на рынке, который позиционирует себя как инструмент для создания “end-to-end” пайплайнов данных. В отличие от dbt, он не ограничивается только трансформацией, а стремится охватить больше этапов работы с данными, включая их загрузку (ingestion) &lt;a href="https://github.com/bruin-data/bruin"&gt;https://github.com/bruin-data/bruin&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Bruin разделяет ту же философию “Analytics as Code”, но предлагает более интегрированный опыт, где SQL и Python являются равноправными гражданами.&lt;/p&gt;
&lt;h5&gt;Плюсы Bruin&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Универсальность:&lt;/b&gt; Один инструмент для определения всего пайплайна: от загрузки из источников до финальных витрин данных. Это может упростить стек технологий.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Нативная поддержка SQL и Python:&lt;/b&gt; Позволяет легко комбинировать задачи на разных языках в одном пайплайне без дополнительных настроек. Это идеально для задач, где чистый SQL громоздок (например, работа с API, машинное обучение).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Простота конфигурации:&lt;/b&gt; Зачастую требует меньше шаблонного кода (boilerplate) для определения ассетов и пайплайнов по сравнению с dbt.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Встроенное качество данных:&lt;/b&gt; Как и dbt, делает акцент на проверках качества на каждом шаге.&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;Минусы Bruin&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt; Пока маленькое сообщество:&lt;/b&gt; Как у нового инструмента, у Bruin гораздо меньше пользователей, готовых решений и обсуждений на форумах по сравнению с dbt. Найти помощь или готовый пакет для решения специфической задачи сложнее.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Незрелость:&lt;/b&gt; Инструмент моложе, а значит, наверное, потенциально менее стабилен и может иметь меньше интеграций по сравнению с проверенным dbt. Пока нет облачных функция за деньги. Я так думал, но все же есть &lt;a href="https://getbruin.com."&gt;https://getbruin.com.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;“Мастер на все руки — эксперт ни в чем?”:&lt;/b&gt; Стремление охватить все этапы (E, L, T) может означать, что в каждом отдельном компоненте Bruin может уступать лучшим в своем классе специализированным инструментам (например, Fivetran в загрузке, dbt в трансформации), но это конечно субъективно.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Сводное сравнение&lt;/h4&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;dbt (data build tool)&lt;/td&gt;
&lt;td style="text-align: center"&gt;Bruin Data&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;Трансформация (T в ELT)&lt;/td&gt;
&lt;td style="text-align: center"&gt;Весь пайплайн (E, L, T)&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;SQL с шаблонизатором Jinja&lt;/td&gt;
&lt;td style="text-align: center"&gt;SQL и Python как равноправные&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;/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;Требует отдельных E/L инструментов&lt;/td&gt;
&lt;td style="text-align: center"&gt;Стремится быть самодостаточным&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h4&gt;Итого&lt;/h4&gt;
&lt;p&gt;Выбор между dbt и Bruin — это выбор между двумя стратегиями построения современного стека данных.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Выбирайте dbt, если:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Вы строите гибкий стек из лучших в своем классе инструментов (“best-of-breed”): один для загрузки, другой для хранения, третий для трансформации.&lt;/li&gt;
&lt;li&gt;Ваша команда в основном состоит из аналитиков, сильных в SQL.&lt;/li&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;b&gt;Выбирайте Bruin, если:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Вы предпочитаете единый, интегрированный инструмент для управления всеми пайплайнами, чтобы упростить архитектуру&lt;/li&gt;
&lt;li&gt;Вы любите open source и End-to-end дата framework: фор data ingestion + transformations + кволити. :)&lt;/li&gt;
&lt;li&gt;Ваши пайплайны требуют тесной связки SQL и Python для трансформаций (например, обогащение данных через вызовы API или модели ML).&lt;/li&gt;
&lt;li&gt;Вы начинаете новый проект или работаете в небольшой команде и цените скорость настройки и меньшее количество движущихся частей.&lt;/li&gt;
&lt;li&gt;Вы Go’шник :) –  Bruin написан на Go почти на 100%.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;И dbt, и Bruin — мощные инструменты, воплощающие современные подходы к инженерии данных. dbt предлагает проверенный, сфокусированный и невероятно мощный движок для трансформаций, ставший стандартом. Bruin же предлагает более универсальный и интегрированный подход, который может быть привлекателен для команд, стремящихся к простоте и нативной поддержке Python.&lt;/p&gt;
&lt;h4&gt;А что такое “Аналитика как код” (Analytics as Code, AaC)?&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;Аналитика как код&lt;/b&gt; — это подход к управлению аналитическими процессами, при котором все компоненты аналитики — от моделей данных и метрик до отчетов и правил доступа — определяются в виде кода в человекочитаемых файлах. Эти файлы затем управляются так же, как исходный код любого другого программного обеспечения: с помощью систем контроля версий, автоматизированного тестирования и развертывания &lt;a href="https://medium.com/gooddata-developers/analytics-as-code-managing-analytics-solutions-like-any-other-software-504372ba6a61"&gt;medium.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Самая близкая и известная аналогия — это &lt;b&gt;Infrastructure as Code (IaC)&lt;/b&gt;. Как IaC (например, с помощью Terraform) позволил инженерам описывать серверы, сети и базы данных в коде вместо ручной настройки через веб-интерфейсы, так и AaC позволяет описывать в коде всё, что связано с данными &lt;a href="https://medium.com/@terezacihelkova/analytics-as-code-what-is-it-and-how-does-it-help-you-93e9a3c179ee"&gt;medium.com&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Идея проста и убедительна: “настройте свои системы один раз, выразите это в виде кода, а затем поместите в систему контроля версий” &lt;a href="https://www.holistics.io/blog/analytics-as-code/"&gt;holistics.io&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;Проблема: Как было раньше?&lt;/h4&gt;
&lt;p&gt;Чтобы понять ценность AaC, нужно посмотреть на проблемы, которые он решает. В традиционном подходе аналитика часто была разрозненной и хрупкой:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Логика в “черных ящиках”:&lt;/b&gt; Сложные преобразования данных были скрыты внутри GUI-интерфейсов старых ETL-инструментов или непосредственно в настройках BI-платформы (например, Tableau, Power BI). Никто, кроме автора, не мог легко понять, как рассчитывается та или иная метрика.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Разрозненные SQL-скрипты:&lt;/b&gt; Аналитики хранили важные SQL-запросы на своих локальных машинах, в общих папках или на wiki-страницах. Не было единой версии правды, код дублировался и быстро устаревал.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Отсутствие контроля версий:&lt;/b&gt; Невозможно было отследить, кто, когда и почему изменил логику расчета ключевого показателя. Откат к предыдущей работающей версии был настоящей головной болью.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;“Ручное” тестирование:&lt;/b&gt; Проверка качества данных после изменений была ручным, подверженным ошибкам процессом. Часто о проблемах узнавали уже от бизнес-пользователей, которые видели неверные цифры в отчетах.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Рассинхронизация:&lt;/b&gt; Инженеры данных готовили сырые таблицы, а аналитики строили свою логику поверх них. Любые изменения с одной стороны могли сломать всю цепочку, не будучи замеченными вовремя.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Этот хаос приводил к главному — &lt;b&gt;недоверию к данным&lt;/b&gt;. Никто не мог быть уверен, что цифры в дашборде верны.&lt;/p&gt;
&lt;h4&gt;Ключевые принципы “Аналитики как код”&lt;/h4&gt;
&lt;p&gt;AaC решает эти проблемы, внедряя практики из мира разработки ПО.&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Декларативное определение:&lt;/b&gt; Все аналитические артефакты описываются в файлах.
&lt;ul&gt;
  &lt;li&gt;Модели данных:** `SELECT * FROM ...` в `.sql` файлах.&lt;/li&gt;
  &lt;li&gt;Тесты:** `not_null`, `unique` в `.yml` файлах.&lt;/li&gt;
  &lt;li&gt;Документация:** Описания таблиц и полей в `.yml` файлах.&lt;/li&gt;
  &lt;li&gt;Метрики и дашборды:** Определения в `.yml` или специализированных файлах &lt;a href="https://medium.com/gooddata-developers/analytics-as-code-managing-analytics-solutions-like-any-other-software-504372ba6a61"&gt;medium.com&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;b&gt;Контроль версий (Git):&lt;/b&gt; Весь код хранится в репозитории (например, на GitHub или GitLab).
&lt;ul&gt;
  &lt;li&gt;Прозрачность:** Каждое изменение — это `commit` с понятным описанием.&lt;/li&gt;
  &lt;li&gt;Совместная работа:** Аналитики работают в отдельных ветках, а изменения вносятся через `Pull Request` (или `Merge Request`), что позволяет проводить ревью кода (code review).&lt;/li&gt;
  &lt;li&gt;Восстанавливаемость:** Если что-то пошло не так, можно легко откатиться к предыдущей версии.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;b&gt;Автоматизированное тестирование:&lt;/b&gt; Тесты являются неотъемлемой частью кода. Они запускаются автоматически при каждом изменении, чтобы гарантировать, что данные по-прежнему соответствуют ожиданиям (например, `user_id` всегда уникален и не равен `NULL`).&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="4"&gt;
&lt;li&gt;&lt;b&gt;CI/CD (Непрерывная интеграция и развертывание):&lt;/b&gt; Процессы полностью автоматизированы.
&lt;ul&gt;
  &lt;li&gt;Когда аналитик вносит изменения в `Pull Request`, автоматически запускаются тесты.&lt;/li&gt;
  &lt;li&gt;После одобрения и слияния ветки изменения автоматически развертываются в продуктивной среде (например, dbt Cloud или Jenkins запускает команду `dbt run`).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="5"&gt;
&lt;li&gt;&lt;b&gt;Модульность и переиспользование (DRY – Don’t Repeat Yourself):&lt;/b&gt; Сложные потоки данных разбиваются на небольшие, логичные и переиспользуемые модели. Одна модель может ссылаться на другую, создавая четкий граф зависимостей (lineage), который можно визуализировать.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Преимущества подхода AaC&lt;/h4&gt;
&lt;p&gt;Принятие этой философии дает компании ощутимые выгоды:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Надежность и доверие:&lt;/b&gt; Благодаря автоматическому тестированию и ревью кода значительно повышается качество данных, а вместе с ним и доверие бизнеса к аналитике.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Скорость и гибкость:&lt;/b&gt; Аналитики могут вносить изменения гораздо быстрее. Цикл от идеи до готового отчета сокращается с недель до дней или даже часов.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Масштабируемость:&lt;/b&gt; Кодовая база легко поддерживается и расширяется. Новые члены команды могут быстро разобраться в проекте благодаря документации и прозрачности.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Прозрачность и обнаруживаемость:&lt;/b&gt; Автоматически сгенерированная документация и графы зависимостей позволяют любому сотруднику понять, откуда берутся данные и как они рассчитываются.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Демократизация:&lt;/b&gt; AaC дает возможность аналитикам, владеющим SQL, самостоятельно создавать надежные и протестированные модели данных, не дожидаясь инженеров данных. Это стирает барьеры между командами.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;В конечном итоге, “Аналитика как код” — это культурный сдвиг, который превращает аналитику из ремесленного занятия в зрелую инженерную дисциплину, обеспечивая скорость, надежность и масштабируемость, необходимые современному бизнесу.&lt;/p&gt;
</description>
</item>

<item>
<title>Apache SeaTunnel – Движение к мультимодальной интеграции данных</title>
<guid isPermaLink="false">270</guid>
<link>https://gavrilov.info/all/apache-seatunnel-dvizhenie-k-multimodalnoy-integracii-dannyh/</link>
<pubDate>Sun, 17 Aug 2025 11:32:24 +0300</pubDate>
<author></author>
<comments>https://gavrilov.info/all/apache-seatunnel-dvizhenie-k-multimodalnoy-integracii-dannyh/</comments>
<description>
&lt;h4&gt;Новое позиционирование Apache SeaTunnel. Движение к унифицированному инструменту для мультимодальной интеграции данных&lt;/h4&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/image-209.png" width="1456" height="840" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Оригинал тут: &lt;a href="https://apacheseatunnel.substack.com/p/apache-seatunnel-new-positioning"&gt;https://apacheseatunnel.substack.com/p/apache-seatunnel-new-positioning&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h4&gt;Введение&lt;/h4&gt;
&lt;p&gt;В постоянно меняющемся мире больших данных эффективная и надежная интеграция данных является ключевым фактором для успеха любого предприятия. Apache SeaTunnel (ранее известный как Waterdrop) зарекомендовал себя как мощный инструмент для синхронизации данных. Однако с развитием технологий и появлением новых вызовов, таких как интеграция разнородных типов данных (структурированных, полуструктурированных и неструктурированных), проект пересматривает свое позиционирование. Цель — превратиться из простого инструмента синхронизации в комплексную, унифицированную платформу для мультимодальной интеграции данных.&lt;/p&gt;
&lt;h4&gt;Проблемы предыдущей архитектуры&lt;/h4&gt;
&lt;p&gt;Изначально Apache SeaTunnel был разработан как плагин, работающий поверх вычислительных движков, таких как Apache Spark и Apache Flink. Такой подход имел свои преимущества, позволяя использовать мощность этих движков, но также порождал ряд проблем:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Зависимость от сторонних движков:&lt;/b&gt; Для выполнения даже самых простых задач по пересылке данных требовалось развертывание и поддержка тяжеловесных кластеров Spark или Flink. Это увеличивало накладные расходы, усложняло настройку и повышало порог входа для новых пользователей.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Сложность конфигурации:&lt;/b&gt; Пользователям приходилось разбираться не только в конфигурации самого SeaTunnel, но и в настройках Spark/Flink, что часто приводило к так называемому “конфигурационному аду”.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Ограничения коннекторов:&lt;/b&gt; Разработка коннекторов была тесно связана с API Spark и Flink, что затрудняло создание универсальных коннекторов, работающих в обеих средах без изменений.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Низкая производительность для простых задач:&lt;/b&gt; Использование мощных, но громоздких движков для элементарных задач ETL (Extract, Transform, Load) было избыточным и неэффективным с точки зрения ресурсов и времени запуска.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Новое видение: унифицированная платформа с собственным движком&lt;/h4&gt;
&lt;p&gt;Чтобы решить эти проблемы и соответствовать современным требованиям, сообщество Apache SeaTunnel представило новую архитектуру, в основе которой лежит собственный вычислительный движок — &lt;b&gt;SeaTunnel Engine&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;Этот стратегический шаг позволил отделить SeaTunnel от обязательной зависимости от Spark и Flink. Теперь SeaTunnel может работать в самостоятельном режиме, что обеспечивает следующие ключевые преимущества:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Легковесность и быстрота:&lt;/b&gt; `SeaTunnel Engine` специально оптимизирован для задач интеграции данных. Он запускается быстрее и потребляет значительно меньше ресурсов, чем полноценные кластеры Spark или Flink, что делает его идеальным для широкого круга задач.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Унификация пакетной и потоковой обработки:&lt;/b&gt; Новая архитектура изначально спроектирована для бесшовной работы как с пакетными (batch), так и с потоковыми (streaming) данными. Пользователям больше не нужно поддерживать два разных стека для разных типов задач — SeaTunnel предоставляет единый интерфейс и модель выполнения.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Упрощенная разработка коннекторов:&lt;/b&gt; С введением унифицированного API коннекторов (`Connector API`), разработчикам стало проще создавать новые интеграции. Коннектор, написанный для `SeaTunnel Engine`, будет работать одинаково для всех сценариев, что ускоряет расширение экосистемы.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Мультимодальная интеграция данных&lt;/h4&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; Традиционная область для SeaTunnel. Поддерживается множество реляционных баз данных (MySQL, PostgreSQL), аналитических СУБД (ClickHouse, Doris) и хранилищ данных.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Полуструктурированные данные:&lt;/b&gt; Эффективная работа с NoSQL базами данных (MongoDB, Elasticsearch) и потоками событий (Kafka, Pulsar).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Неструктурированные данные:&lt;/b&gt; Расширение поддержки для озер данных (Data Lakes) и файловых систем (HDFS, S3, OSS). Это включает интеграцию с форматами вроде Apache Hudi, Iceberg и Delta Lake.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Особое внимание уделяется критически важным функциям, таким как &lt;b&gt;Захват изменяемых данных (CDC)&lt;/b&gt; и &lt;b&gt;синхронизация всей базы данных целиком&lt;/b&gt;. SeaTunnel теперь может считывать журналы транзакций (например, binlog в MySQL) для захвата изменений в реальном времени и применять их к целевой системе. Функция полной синхронизации позволяет в одной задаче перенести схему и все данные из одной базы в другую, что значительно упрощает миграцию.&lt;/p&gt;
&lt;h4&gt;Будущее развитие&lt;/h4&gt;
&lt;p&gt;Дорожная карта проекта включает в себя:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Расширение экосистемы коннекторов:&lt;/b&gt; Добавление поддержки еще большего числа источников и приемников, включая современные SaaS-платформы и векторные базы данных для задач ИИ.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Улучшенная поддержка озер данных:&lt;/b&gt; Углубление интеграции с форматами Hudi и Iceberg, поддержка эволюции схем и транзакционных операций.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Пользовательский интерфейс:&lt;/b&gt; Разработка визуального интерфейса для создания и мониторинга заданий, что сделает инструмент более доступным для широкого круга пользователей.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Повышение производительности и стабильности:&lt;/b&gt; Непрерывная оптимизация `SeaTunnel Engine` для еще более быстрой и надежной обработки данных.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Заключение&lt;/h4&gt;
&lt;p&gt;Apache SeaTunnel совершает важный переход от зависимого инструмента к самостоятельной, легковесной и унифицированной платформе для интеграции данных. Отказ от обязательной привязки к Spark/Flink и внедрение собственного `SeaTunnel Engine` открывают новые возможности для пользователей, которым нужно простое, но мощное решение для пакетной и потоковой обработки разнородных данных. Новое позиционирование делает SeaTunnel сильным конкурентом в мире современных ETL/ELT инструментов.&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;h5&gt;Выводы&lt;/h5&gt;
&lt;p&gt;Проанализировав направление развитие Apache SeaTunnel, можно сделать несколько ключевых выводов:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Стратегическая зрелость:&lt;/b&gt; Переход на собственный движок (`SeaTunnel Engine`) — это признак зрелости проекта. Команда осознала, что зависимость от универсальных, но тяжеловесных движков (Spark/Flink) является узким местом для основного сценария использования — интеграции данных. Создание специализированного движка позволяет оптимизировать производительность и снизить накладные расходы именно для этих задач.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Соответствие трендам:&lt;/b&gt; Этот шаг полностью соответствует общему тренду в индустрии данных — движению от монолитных, “умеющих все” платформ к более легковесным и специализированным инструментам. Для многих задач по перемещению и простой трансформации данных запуск Spark-кластера является избыточным. SeaTunnel теперь предлагает “золотую середину”.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Конкурентное позиционирование:&lt;/b&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;b&gt;Против коммерческих SaaS ETL (Fivetran, Airbyte):&lt;/b&gt; SeaTunnel является мощной open-source альтернативой. Он привлекателен для компаний, которые хотят полного контроля над своей инфраструктурой, стремятся избежать зависимости от поставщика (vendor lock-in) и имеют техническую экспертизу для самостоятельного развертывания и поддержки.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Против специализированных CDC-инструментов (Debezium):&lt;/b&gt; SeaTunnel не просто захватывает изменения (CDC), а встраивает эту функциональность в полноценный конвейер интеграции. Это решение “все в одном”, которое позволяет не только извлечь данные, но и доставить их в целевую систему (например, озеро данных или хранилище) в рамках одного инструмента.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Фокус на “мультимодальности” — это задел на будущее.&lt;/b&gt; Поддержка не только реляционных баз и Kafka, но и озер данных (Hudi, Iceberg) и, в перспективе, векторных баз, говорит о том, что проект нацелен на обслуживание современных стеков данных, включая аналитику в реальном времени и конвейеры для машинного обучения (MLOps).&lt;/li&gt;
&lt;/ol&gt;
&lt;h5&gt;Рекомендации&lt;/h5&gt;
&lt;p&gt;Исходя из этого, можно дать следующие рекомендации:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Кому стоит обратить внимание на Apache SeaTunnel:&lt;/b&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;b&gt;Командам, для которых Spark/Flink избыточны.&lt;/b&gt; Если ваша основная задача — это синхронизация данных между различными источниками (например, из MySQL в ClickHouse или из Kafka в HDFS) без сложных вычислений, `SeaTunnel Engine` может оказаться значительно более эффективным и простым в эксплуатации решением.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Компаниям, ищущим open-source замену коммерческим ETL-инструментам.&lt;/b&gt; Если у вас есть экспертиза для управления Java-приложениями и вы хотите построить гибкую, масштабируемую и экономичную платформу интеграции данных, SeaTunnel — отличный кандидат.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Пользователям экосистемы Apache.&lt;/b&gt; Проект тесно интегрируется с другими популярными проектами Apache (Doris, Hudi, Flink, Spark), что делает его естественным выбором для тех, кто уже использует эти технологии.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Инженерам, которым нужна унификация.&lt;/b&gt; Если вы устали поддерживать отдельные скрипты или инструменты для пакетной и потоковой обработки, SeaTunnel предлагает единый подход к обоим сценариям.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;b&gt;Что нужно проверить перед внедрением:&lt;/b&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;b&gt;Экосистему коннекторов:&lt;/b&gt; Самое важное — убедиться, что в SeaTunnel есть готовые, стабильные коннекторы для всех ваших источников и приемников данных. Хотя сообщество активно их добавляет, покрытие может быть не таким широким, как у коммерческих лидеров рынка.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Функциональность CDC:&lt;/b&gt; Если вам нужен захват изменений в реальном времени, детально изучите поддержку вашей СУБД. Проверьте, насколько стабильно работает коннектор и какие гарантии доставки (exactly-once, at-least-once) он предоставляет.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Операционная сложность:&lt;/b&gt; Несмотря на то, что SeaTunnel стал проще, это все еще open-source инструмент, требующий мониторинга, настройки и периодических обновлений. Убедитесь, что у вашей команды есть ресурсы для его поддержки.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Apache SeaTunnel трансформируется в мощный и современный инструмент, который заслуживает внимания со стороны инженеров данных. Его новое позиционирование как легковесной, унифицированной платформы делает его сильным игроком на поле интеграции данных.&lt;/p&gt;
</description>
</item>

<item>
<title>iceberg-kafka-connect</title>
<guid isPermaLink="false">268</guid>
<link>https://gavrilov.info/all/iceberg-kafka-connect/</link>
<pubDate>Sun, 17 Aug 2025 11:07:00 +0300</pubDate>
<author></author>
<comments>https://gavrilov.info/all/iceberg-kafka-connect/</comments>
<description>
&lt;p&gt;Крутой блог по всей экостистеме кафка, примеры по iceberg которые разобраны ниже&lt;/p&gt;
&lt;p&gt;&lt;a href="https://rmoff.net/2025/07/04/writing-to-apache-iceberg-on-s3-using-kafka-connect-with-glue-catalog/"&gt;https://rmoff.net/2025/07/04/writing-to-apache-iceberg-on-s3-using-kafka-connect-with-glue-catalog/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;небольшой пост про CDC от автора книги гроккаем конкурентность&lt;/p&gt;
&lt;p&gt;&lt;a href="https://luminousmen.com/post/change-data-capture"&gt;https://luminousmen.com/post/change-data-capture&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;дока по iceberg-sink connector&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/databricks/iceberg-kafka-connect"&gt;https://github.com/databricks/iceberg-kafka-connect&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;kafka vizualizer&lt;/p&gt;
&lt;p&gt;&lt;a href="https://softwaremill.com/kafka-visualisation/"&gt;https://softwaremill.com/kafka-visualisation/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;А тут видосик:&lt;/p&gt;
&lt;p&gt;&lt;video controls style="width: 100%; max-width: 740px; height: auto;"&gt;&lt;br /&gt;
&lt;source src="http://a.gavrilov.info/data/posts/debezium+iceberg_s.mp4" type="video/mp4"&gt;&lt;br /&gt;
Ваш браузер не поддерживает видео.&lt;br /&gt;
&lt;/video&gt;&lt;/p&gt;
</description>
</item>

<item>
<title>Описание патерна Slowly Changing Dimensions (SCD)</title>
<guid isPermaLink="false">267</guid>
<link>https://gavrilov.info/all/opisanie-paterna-slowly-changing-dimensions-scd/</link>
<pubDate>Sat, 16 Aug 2025 23:24:59 +0300</pubDate>
<author></author>
<comments>https://gavrilov.info/all/opisanie-paterna-slowly-changing-dimensions-scd/</comments>
<description>
&lt;p&gt;&lt;b&gt;Slowly Changing Dimensions (SCD)&lt;/b&gt;, или &lt;b&gt;Медленно меняющиеся измерения&lt;/b&gt;, — это концепция и набор методов из области хранилищ данных (Data Warehousing), которые используются для управления изменениями в атрибутах измерений с течением времени. Измерения — это справочные таблицы, которые описывают бизнес-сущности, такие как клиенты, продукты, сотрудники, географические регионы.&lt;/p&gt;
&lt;p&gt;Атрибуты этих сущностей (например, адрес клиента или категория продукта) меняются, но обычно не очень часто — отсюда и название “медленно меняющиеся”. Основная задача SCD — решить, как хранить эти изменения, чтобы обеспечить точность исторических отчетов &lt;a href="https://www.datacamp.com/tutorial/mastering-slowly-changing-dimensions-scd"&gt;www.datacamp.com&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Например, если вы просто перезапишете адрес клиента, вы потеряете информацию о том, где он жил раньше. Это может исказить анализ продаж по регионам за прошлые периоды. Патерны SCD предлагают различные стратегии для решения этой проблемы.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/opisanie-paterna-slowly-changing-dimensions-scd.png" width="1060" height="720" alt="" /&gt;
&lt;/div&gt;
&lt;h4&gt;Основные типы SCD&lt;/h4&gt;
&lt;p&gt;Существует несколько типов SCD, но самыми распространенными и фундаментальными являются Типы 1, 2 и 3.&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;h5&gt;Тип 1: Перезапись атрибута (Overwrite)&lt;/h5&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;Преимущества:** Простота реализации, не требует увеличения объема хранилища.&lt;/li&gt;
&lt;li&gt;Недостатки:&lt;b&gt; **История изменений полностью теряется.&lt;/b&gt; Анализ, основанный на исторических значениях атрибута, становится невозможным.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Пример:&lt;/b&gt;&lt;br /&gt;
У нас есть клиент Анна Петрова, которая живет в Москве.&lt;/p&gt;
&lt;p&gt;*Таблица `DimCustomer` до изменений:*&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;CustomerKey&lt;/td&gt;
&lt;td style="text-align: center"&gt;FullName&lt;/td&gt;
&lt;td style="text-align: center"&gt;City&lt;/td&gt;
&lt;/tr&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;101&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;/table&gt;
&lt;p&gt;Анна переезжает в Санкт-Петербург. При использовании &lt;b&gt;SCD Тип 1&lt;/b&gt; таблица будет обновлена:&lt;/p&gt;
&lt;p&gt;*Таблица `DimCustomer` после изменений:*&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;CustomerKey&lt;/td&gt;
&lt;td style="text-align: center"&gt;FullName&lt;/td&gt;
&lt;td style="text-align: center"&gt;City&lt;/td&gt;
&lt;/tr&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;101&lt;/td&gt;
&lt;td style="text-align: center"&gt;Анна Петрова&lt;/td&gt;
&lt;td style="text-align: right"&gt;Санкт-Петербург&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Теперь невозможно узнать, что раньше Анна жила в Москве.&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;h5&gt;Тип 2: Добавление новой строки (Add New Row)&lt;/h5&gt;
&lt;p&gt;Это самый распространенный и мощный тип SCD, так как он позволяет сохранять полную историю изменений.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Как работает:** Вместо перезаписи существующей записи, создается новая запись для той же сущности (например, того же клиента). Старая запись помечается как неактуальная (истекшая), а новая — как актуальная. Для этого в таблицу измерения обычно добавляют несколько служебных столбцов &lt;a href="https://learn.microsoft.com/en-us/fabric/data-factory/slowly-changing-dimension-type-two"&gt;learn.microsoft.com&lt;/a&gt;:
&lt;ul&gt;
  &lt;li&gt;`StartDate` / `EffectiveDate` — дата, с которой запись стала актуальной.&lt;/li&gt;
  &lt;li&gt;`EndDate` — дата, когда запись перестала быть актуальной.&lt;/li&gt;
  &lt;li&gt;`IsCurrent` / `CurrentFlag` — флаг (например, ‘Yes’/’No’ или 1/0), показывающий, является ли эта запись текущей.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Когда использовать:** Когда сохранение истории критически важно для анализа. Это стандартный выбор для большинства атрибутов в хранилищах данных.&lt;/li&gt;
&lt;li&gt;Преимущества:** Сохраняется полная, точная история. Позволяет проводить корректный point-in-time анализ (анализ на определенный момент времени).&lt;/li&gt;
&lt;li&gt;Недостатки:** Увеличивается объем таблицы, так как для одного клиента может быть несколько записей. Запросы могут стать сложнее (нужно фильтровать по флагу `IsCurrent` или по диапазону дат) &lt;a href="https://hevodata.com/learn/slowly-changing-dimensions/"&gt;hevodata.com&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Пример:&lt;/b&gt;&lt;br /&gt;
Снова используем пример с Анной Петровой.&lt;/p&gt;
&lt;p&gt;*Таблица `DimCustomer` до изменений:*&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;SurrogateKey&lt;/td&gt;
&lt;td style="text-align: center"&gt;CustomerID&lt;/td&gt;
&lt;td style="text-align: center"&gt;FullName&lt;/td&gt;
&lt;td style="text-align: center"&gt;City&lt;/td&gt;
&lt;td style="text-align: center"&gt;StartDate&lt;/td&gt;
&lt;td style="text-align: center"&gt;EndDate&lt;/td&gt;
&lt;td style="text-align: center"&gt;IsCurrent&lt;/td&gt;
&lt;/tr&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;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;td style="text-align: center"&gt;:---&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;1&lt;/td&gt;
&lt;td style="text-align: center"&gt;101&lt;/td&gt;
&lt;td style="text-align: right"&gt;Анна Петрова&lt;/td&gt;
&lt;td style="text-align: center"&gt;Москва&lt;/td&gt;
&lt;td style="text-align: center"&gt;2020-01-15&lt;/td&gt;
&lt;td style="text-align: center"&gt;NULL&lt;/td&gt;
&lt;td style="text-align: center"&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Анна переезжает 16 августа 2024 года. При использовании &lt;b&gt;SCD Тип 2&lt;/b&gt; таблица изменится так:&lt;/p&gt;
&lt;p&gt;*Таблица `DimCustomer` после изменений:*&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;SurrogateKey&lt;/td&gt;
&lt;td style="text-align: center"&gt;CustomerID&lt;/td&gt;
&lt;td style="text-align: center"&gt;FullName&lt;/td&gt;
&lt;td style="text-align: center"&gt;City&lt;/td&gt;
&lt;td style="text-align: center"&gt;StartDate&lt;/td&gt;
&lt;td style="text-align: center"&gt;EndDate&lt;/td&gt;
&lt;td style="text-align: center"&gt;IsCurrent&lt;/td&gt;
&lt;/tr&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;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;td style="text-align: center"&gt;:---&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;1&lt;/td&gt;
&lt;td style="text-align: center"&gt;101&lt;/td&gt;
&lt;td style="text-align: right"&gt;Анна Петрова&lt;/td&gt;
&lt;td style="text-align: center"&gt;Москва&lt;/td&gt;
&lt;td style="text-align: center"&gt;2020-01-15&lt;/td&gt;
&lt;td style="text-align: center"&gt;2024-08-15&lt;/td&gt;
&lt;td style="text-align: center"&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;2&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;101&lt;/td&gt;
&lt;td style="text-align: right"&gt;Анна Петрова&lt;/td&gt;
&lt;td style="text-align: right"&gt;Санкт-Петербург&lt;/td&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;2024-08-16&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;NULL&lt;/td&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Yes&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Теперь мы сохранили всю историю перемещений Анны.&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;h5&gt;Тип 3: Добавление нового атрибута (Add New Attribute)&lt;/h5&gt;
&lt;p&gt;Этот тип сохраняет ограниченную историю, добавляя в таблицу отдельный столбец для предыдущего значения атрибута.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Как работает:** Создается новый столбец, например, `PreviousCity`. Когда атрибут `City` меняется, его старое значение копируется в `PreviousCity`, а новое записывается в `City`.&lt;/li&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;b&gt;Пример:&lt;/b&gt;&lt;br /&gt;
Анна переезжает из Москвы в Санкт-Петербург.&lt;/p&gt;
&lt;p&gt;*Таблица `DimCustomer` до изменений:*&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;CustomerKey&lt;/td&gt;
&lt;td style="text-align: center"&gt;FullName&lt;/td&gt;
&lt;td style="text-align: center"&gt;CurrentCity&lt;/td&gt;
&lt;td style="text-align: center"&gt;PreviousCity&lt;/td&gt;
&lt;/tr&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;td style="text-align: center"&gt;:---&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;101&lt;/td&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;NULL&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;*Таблица `DimCustomer` после изменений:*&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;CustomerKey&lt;/td&gt;
&lt;td style="text-align: center"&gt;FullName&lt;/td&gt;
&lt;td style="text-align: center"&gt;CurrentCity&lt;/td&gt;
&lt;td style="text-align: center"&gt;PreviousCity&lt;/td&gt;
&lt;/tr&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;td style="text-align: center"&gt;:---&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;101&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;&lt;/td&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Москва&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Если Анна переедет снова, значение “Москва” будет потеряно.&lt;/p&gt;
&lt;h4&gt;Другие типы SCD&lt;/h4&gt;
&lt;p&gt;Существуют и более сложные гибридные типы:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Тип 4 (History Table):** Основная таблица измерения хранит только текущие данные (как Тип 1), а вся история изменений выносится в отдельную таблицу. Это полезно, когда изменения происходят часто в очень больших таблицах измерений &lt;a href="https://medium.com/@zivilevalutytesilveira/slowly-changing-dimensions-in-data-warehousing-9479699bf40f"&gt;medium.com&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Тип 6 (Hybrid):** Комбинирует подходы Типов 1, 2 и 3. Например, в таблице хранятся поля для полной истории (SCD2) и одновременно поле для текущего значения (SCD1 для быстрого доступа) и предыдущего значения (SCD3 для сравнения).&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Тип 4: Добавление исторической таблицы (History Table / Audit Table)&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;Идея:&lt;/b&gt; Разделить текущие данные и исторические данные в разные таблицы для оптимизации производительности.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Как работает:** Создаются две таблицы:
&lt;ol start="1"&gt;
  &lt;li&gt;&lt;b&gt;Таблица измерения (Dimension Table):&lt;/b&gt; Хранит *только* текущие, самые последние данные. Эта таблица по своей сути работает как &lt;b&gt;SCD Тип 1&lt;/b&gt; (данные просто перезаписываются). Она маленькая, быстрая и идеально подходит для большинства запросов, где история не нужна.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Историческая таблица (History Table):&lt;/b&gt; Хранит всю историю изменений. Каждый раз, когда в основной таблице происходит изменение, старая версия строки (до обновления) добавляется в историческую таблицу. Эта таблица часто содержит служебные поля, как в SCD Тип 2 (`StartDate`, `EndDate`, `Version`), для отслеживания временного периода.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Когда использовать:** Когда у вас есть очень большая таблица измерений (например, десятки миллионов клиентов), и большинство аналитических запросов относится только к текущим данным. Разделение таблиц позволяет сделать эти частые запросы очень быстрыми, не жертвуя при этом возможностью проводить глубокий исторический анализ при необходимости.&lt;/li&gt;
&lt;li&gt;Преимущества:**
&lt;ul&gt;
  &lt;li&gt;Высокая производительность для запросов к текущим данным.&lt;/li&gt;
  &lt;li&gt;Логическое разделение данных: актуальные и исторические.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Недостатки:**
&lt;ul&gt;
  &lt;li&gt;Усложнение ETL/ELT процесса, так как нужно управлять двумя таблицами.&lt;/li&gt;
  &lt;li&gt;Анализ, требующий одновременного доступа к историческим и текущим данным, усложняется, так как требует `JOIN` или `UNION` между двумя таблицами.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;`DimCustomer` (основная таблица)&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;CustomerID&lt;/td&gt;
&lt;td style="text-align: center"&gt;FullName&lt;/td&gt;
&lt;td style="text-align: center"&gt;City&lt;/td&gt;
&lt;/tr&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;101&lt;/td&gt;
&lt;td style="text-align: right"&gt;Анна Петрова&lt;/td&gt;
&lt;td style="text-align: center"&gt;Москва&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;`HistoryCustomer` (историческая таблица) – *пустая*&lt;/p&gt;
&lt;p&gt;*Процесс изменения:*&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Перед&lt;/b&gt; обновлением основной таблицы, текущая строка (Анна в Москве) копируется в `HistoryCustomer`.&lt;/li&gt;
&lt;li&gt;Затем основная таблица `DimCustomer` обновляется новым значением.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;*Таблицы &lt;b&gt;после&lt;/b&gt; изменений:*&lt;/p&gt;
&lt;p&gt;`DimCustomer` (всегда хранит только актуальные данные)&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;CustomerID&lt;/td&gt;
&lt;td style="text-align: center"&gt;FullName&lt;/td&gt;
&lt;td style="text-align: center"&gt;City&lt;/td&gt;
&lt;/tr&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;101&lt;/td&gt;
&lt;td style="text-align: right"&gt;Анна Петрова&lt;/td&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Санкт-Петербург&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;`HistoryCustomer` (накапливает историю)&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;HistoryID&lt;/td&gt;
&lt;td style="text-align: right"&gt;CustomerID&lt;/td&gt;
&lt;td style="text-align: center"&gt;FullName&lt;/td&gt;
&lt;td style="text-align: center"&gt;City&lt;/td&gt;
&lt;td style="text-align: center"&gt;StartDate&lt;/td&gt;
&lt;td style="text-align: center"&gt;EndDate&lt;/td&gt;
&lt;/tr&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: left"&gt;:---&lt;/td&gt;
&lt;td style="text-align: left"&gt;:---&lt;/td&gt;
&lt;td style="text-align: left"&gt;:---&lt;/td&gt;
&lt;td style="text-align: left"&gt;:---&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;1&lt;/td&gt;
&lt;td style="text-align: center"&gt;101&lt;/td&gt;
&lt;td&gt;Анна Петрова&lt;/td&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Москва&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;2020-01-15&lt;/td&gt;
&lt;td style="text-align: center"&gt;2024-08-15&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h4&gt;Тип 5: Гибридный подход (Mini-Dimension + Type 1 Outrigger)&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;Идея:&lt;/b&gt; Вынести часто меняющиеся атрибуты из большой таблицы измерений в отдельную “мини-таблицу”, чтобы избежать “раздувания” основной таблицы.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Как работает:**
&lt;ol start="1"&gt;
  &lt;li&gt;Из основной таблицы измерения (например, `DimCustomer`) выделяется группа атрибутов, которые часто меняются вместе (например, “Тарифный план”, “Статус подписки”).&lt;/li&gt;
  &lt;li&gt;Создается отдельная таблица — “мини-измерение” (например, `DimSubscriptionProfile`) — только для этих атрибутов. Эта мини-таблица управляется по &lt;b&gt;SCD Тип 2&lt;/b&gt; (добавление новой строки для каждого уникального набора значений).&lt;/li&gt;
  &lt;li&gt;В основной таблице `DimCustomer` эти атрибуты удаляются, и вместо них добавляется один внешний ключ (например, `SubscriptionProfileKey`), который ссылается на мини-измерение.&lt;/li&gt;
  &lt;li&gt;Этот ключ в основной таблице `DimCustomer` обновляется по принципу &lt;b&gt;SCD Тип 1&lt;/b&gt; (просто перезаписывается), указывая на *актуальную* запись в мини-измерении.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Когда использовать:** В очень больших (широких и/или с большим количеством строк) таблицах измерений, где лишь небольшая группа атрибутов меняется относительно часто. Это позволяет отслеживать историю этих атрибутов, не создавая новую многомиллионную запись в основной таблице при каждом изменении.&lt;/li&gt;
&lt;li&gt;Преимущества:**
&lt;ul&gt;
  &lt;li&gt;Экономия места и контроль над ростом основной таблицы измерения.&lt;/li&gt;
  &lt;li&gt;Позволяет вести детальную историю для подгруппы атрибутов.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Недостатки:**
&lt;ul&gt;
  &lt;li&gt;Более сложная модель данных, требующая дополнительных `JOIN`.&lt;/li&gt;
  &lt;li&gt;Может быть сложнее для понимания конечными пользователями.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&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;`DimCustomer`&lt;/p&gt;
&lt;table cellpadding="0" cellspacing="0" border="0" class="e2-text-table"&gt;
&lt;tr&gt;
&lt;td style="text-align: right"&gt;CustomerKey&lt;/td&gt;
&lt;td style="text-align: center"&gt;FullName&lt;/td&gt;
&lt;td style="text-align: center"&gt;SubscriptionProfileKey&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;:---&lt;/td&gt;
&lt;td style="text-align: left"&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;202&lt;/td&gt;
&lt;td style="text-align: center"&gt;Иван Иванов&lt;/td&gt;
&lt;td style="text-align: center"&gt;55&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;`DimSubscriptionProfile` (мини-измерение, управляется по SCD2)&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;ProfileKey&lt;/td&gt;
&lt;td style="text-align: center"&gt;Plan&lt;/td&gt;
&lt;td style="text-align: center"&gt;Status&lt;/td&gt;
&lt;td style="text-align: center"&gt;IsCurrent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;:---&lt;/td&gt;
&lt;td style="text-align: left"&gt;:---&lt;/td&gt;
&lt;td style="text-align: left"&gt;:---&lt;/td&gt;
&lt;td style="text-align: left"&gt;:---&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;55&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;Basic&lt;/td&gt;
&lt;td style="text-align: center"&gt;Active&lt;/td&gt;
&lt;td style="text-align: center"&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;*Процесс изменения:* Иван переходит на план “Premium”.&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;В `DimSubscriptionProfile` добавляется новая строка для “Premium”, а старая помечается как неактуальная.&lt;/li&gt;
&lt;li&gt;В `DimCustomer` у Ивана обновляется ключ `SubscriptionProfileKey`.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;*Таблицы &lt;b&gt;после&lt;/b&gt; изменений:*&lt;/p&gt;
&lt;p&gt;`DimCustomer` (здесь изменился только ключ)&lt;/p&gt;
&lt;table cellpadding="0" cellspacing="0" border="0" class="e2-text-table"&gt;
&lt;tr&gt;
&lt;td style="text-align: right"&gt;CustomerKey&lt;/td&gt;
&lt;td style="text-align: center"&gt;FullName&lt;/td&gt;
&lt;td style="text-align: center"&gt;SubscriptionProfileKey&lt;/td&gt;
&lt;/tr&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;202&lt;/td&gt;
&lt;td style="text-align: center"&gt;Иван Иванов&lt;/td&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;56&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;`DimSubscriptionProfile` (здесь хранится вся история)&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;ProfileKey&lt;/td&gt;
&lt;td style="text-align: center"&gt;Plan&lt;/td&gt;
&lt;td style="text-align: center"&gt;Status&lt;/td&gt;
&lt;td style="text-align: center"&gt;IsCurrent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;:---&lt;/td&gt;
&lt;td style="text-align: left"&gt;:---&lt;/td&gt;
&lt;td style="text-align: left"&gt;:---&lt;/td&gt;
&lt;td style="text-align: left"&gt;:---&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;55&lt;/td&gt;
&lt;td style="text-align: center"&gt;Basic&lt;/td&gt;
&lt;td style="text-align: center"&gt;Active&lt;/td&gt;
&lt;td style="text-align: center"&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;56&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Premium&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Active&lt;/b&gt;&lt;/td&gt;
&lt;td style="text-align: center"&gt;&lt;b&gt;Yes&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;h4&gt;Тип 6: Гибридный (Комбинация Типа 1, 2 и 3)&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;Идея:&lt;/b&gt; Обеспечить максимальную гибкость для анализа, объединив сильные стороны трех основных типов в одной таблице.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Как работает:&lt;b&gt; Этот тип строится на основе **SCD Тип 2&lt;/b&gt; (добавление новой строки для истории), но с добавлением атрибутов из &lt;b&gt;SCD Тип 1&lt;/b&gt; (перезапись) для упрощения некоторых запросов.
&lt;ul&gt;
  &lt;li&gt;Основная структура — это SCD Тип 2: есть строки для каждой исторической версии с полями `StartDate`, `EndDate` и `IsCurrent`. Поле атрибута (например, `City`) хранит значение, актуальное на тот исторический период.&lt;/li&gt;
  &lt;li&gt;Дополнительно в таблицу добавляется столбец `CurrentCity`. Этот столбец для *всех* записей одного клиента (и исторических, и текущей) всегда хранит &lt;b&gt;актуальное на данный момент&lt;/b&gt; значение (поведение SCD Тип 1).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Когда использовать:** Когда аналитикам часто нужно отвечать на два типа вопросов:
&lt;ol start="1"&gt;
  &lt;li&gt;“Каким был город клиента на момент продажи?” (Используется историческое поле `City`).&lt;/li&gt;
  &lt;li&gt;“Каковы продажи всем клиентам, которые *сейчас* живут в Москве, за всю историю?” (Используется поле `CurrentCity` для фильтрации).&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Преимущества:**
&lt;ul&gt;
  &lt;li&gt;Невероятная гибкость анализа без сложных `JOIN` или подзапросов для определения текущего состояния.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Недостатки:**
&lt;ul&gt;
  &lt;li&gt;Усложнение ETL/ELT. При изменении адреса нужно не только создать новую строку и закрыть старую, но и обновить поле `CurrentCity` во &lt;b&gt;всех&lt;/b&gt; предыдущих строках для этого клиента. Это может быть ресурсозатратно.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Пример:&lt;/b&gt;&lt;br /&gt;
Снова Анна, переезжающая из Москвы в Санкт-Петербург.&lt;/p&gt;
&lt;p&gt;*Таблица `DimCustomer` &lt;b&gt;до&lt;/b&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;SurrogateKey&lt;/td&gt;
&lt;td style="text-align: center"&gt;CustomerID&lt;/td&gt;
&lt;td style="text-align: center"&gt;City&lt;/td&gt;
&lt;td style="text-align: center"&gt;CurrentCity&lt;/td&gt;
&lt;td style="text-align: center"&gt;StartDate&lt;/td&gt;
&lt;td style="text-align: center"&gt;EndDate&lt;/td&gt;
&lt;td style="text-align: center"&gt;IsCurrent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;:---&lt;/td&gt;
&lt;td style="text-align: left"&gt;:---&lt;/td&gt;
&lt;td style="text-align: left"&gt;:---&lt;/td&gt;
&lt;td style="text-align: left"&gt;:---&lt;/td&gt;
&lt;td style="text-align: left"&gt;:---&lt;/td&gt;
&lt;td style="text-align: left"&gt;:---&lt;/td&gt;
&lt;td style="text-align: left"&gt;:---&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;1&lt;/td&gt;
&lt;td style="text-align: center"&gt;101&lt;/td&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;2020-01-15&lt;/td&gt;
&lt;td style="text-align: center"&gt;NULL&lt;/td&gt;
&lt;td style="text-align: center"&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;*Процесс изменения:*&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;Старая строка “закрывается” (обновляется `EndDate`, `IsCurrent` = ‘No’).&lt;/li&gt;
&lt;li&gt;Создается новая актуальная строка.&lt;/li&gt;
&lt;li&gt;Во &lt;b&gt;всех строках&lt;/b&gt; для CustomerID=101 поле `CurrentCity` обновляется до “Санкт-Петербург”.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;*Таблица `DimCustomer` &lt;b&gt;после&lt;/b&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;SurrogateKey&lt;/td&gt;
&lt;td style="text-align: center"&gt;CustomerID&lt;/td&gt;
&lt;td style="text-align: center"&gt;City&lt;/td&gt;
&lt;td style="text-align: center"&gt;CurrentCity&lt;/td&gt;
&lt;td style="text-align: center"&gt;StartDate&lt;/td&gt;
&lt;td style="text-align: center"&gt;EndDate&lt;/td&gt;
&lt;td style="text-align: center"&gt;IsCurrent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;:---&lt;/td&gt;
&lt;td style="text-align: left"&gt;:---&lt;/td&gt;
&lt;td style="text-align: left"&gt;:---&lt;/td&gt;
&lt;td style="text-align: left"&gt;:---&lt;/td&gt;
&lt;td style="text-align: left"&gt;:---&lt;/td&gt;
&lt;td style="text-align: left"&gt;:---&lt;/td&gt;
&lt;td style="text-align: left"&gt;:---&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;1&lt;/td&gt;
&lt;td style="text-align: center"&gt;101&lt;/td&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;&lt;/td&gt;
&lt;td style="text-align: center"&gt;2020-01-15&lt;/td&gt;
&lt;td style="text-align: center"&gt;2024-08-15&lt;/td&gt;
&lt;td style="text-align: center"&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: center"&gt;2&lt;/td&gt;
&lt;td style="text-align: center"&gt;101&lt;/td&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;&lt;/td&gt;
&lt;td style="text-align: center"&gt;2024-08-16&lt;/td&gt;
&lt;td style="text-align: center"&gt;NULL&lt;/td&gt;
&lt;td style="text-align: center"&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;
&lt;p&gt;Теперь можно легко отфильтровать по `City` для исторического анализа или по `CurrentCity` для анализа в разрезе текущего состояния.&lt;/p&gt;
&lt;h4&gt;Ссылки для дальнейшего изучения&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Microsoft Fabric:** Slowly changing dimension type 2 &lt;a href="https://learn.microsoft.com/en-us/fabric/data-factory/slowly-changing-dimension-type-two"&gt;https://learn.microsoft.com/en-us/fabric/data-factory/slowly-changing-dimension-type-two&lt;/a&gt; — Хорошее описание и пример реализации SCD Тип 2.&lt;/li&gt;
&lt;li&gt;DataCamp:** Mastering Slowly Changing Dimensions (SCD) &lt;a href="https://www.datacamp.com/tutorial/mastering-slowly-changing-dimensions-scd"&gt;https://www.datacamp.com/tutorial/mastering-slowly-changing-dimensions-scd&lt;/a&gt; — Комплексный учебник по основным типам SCD.&lt;/li&gt;
&lt;li&gt;HevoData:** Slowly Changing Dimensions(SCD): Types with Examples &lt;a href="https://hevodata.com/learn/slowly-changing-dimensions/"&gt;https://hevodata.com/learn/slowly-changing-dimensions/&lt;/a&gt; — Детальное объяснение всех основных типов с примерами.&lt;/li&gt;
&lt;li&gt;ThoughtSpot:** Slowly Changing Dimensions (SCD): 4 Types &amp; How to ...&lt;a href="https://www.thoughtspot.com/data-trends/data-modeling/slowly-changing-dimensions-in-data-warehouse"&gt;https://www.thoughtspot.com/data-trends/data-modeling/slowly-changing-dimensions-in-data-warehouse&lt;/a&gt; — Еще один ресурс с обзором и сравнением типов SCD.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Идея: Концептуальная архитектура: SCD на стеке Lakehouse + Data Mesh + dbt&lt;/p&gt;
&lt;p&gt;Основная идея заключается в создании надежных, версионируемых и децентрализованных “продуктов данных”, одним из которых является таблица измерений с полной историей (SCD). (Автоматическая)&lt;/p&gt;
&lt;p&gt;Вот как компоненты взаимодействуют друг с другом:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Lakehouse (Основа):&lt;/b&gt; Это наша физическая среда. Мы используем открытое озеро данных (например, S3, ADLS) для хранения, а поверх него — табличный формат &lt;b&gt;Apache Iceberg&lt;/b&gt;. Iceberg предоставляет нам ACID-транзакции, эволюцию схемы и, что самое важное для SCD, атомарные и эффективные операции `MERGE` (`UPDATE`/`INSERT`/`DELETE`) на уровне строк прямо в озере данных.&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;b&gt;Data Mesh (Философия организации):&lt;/b&gt; Вместо централизованной команды данных, мы принимаем философию Data Mesh. A “Команда домена Клиенты” несет полную ответственность за все данные, связанные с клиентами. Их задача — предоставить остальной компании высококачественный продукт данных под названием `dim_customers`. Этот продукт должен включать полную историю изменений (SCD Type 2).&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;b&gt;ETL/ELT (Процесс):&lt;/b&gt; Это конвейер, по которому данные текут от источника к потребителю.
&lt;ul&gt;
  &lt;li&gt;Extract &amp; Load:&lt;b&gt; Исходные данные (например, изменения в базе данных клиентов) захватываются с помощью CDC (Change Data Capture) инструментов типа Debezium и попадают в **Kafka&lt;/b&gt;. Оттуда они загружаются (Load) в “бронзовый” слой нашего Lakehouse (в сыром виде, в таблицы Iceberg).&lt;/li&gt;
  &lt;li&gt;Transform:&lt;b&gt; Здесь в игру вступает **dbt&lt;/b&gt;. Команда домена использует `dbt` для преобразования сырых данных из бронзового слоя в готовую к использованию модель в “серебряном” слое — нашу таблицу `dim_customers`.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="4"&gt;
&lt;li&gt;&lt;b&gt;dbt (Инструмент автоматизации SCD):&lt;/b&gt; `dbt` является сердцем автоматизации. Он не просто выполняет SQL-скрипты. У него есть встроенный функционал для реализации SCD Type 2, который называется &lt;b&gt;`Snapshots`&lt;/b&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;h4&gt;Сценарий 1: Автоматическое формирование SCD с помощью `dbt snapshots`&lt;/h4&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; У нас есть “бронзовая” таблица `bronze_customers`, которая содержит текущее состояние всех клиентов. Эта таблица обновляется периодически (например, раз в час) новыми данными из Kafka.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;dbt Snapshot:&lt;/b&gt; В проекте `dbt` команда домена создает файл “снэпшота” (`snapshot/customers_snapshot.sql`). Внутри него описывается, как `dbt` должен отслеживать изменения.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;{% snapshot customers_snapshot %}

    {{
        config(
          target_schema='silver',
          unique_key='customer_id',
          strategy='check',
          check_cols=['address', 'email', 'phone_number'],
          updated_at='last_modified_at',
        )
    }}

    select * from {{ source('bronze', 'customers') }}

    {% endsnapshot %}&lt;/code&gt;&lt;/pre&gt;&lt;ol start="3"&gt;
&lt;li&gt;&lt;b&gt;Автоматизация:&lt;/b&gt; Оркестратор (например, Airflow) запускает команду `dbt snapshot` по расписанию.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Что делает dbt “под капотом”:&lt;/b&gt;
&lt;ul&gt;
  &lt;li&gt;Он сравнивает записи из исходной таблицы (`bronze_customers`) с текущими записями в целевой таблице (`silver.customers_snapshot`).&lt;/li&gt;
  &lt;li&gt;Используя `unique_key` (`customer_id`), он находит совпадающие записи.&lt;/li&gt;
  &lt;li&gt;С помощью стратегии `check` он проверяет, изменилось ли значение в любом из столбцов, перечисленных в `check_cols`.&lt;/li&gt;
  &lt;li&gt;Если изменение обнаружено:
&lt;ul&gt;
    &lt;li&gt;Он обновляет старую запись в целевой таблице, проставляя ей дату окончания актуальности (`dbt_valid_to`).&lt;/li&gt;
    &lt;li&gt;Он вставляет новую строку с обновленными данными и датой начала актуальности (`dbt_valid_from`).&lt;/li&gt;
  &lt;/ul&gt;
&lt;/li&gt;
  &lt;li&gt;`dbt` генерирует одну атомарную операцию `MERGE` для таблицы Iceberg, которая эффективно выполняет все эти обновления и вставки за одну транзакцию.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;b&gt;Результат:&lt;/b&gt; В `silver.customers_snapshot` мы получаем идеальную таблицу SCD Type 2, которая обновляется автоматически и надежно, без написания сложной логики `MERGE` вручную.&lt;/p&gt;
</description>
</item>

<item>
<title>Книга “I ♥ Logs” Джея Крепса</title>
<guid isPermaLink="false">259</guid>
<link>https://gavrilov.info/all/kniga-i-logs-dzheya-krepsa/</link>
<pubDate>Wed, 06 Aug 2025 00:37:25 +0300</pubDate>
<author></author>
<comments>https://gavrilov.info/all/kniga-i-logs-dzheya-krepsa/</comments>
<description>
&lt;h4&gt;Часть 1: Книга “I Love Logs” EVENT DATA, STREAM PROCESSING, AND DATA INTEGRATION&lt;/h4&gt;
&lt;p&gt;Джей Крепс&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/Snimok-ekrana-2025-08-06-v-00.11.45.png" width="900" height="362" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Оригинал тут: &lt;a href="https://a.gavrilov.info/data/posts/I_Heart_Logs-Jay_Kreps.pdf"&gt;I_Heart_Logs-Jay_Kreps.pdf &lt;/a&gt;&lt;/div&gt;
&lt;/div&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;ul&gt;
  &lt;li&gt;Ключевая идея: лог — это не просто текстовый файл для отладки, а упорядоченная, неизменяемая (append-only) последовательность записей (событий), снабженная уникальными, последовательно увеличивающимися номерами (offset’ами), которые служат “временем” в распределенной системе.&lt;/li&gt;
  &lt;li&gt;Он является “источником истины” (`source of truth`) и позволяет восстановить состояние системы.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;State Machine Replication Principle&lt;/b&gt;: Если два детерминированных процесса начинают в одном состоянии и получают одинаковые входные данные в одном и том же порядке, они произведут одинаковый вывод и закончат в одном и том же состоянии. Лог обеспечивает этот “одинаковый порядок”.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;b&gt;Роль логов в базах данных&lt;/b&gt;:
&lt;ul&gt;
  &lt;li&gt;Логи лежат в основе работы ACID-баз данных (commit log, transaction log) для обеспечения атомарности, изоляции и долговечности.&lt;/li&gt;
  &lt;li&gt;Используются для репликации данных между мастером и репликами (Change Data Capture – CDC).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;b&gt;Применения логов&lt;/b&gt;:
&lt;ul&gt;
  &lt;li&gt;&lt;b&gt;Интеграция данных (Data Integration)&lt;/b&gt;: Лог становится центральной “магистралью данных” или единой “шиной событий” для всей организации. Он решает проблему интеграции “N систем с N системами” (N²) путем преобразования ее в “N систем с одним логом” (N). Крепс приводит “Иерархию потребностей Маслоу для данных” (сбор/аквизиция данных, семантика, понимание, автоматизация), подчеркивая, что без надежного сбора данных невозможно ничего другого.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/Snimok-ekrana-2025-08-06-v-00.24.03.png" width="738" height="294" alt="" /&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Организационная масштабируемость**: Ответственность за чистоту и формат данных лежит на *производителе* данных, а не на потребителях или центральной команде ETL.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Потоковая обработка в реальном времени (Real-time Stream Processing)&lt;/b&gt;: Лог — это естественное представление потока данных. Любое событие в реальном времени, база данных, изменяющаяся с течением времени, — всё это логи.&lt;/li&gt;
&lt;li&gt;Крепс выступает за &lt;b&gt;Kappa-архитектуру&lt;/b&gt; как альтернативу Lambda-архитектуре.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Критика Lambda&lt;/b&gt;: Дублирование логики (один и тот же расчет в batch и stream слоях), сложность оперирования.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Альтернативная модель репроцессинга&lt;/b&gt;: Вместо двух отдельных фреймворков (batch и stream) — использовать единую потоковую систему, которая может пересчитывать историю, используя лог как источник исторических данных. Когда логика меняется, запускается новый потоковый Job с начала лога, записывающий результат в новую таблицу, и после догона старая таблица заменяется новой.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Проектирование распределенных систем&lt;/b&gt;: Лог упрощает дизайн. Вместо того, чтобы каждая система занималась согласованностью, репликацией и восстановлением, эти функции можно передать логированию.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Паттерн “Сервис = Лог + Serving Layer”&lt;/b&gt;: Лог хранит все изменения (source of truth), а “serving layer” (например, поисковая система, key-value хранилище) строит индексированные или материализованные представления на основе лога для быстрых запросов.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol start="4"&gt;
&lt;li&gt;&lt;b&gt;Технические особенности и оптимизации&lt;/b&gt;:
&lt;ul&gt;
  &lt;li&gt;&lt;b&gt;Партиционирование лога&lt;/b&gt;: Для горизонтального масштабирования (Kafka). Позволяет обрабатывать записи независимо, не требует глобального порядка. Порядок гарантируется только в пределах одной партиции.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Батчинг (Batching)&lt;/b&gt;: Соединение мелких операций в крупные для повышения пропускной способности.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Zero-Copy Data Transfer&lt;/b&gt;: Передача данных между слоями памяти без их копирования, что улучшает производительность.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Log Compaction (Компактирование лога)&lt;/b&gt;: Оптимизация хранения для “лагов изменений” (changelogs). Вместо хранения всех версий записи, оставляется только последняя версия для каждого ключа. Это позволяет восстановить *текущее* состояние, но не *всю* историю.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="5"&gt;
&lt;li&gt;&lt;b&gt;Дуальность таблиц и событий (Tables and Events Are Dual)&lt;/b&gt;:
&lt;ul&gt;
  &lt;li&gt;Крепс проводит аналогию с системами контроля версий (Git): история изменений (патчи) — это лог, а текущая рабочая копия — это таблица.&lt;/li&gt;
  &lt;li&gt;Данные могут свободно “перетекать” между состоянием (таблица) и потоком изменений (лог).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;b&gt; Стоило бы дополнить (2023-2024):&lt;/b&gt;&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Эволюция экосистемы&lt;/b&gt;:
&lt;ul&gt;
  &lt;li&gt;Книга вышла в 2014 году. С тех пор Kafka стала де-факто стандартом. Появились альтернативы &lt;a href="https://pulsar.apache.org"&gt;Apache Pulsar&lt;/a&gt; его, кстати, умеет читать и писать Seatunnel :) и множество надстроек/фреймворков (Kafka Streams, Flink SQL, Materialize).&lt;/li&gt;
  &lt;li&gt;Рост Serverless-архитектур и их интеграция с логами (AWS Lambda, Google Cloud Functions, Azure Functions как потребители логов).&lt;/li&gt;
  &lt;li&gt;Повсеместное использование Kubernetes и операторов для развертывания и управления Kafka-кластерами.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;b&gt;Управление схемами (Schema Management)&lt;/b&gt;:
&lt;ul&gt;
  &lt;li&gt;Книга упоминает структурированные логи, но не углубляется в детали. Сегодня критически важен &lt;b&gt;Schema Registry&lt;/b&gt; (например, Confluent Schema Registry или &lt;a href="http://apicur.io)"&gt;http://apicur.io)&lt;/a&gt; для обеспечения совместимости схем данных в логах и управления их версиями. Это предотвращает “data swamp” и делает логи действительно надежным источником данных.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;b&gt;Качество данных и Observability&lt;/b&gt;:
&lt;ul&gt;
  &lt;li&gt;Помимо “структуры”, важна *семантика* и *качество* данных. Мониторинг “data quality”, “data lineage” (происхождение данных) и “data governance” становятся ключевыми.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Observability&lt;/b&gt;: Трассировка событий через лог-пайплайн (например, OpenTelemetry), сбор метрик (lag потребителей, пропускная способность, ошибки) с Prometheus/Grafana.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="4"&gt;
&lt;li&gt;&lt;b&gt;Безопасность (Security)&lt;/b&gt;:
&lt;ul&gt;
  &lt;li&gt;Шифрование данных в пути (TLS) и в состоянии покоя (at-rest encryption).&lt;/li&gt;
  &lt;li&gt;Аутентификация и авторизация (RBAC) для продюсеров и потребителей Kafka.&lt;/li&gt;
  &lt;li&gt;Аудит доступа к логам.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="5"&gt;
&lt;li&gt;&lt;b&gt;Паттерны микросервисной архитектуры&lt;/b&gt;:
&lt;ul&gt;
  &lt;li&gt;&lt;b&gt;Event Sourcing&lt;/b&gt; и &lt;b&gt;CQRS&lt;/b&gt; стали стандартными паттернами.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Saga Pattern&lt;/b&gt; для координации распределенных транзакций между микросервисами, часто реализуемых через лог.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Data Mesh&lt;/b&gt;: Принцип, что данные должны рассматриваться как продукт. Команда-владелец домена отвечает за свой “дата-продукт” и предоставляет его через лог, который является частью этого “продукта”.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="6"&gt;
&lt;li&gt;&lt;b&gt;Real-time Analytics и ML&lt;/b&gt;:
&lt;ul&gt;
  &lt;li&gt;Пайплайны с логами используются для обучения и инференса ML-моделей в реальном времени. Например, логи кликов для рекомендательных систем.&lt;/li&gt;
  &lt;li&gt;Появление GPU-ускоренных фреймворков для потоковой обработки (например, NVIDIA RAPIDS).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="7"&gt;
&lt;li&gt;&lt;b&gt;Антипаттерны и ошибки&lt;/b&gt;: Конкретные примеры из практики, как неправильное внедрение логов может привести к проблемам.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;h4&gt;&lt;b&gt;Часть 2: Современный взгляд Логи: Кровеносная система Data-Driven компаний&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;Представьте себе, что данные – это жизненная сила вашей компании, а IT-инфраструктура – ее тело. Тогда логи, как это ни парадоксально, стали бы ее &lt;b&gt;кровеносной системой&lt;/b&gt;. Они несут информацию от каждой клетки к каждому органу, обеспечивая слаженность и жизнеспособность всего организма.&lt;/p&gt;
&lt;p&gt;В эпоху распределенных систем, микросервисов, Big Data и искусственного интеллекта, когда скорость обработки информации определяет конкурентное преимущество, традиционные подходы к интеграции и обработке данных трещат по швам. Книга, которая у вас в руках – это переосмысление ключевых идей Джея Крепса, соавтора Apache Kafka, о том, как “скромный” лог превратился из технической детали в центральный архитектурный примитив.&lt;/p&gt;
&lt;p&gt;Мы пройдем путь от понимания природы лога до его применения в масштабных системах, интеграции данных, потоковой обработке и построении отказоустойчивых архитектур. Эта книга не только сохранит оригинальные прозрения, но и дополнит их новейшими практиками, инструментами и опытом, накопленным IT-индустрией за последнее десятилетие. Вы узнаете, как избежать распространенных ошибок и построить по-настоящему гибкую и масштабируемую систему, где данные действительно “текут” свободно.&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;h4&gt;&lt;b&gt;Глава 1: Лог: Недооцененный фундамент современных систем&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;Когда речь заходит о логах, большинство инженеров представляют себе длинные текстовые файлы с отладочной информацией. Однако, как показал Джей Крепс, истинная природа лога гораздо глубже.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Что такое Лог? Глубже, чем кажется.&lt;/b&gt;&lt;br /&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;&lt;b&gt;Принцип State Machine Replication: Волшебство порядка&lt;/b&gt;&lt;br /&gt;
Это краеугольный камень распределенных систем. Он гласит:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;b&gt;Если два идентичных, детерминированных процесса начинают в одном состоянии и получают одинаковые входные данные в одном и том же порядке, они произведут одинаковый вывод и закончат в одном и том же состоянии.&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;В этом принцип “лога” критически важен: он обеспечивает “одинаковый порядок” входных данных для всех реплик. Если у вас есть лог всех изменений (событий), вы можете “воспроизвести” этот лог на разных машинах, чтобы они достигли идентичного состояния.&lt;/p&gt;
&lt;p&gt;*Пример из практики*: Банковский счет. Вместо хранения одного числа (текущий баланс), мы храним лог всех транзакций: “снятие 1000 руб.”, “поступление 5000 руб.”. Текущий баланс – это всего лишь функция, которая суммирует все записи в логе до текущего момента. Если банк “забудет” состояние баланса, он всегда может его восстановить, проиграв лог всех транзакций.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Логи в базах данных: Невидимый двигатель&lt;/b&gt;&lt;br /&gt;
Внутри любой надежной реляционной базы данных или NoSQL-хранилища уже давно работает лог: `commit log` или `transaction log`. Он гарантирует, что даже при сбое системы, транзакции не будут потеряны, а данные останутся согласованными (свойства ACID). Механизмы репликации баз данных (например, бинарные логи MySQL или WAL PostgreSQL) – это по сути потоковая передача записей из такого лога. Это и есть &lt;b&gt;Change Data Capture (CDC)&lt;/b&gt; – захват изменений данных.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Дополнение (2023-2024):&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Структурированные логи и схемы&lt;/b&gt;: Для машинного чтения и обработки логам необходим строгий формат. Сегодня это почти всегда JSON, Apache Avro или Google Protocol Buffers.
&lt;ul&gt;
  &lt;li&gt;Рекомендация&lt;b&gt;: Используйте &lt;/b&gt;Schema Registry**. Это централизованное хранилище ваших схем, которое позволяет эволюционировать схемы логов, не ломая обратную совместимость. Оно критически важно для долгосрочной жизнеспособности вашей data-инфраструктуры. Без Schema Registry ваши логи быстро превратятся в “data swamp” – болото неструктурированных, непонятных данных.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Лог как Event Stream&lt;/b&gt;: В современных архитектурах каждый чих в системе – это событие. Логи веб-сервера, действия пользователя, метрики микросервисов, изменения в БД – все это может быть представлено как лог событий.&lt;/li&gt;
&lt;/ul&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;: Произвольные текстовые сообщения в логах делают их крайне сложными для автоматического анализа и интеграции. Всегда! используйте структурированные форматы.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Игнорирование порядка&lt;/b&gt;: Если события записываются без гарантии порядка, вы никогда не сможете надежно воспроизвести состояние системы или построить корректные агрегаты.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;h4&gt;&lt;b&gt;Глава 2: Данные как потоки: Интеграция через Логи&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;Одна из самых болезненных проблем в больших компаниях – это интеграция данных. Исторически это решалось кастомными ETL (Extract, Transform, Load) пайплайнами, где каждая система “говорила” с каждой. Такая модель приводит к экспоненциальному росту сложности (N² соединений для N систем).&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Централизованная шина событий: Революция в интеграции&lt;/b&gt;&lt;br /&gt;
Идея Крепса: вместо N² соединений, создайте универсальный централизованный лог, который будет выступать в роли “шины событий” или “артерии данных”.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Производители данных&lt;/b&gt;: Системы, генерирующие данные, публикуют их в этот центральный лог.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Потребители данных&lt;/b&gt;: Системы, которым нужны эти данные, подписываются на соответствующие части лога (топики) и потребляют их независимо, в своем темпе.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/Snimok-ekrana-2025-08-06-v-00.05.12.png" width="1092" height="252" alt="" /&gt;
&lt;/div&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;```mermaid
graph LR
A[Система 1 (Продюсер)] -- Публикует --&amp;gt; C(Центральный Лог)
B[Система 2 (Продюсер)] -- Публикует --&amp;gt; C
C -- Потребляет --&amp;gt; D[Система A (Потребитель)]
C -- Потребляет --&amp;gt; E[Система B (Потребитель)]
C -- Потребляет --&amp;gt; F[Система C (Потребитель)]
```&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Вместо множества прямых соединений между A-D, A-E, A-F, B-D, B-E, B-F, мы получаем лишь несколько соединений к центральному логу. Сложность снижается с N² до N.&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;: Понимание значения данных, их контекста, метаданных.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Понимание&lt;/b&gt;: Способность строить отчеты, визуализации.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Автоматизация&lt;/b&gt;: Реализация сложных алгоритмов, прогнозов.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Задача интеграции данных лежит в основе этой иерархии. Логи — это инструмент для её решения.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Дополнение (2023-2024):&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Data Mesh и Data Products&lt;/b&gt;: Эта концепция идеально ложится на идею центрального лога. Каждая команда-владелец домена (например, “Клиенты”, “Заказы”) становится ответственной за свой “Data Product”. Этот продукт включает в себя данные (часто в виде топиков лога), их схемы, качество, доступность и документацию.
&lt;ul&gt;
  &lt;li&gt;&lt;b&gt;Рекомендация&lt;/b&gt;: Внедряйте `Data Contracts`. Это соглашения между командами о структуре и семантике данных, которые они передают через лог, аналогично API-контрактам.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Cloud-Native решения&lt;/b&gt;:
&lt;ul&gt;
  &lt;li&gt;&lt;b&gt;Managed Kafka&lt;/b&gt;: Облачные провайдеры предлагают управляемые сервисы Kafka (Confluent Cloud, AWS MSK, Azure Event Hubs). Это снимает бремя операционного управления.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;CDC&lt;/b&gt;: Инструменты вроде &lt;b&gt;Debezium&lt;/b&gt; позволяют легко интегрировать изменения из традиционных баз данных (PostgreSQL, MySQL, MongoDB) напрямую в Kafka в реальном времени, превращая их в логи событий.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Трансформации данных&lt;/b&gt;: Где делать ETL?
&lt;ul&gt;
  &lt;li&gt;&lt;b&gt;Source-side&lt;/b&gt;: Продюсер должен публиковать максимально чистые, канонические данные.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Stream-side&lt;/b&gt;: Для добавления обогащённых данных или агрегатов могут быть использованы потоковые процессоры (см. Глава 3), создающие новые, производные топики лога.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Sink-side&lt;/b&gt;: Минимальные трансформации при загрузке в целевые системы (например, для специфичных схем БД хранилища).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Ошибки, которых стоит избегать:&lt;/b&gt;&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;“Big Ball of Mud”&lt;/b&gt;: Не пытайтесь создавать слишком сложные ETL-пайплайны внутри самого лога. Идеально, если лог остаётся “сырым” источником событий, а трансформации и обогащения происходят в отдельных потоковых приложениях.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Отсутствие ownership&lt;/b&gt;: Если нет четкой ответственности за данные, опубликованные в логе, они быстро теряют качество. Команда-производитель должна быть “владельцем” своих данных в логе.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Blindly копирование всего&lt;/b&gt;: Не все данные нужны всем. Фильтруйте и маршрутизируйте данные к нужным потребителям, чтобы не перегружать системы и сократить расходы.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;h4&gt;&lt;b&gt;Глава 3: Потоковая обработка в реальном времени и не только&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;Логи и потоковая обработка неотделимы друг от друга. Лог — это естественная модель для потока событий.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Что такое потоковая обработка? Шире, чем кажется.&lt;/b&gt;&lt;br /&gt;
Крепс расширил определение потоковой обработки. Это не просто “обработка данных по мере их поступления и затем отбрасывание”. Это &lt;b&gt;непрерывная обработка данных&lt;/b&gt;, способная выдавать результаты с низкой задержкой, но при этом иметь дело с историческими данными (то есть, лог можно переиграть).&lt;/p&gt;
&lt;p&gt;&lt;b&gt;От Lambda к Kappa: Парадокс репроцессинга&lt;/b&gt;&lt;br /&gt;
Традиционная &lt;b&gt;Lambda-архитектура&lt;/b&gt; предполагала два параллельных пути обработки:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Batch-слой (партия)&lt;/b&gt;: Высокая задержка, высокая точность, обработка всей истории (например, Hadoop MapReduce).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Speed-слой (скорость)&lt;/b&gt;: Низкая задержка, возможно, меньшая точность, обработка только новых данных (например, Storm).&lt;br /&gt;
Результаты из обоих слоев объединяются для получения полной картины.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Проблема Lambda&lt;/b&gt;: Дублирование бизнес-логики. Один и тот же расчет должен быть написан и поддерживаться дважды, на двух разных фреймворках (например, HiveQL/Spark для batch и Flink/Storm для stream). Это приводит к ошибкам, задержкам в разработке и высоким операционным издержкам.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Kappa-архитектура (Преимущество лога): Изобретая колесо заново, но лучше.&lt;/b&gt;&lt;br /&gt;
Крепс предложил элегантную альтернативу — &lt;b&gt;Kappa-архитектуру&lt;/b&gt;, которая устраняет необходимость в отдельном batch-слое. Идея проста:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Храните все сырые данные в логе (Kafka)&lt;/b&gt;: Настройте достаточно длинный `retention` (срок хранения), например, 30, 90 дней или даже дольше, если это необходимо для исторического анализа.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Единый потоковый процессор&lt;/b&gt;: Используйте один фреймворк (например, Apache Flink, Kafka Streams) для обработки данных. Этот же код обрабатывает как новые, так и исторические данные.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Репроцессинг без боли&lt;/b&gt;: Если вам нужно изменить логику обработки или исправить ошибку:
&lt;ul&gt;
  &lt;li&gt;Запустите &lt;b&gt;новый экземпляр&lt;/b&gt; потокового Job.&lt;/li&gt;
  &lt;li&gt;Он начинает читать данные &lt;b&gt;с начала лога&lt;/b&gt;.&lt;/li&gt;
  &lt;li&gt;Результаты записываются в &lt;b&gt;новую целевую таблицу/топик&lt;/b&gt;.&lt;/li&gt;
  &lt;li&gt;Как только новый Job “догонит” текущее время, переключите потребителей с “устаревшей” целевой таблицы на “новую”.&lt;/li&gt;
  &lt;li&gt;Остановите и удалите старый Job и старую таблицу.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/Snimok-ekrana-2025-08-06-v-00.04.01.png" width="1092" height="680" alt="" /&gt;
&lt;/div&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;```mermaid
graph TD
    A[Исходный Лог (Kafka)]
    B[Старый Processing Job (v1)]
    C[Новый Processing Job (v2)]

    A -- Читает с offset 0 --&amp;gt; C
    A -- Читает с текущего offset --&amp;gt; B

    B -- Записывает в --&amp;gt; D[Старая Выходная Таблица]
    C -- Записывает в --&amp;gt; E[Новая Выходная Таблица]

    F[Приложение]--&amp;gt;D
    subgraph Reprocessing
        C
    end
    subgraph Switch
        direction LR
        F --&amp;gt; G[Переключить на E]
        G --&amp;gt; H[Удалить D, остановить B]
    end
```&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;b&gt;Дополнение (2023-2024):&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Фреймворки&lt;/b&gt;:
&lt;ul&gt;
  &lt;li&gt;Apache Flink**: Де-факто стандарт для сложных stateful-вычислений с `exactly-once` семантикой. Поддерживает `event time`, `watermarks` (для обработки событий, пришедших не по порядку) и гибкие окна агрегации.&lt;/li&gt;
  &lt;li&gt;Kafka Streams / ksqlDB**: Для более простых задач обработки в рамках экосистемы Kafka. Идеально для микросервисов.&lt;/li&gt;
  &lt;li&gt;Apache Spark Streaming / Structured Streaming**: Позволяет использовать привычные API Spark для потоков.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Работа с состоянием (Stateful Processing)&lt;/b&gt;: Многие потоковые задачи требуют сохранения состояния (например, подсчёт уникальных пользователей за час). Современные фреймворки (Flink) позволяют хранить это состояние отказоустойчиво, часто используя RocksDB локально и чекпоинты в удаленном хранилище (S3/HDFS).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Real-time OLAP / Data Warehousing&lt;/b&gt;: Появляется класс решений, которые строят агрегаты и индексы напрямую из логов для интерактивных аналитических запросов (например, ClickHouse, Apache Druid, Materialize).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;GPU-ускорение&lt;/b&gt;: Для ML-инференса и сложных расчетов на потоках, где время критично (например, обнаружение аномалий, фрод-мониторинг), начинают использоваться GPU-ускоренные библиотеки (NVIDIA RAPIDS).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Ошибки, которых стоит избегать:&lt;/b&gt;&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Игнорирование late data&lt;/b&gt;: События в реальном мире не всегда приходят по порядку. Используйте `watermarks` и `event time` для корректной обработки “поздних” данных.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Репроцессинг “на потом”&lt;/b&gt;: Откладывание возможности репроцессинга приводит к накоплению технического долга и невозможности быстро исправлять ошибки в логике. Заложите её в архитектуру с самого начала.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Чрезмерное усложнение&lt;/b&gt;: Не пытайтесь написать собственный потоковый движок. Используйте проверенные фреймворки, они уже решили большинство проблем с распределенностью, отказоустойчивостью и производительностью.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;h4&gt;&lt;b&gt;Глава 4: Логи как фундамент для отказоустойчивых систем&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;Помимо интеграции и потоковой обработки, логи играют решающую роль в построении самих распределенных систем, упрощая их внутреннюю архитектуру.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Паттерн “Сервис = Лог + Serving Layer”&lt;/b&gt;&lt;br /&gt;
В этом паттерне логика сервиса разделяется на две основные части:&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Лог (The Log)&lt;/b&gt;: Выступает как *единственный источник истины* для всех изменений состояния сервиса. Все записи (события, команды) сначала попадают в лог.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Serving Layer (Слой обслуживания/запросов)&lt;/b&gt;: Это набор вычислительных узлов, которые подписываются на лог и строят локальные, оптимизированные для запросов, представления данных (индексы).
&lt;ul&gt;
  &lt;li&gt;Пример: Пользователь хочет обновить свой профиль. Запрос на обновление фиксируется как событие в логе. Serving Layer, потребляя это событие, обновляет свою локальную копию данных (например, в базе данных или поисковом индексе Elasticsearch). Когда пользователь запрашивает профиль, запрос идет в Serving Layer.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Преимущество&lt;/b&gt;: Serving Layer может быть оптимизирован под конкретный тип запроса (например, Elasticsearch для полнотекстового поиска, Redis для быстрого key-value доступа), но при этом получать все данные из единого, надежного лога.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/Snimok-ekrana-2025-08-06-v-00.03.18.png" width="1090" height="372" alt="" /&gt;
&lt;/div&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;```mermaid
graph TD
    A[Client] --&amp;gt; B[API Gateway/Микросервис записи]
    B -- Записывает событие/изменение --&amp;gt; C(Центральный Лог)

    C -- Подписывается --&amp;gt; D[Serving Layer 1 (напр. Elasticsearch)]
    C -- Подписывается --&amp;gt; E[Serving Layer 2 (напр. Redis Cache)]
    C -- Подписывается --&amp;gt; F[Serving Layer 3 (напр. Data Warehouse)]

    A -- Читает --&amp;gt; D
    A -- Читает --&amp;gt; E
```&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;b&gt;Преимущества такой архитектуры:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Отказоустойчивость и восстановление&lt;/b&gt;: Если Serving Layer упадет, он может полностью восстановить свое состояние, “проиграв” лог с самого начала или с последнего чекпоинта. Лог является его бэкапом.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Изоляция сбоев&lt;/b&gt;: Падение одного Serving Layer не влияет на способность других Serving Layer’ов продолжать работу.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Детерминированность&lt;/b&gt;: Гарантия порядка из лога обеспечивает согласованность данных во всех Serving Layer’ах.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Горизонтальное масштабирование&lt;/b&gt;: Лог можно партиционировать (делим данные на части), и каждый Serving Layer может обрабатывать одну или несколько партиций, что позволяет добавлять узлы по мере роста нагрузки.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Отсутствие блокировок&lt;/b&gt;: Поскольку записи идут в лог, а чтение происходит из Serving Layer, это значительно снижает конкуренцию и улучшает параллелизм.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Log Compaction: Компактирование истории&lt;/b&gt;&lt;br /&gt;
Не всегда нужно хранить полную историю каждого изменения. Например, если вы отслеживаете текущее местоположение курьера, вам нужна только *последняя* координата, а не весь его путь.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Log Compaction (компактирование лога)&lt;/b&gt; – это процесс, при котором для каждого ключа в логе сохраняется только его *последнее* значение, а все предыдущие дубликаты удаляются.  &lt;br /&gt;
Это позволяет логу действовать как &lt;b&gt;changelog&lt;/b&gt; (журнал изменений), который, будучи проигранным с начала, воссоздаст *текущее* состояние распределенной таблицы.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Пример&lt;/b&gt;: Kafka умеет выполнять компактирование топиков, что идеально подходит для хранения состояния Key-Value пар (например, текущие балансы счетов, последние известные IP-адреса).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Дополнение (2023-2024):&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Event Sourcing&lt;/b&gt;: Паттерн, при котором основное состояние приложения сохраняется как последовательность событий в логе, а не как изменяемое состояние в базе данных. Состояние агрегатов получается путем применения всех событий.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Command Query Responsibility Segregation (CQRS)&lt;/b&gt;: Часто используется вместе с Event Sourcing. Команды (изменения) записываются в лог, а запросы (чтения) обслуживаются из оптимизированных для чтения материализованных представлений, построенных из того же лога.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Saga Pattern&lt;/b&gt;: Для координации долгих распределенных транзакций между множеством микросервисов, лог событий часто используется как механизм асинхронной связи и координации. Каждый сервис публикует событие о завершении своей части работы, а координатор Саги реагирует на эти события.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Kubernetes Operators&lt;/b&gt;: Для управления сложностью распределенных лог-систем, таких как Kafka, существуют Kubernetes Operators, которые автоматизируют развертывание, масштабирование, восстановление и обновление кластеров.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Observability (наблюдаемость)&lt;/b&gt;: Логи — это не только данные, но и инструмент для понимания поведения системы. Добавьте трассировку (`trace_id` в события) для отслеживания пути запроса через множество микросервисов и логов. Анализируйте `consumer lag` (отставание потребителей) как ключевую метрику здоровья потоковой системы.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Ошибки, которых стоит избегать:&lt;/b&gt;&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;“Я напишу свою Kafka”&lt;/b&gt;: Построение надежной распределенной лог-системы чрезвычайно сложно. Используйте проверенные решения (Kafka, Pulsar).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Забыть о версионировании&lt;/b&gt;: Изменения в структуре событий могут сломать старых потребителей. Используйте Schema Registry и стратегии совместимости схем (backward/forward compatibility).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Ручное управление состоянием&lt;/b&gt;: Не пытайтесь управлять состоянием stateful-приложений вручную. Доверьте эту задачу фреймворкам потоковой обработки, которые используют лог для отказоустойчивости.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;h4&gt;&lt;b&gt;Глава 5: Безопасность, Надежность и Операционная Эффективность&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;Лог, будучи “источником истины” и “кровеносной системой” данных, требует самого высокого уровня внимания к безопасности, надежности и операционной эффективности.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Безопасность (Security): Доверяй, но проверяй&lt;/b&gt;&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Шифрование данных&lt;/b&gt;:
&lt;ul&gt;
  &lt;li&gt;&lt;b&gt;В пути (In-transit Encryption)&lt;/b&gt;: Всегда используйте TLS (Transport Layer Security) для обмена данными между клиентами (продюсерами/потребителями) и брокерами лога, а также между самими брокерами.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;В состоянии покоя (At-rest Encryption)&lt;/b&gt;: Шифруйте данные на диске, где хранятся логи. Это может быть реализовано на уровне операционной системы, файловой системы или диска (LUKS, AWS EBS Encryption).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Аутентификация и Авторизация (Authentication &amp; Authorization – RBAC)&lt;/b&gt;:
&lt;ul&gt;
  &lt;li&gt;&lt;b&gt;Аутентификация&lt;/b&gt;: Убедитесь, что только доверенные клиенты могут подключаться к лог-системе (например, с помощью SASL/Kerberos, SSL-сертификатов или OAuth 2.0).&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Авторизация (RBAC)&lt;/b&gt;: Применяйте принцип наименьших привилегий. Контролируйте, кто может записывать в конкретные топики, а кто может читать из них. Отдельные приложения могут иметь разрешения только на чтение из определённых топиков и запись в свои собственные выходные топики.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Аудит (Auditing)&lt;/b&gt;: Включите логи аудита для всех действий в лог-системе (кто, когда, что изменил или прочитал).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;b&gt;Надежность (Reliability): Будьте готовы ко всему&lt;/b&gt;&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Репликация данных&lt;/b&gt;: Для обеспечения надежности критически важные данные должны быть реплицированы. В Kafka это достигается за счет репликации партиций между брокерами. Определите `replication factor` (фактор репликации) в зависимости от критичности данных (обычно 3).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Диспетчер сбоев (Disaster Recovery)&lt;/b&gt;:
&lt;ul&gt;
  &lt;li&gt;&lt;b&gt;Внутрикластерная отказоустойчивость&lt;/b&gt;: Лог-система должна быть способна выдержать отказ отдельных узлов или зон доступности (Availability Zones) без потери данных.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Географическая репликация&lt;/b&gt;: Для защиты от сбоев целых дата-центров используйте мульти-кластерные развертывания с гео-репликацией (например, MirrorMaker2 для Kafka).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Idempotence Producers&lt;/b&gt;: Убедитесь, что продюсеры могут повторно отправлять сообщения при сбоях без создания дубликатов, достигая `at-least-once` или `exactly-once` семантики.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;At-least-once, At-most-once, Exactly-once Semantics&lt;/b&gt;: Понимайте и выбирайте подходящую семантику доставки сообщений для каждого пайплайна. `Exactly-once` сложнее всего, но обеспечивает максимальную точность.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;b&gt;Операционная Эффективность (Operational Efficiency): Не замедляйтесь&lt;/b&gt;&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Партиционирование&lt;/b&gt;: Правильное партиционирование топиков критически важно.
&lt;ul&gt;
  &lt;li&gt;Должно быть достаточно партиций для параллельной обработки.&lt;/li&gt;
  &lt;li&gt;Ключи партиционирования должны распределять нагрузку равномерно.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Ошибка&lt;/b&gt;: Недостаточное количество партиций может привести к узким местам. Слишком много партиций усложняет управление и увеличивает нагрузку на брокеры.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Батчинг (Batching)&lt;/b&gt;: Соединяйте мелкие записи в большие “пакеты” перед отправкой в лог. Это значительно уменьшает накладные расходы на I/O и сетевые операции.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Zero-Copy&lt;/b&gt;: Используйте механизмы, позволяющие передавать данные из лога напрямую в сетевой сокет, минуя буферы приложения для копирования. Это снижает нагрузку на CPU.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Мониторинг&lt;/b&gt;: Ключ к здоровой системе.
&lt;ul&gt;
  &lt;li&gt;&lt;b&gt;Метрики брокеров&lt;/b&gt;: CPU, память, диск I/O, сетевой трафик, количество сообщений, пропускная способность.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Метрики топиков&lt;/b&gt;: Размер, количество партиций, скорость записи/чтения.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Метрики потребителей&lt;/b&gt;: &lt;b&gt;Consumer Lag&lt;/b&gt; (отставание потребителей) — это самая важная метрика. Если `consumer lag` растет, значит, потребитель не справляется с нагрузкой, и данные накапливаются.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Алерты&lt;/b&gt;: Настройте оповещения на критические метрики (высокий `consumer lag`, ошибки записи/чтения, недоступность брокеров).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Логирование и Трассировка&lt;/b&gt;: Стандартизируйте форматы логов приложений, отправляющих и потребляющих данные из лога. Включите корреляционные ID (`trace_id`, `span_id`) для отслеживания событий через всю распределенную систему (например, с помощью OpenTelemetry).&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Управление ресурсами&lt;/b&gt;: Убедитесь, что у брокеров лога достаточно ресурсов (CPU, RAM, диск I/O) для обработки пиковых нагрузок. Используйте быстрые диски (SSD/NVMe).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;b&gt;Дополнение (2023-2024): Chaos Engineering&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Для проверки устойчивости вашей лог-инфраструктуры к сбоям, регулярно проводите эксперименты в контролируемой среде.&lt;/li&gt;
&lt;li&gt;Примеры**: Имитация отказа брокера (убиваем процесс), сетевые проблемы (Partition), перегрузка диска, увеличение задержки для потребителя. Это помогает выявлять слабые места *до* того, как они проявятся в продакшене.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;h4&gt;&lt;b&gt;Заключение: пошаговый план к Data-Driven Будущему&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;Мы проделали большой путь, от понимания фундаментальной природы лога до его роли в современных распределенных системах, интеграции данных и потоковой обработке. Лог — это не просто техническая деталь, а стратегический актив, который позволяет вашей компании быть по-настоящему “data-driven”.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Краткие выводы:&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Лог — это источник истины&lt;/b&gt;: Он хранит историю изменений в гарантированном порядке.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Лог упрощает&lt;/b&gt;: Он решает проблемы интеграции (N² → N), репликации и восстановления.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Лог масштабирует&lt;/b&gt;: Благодаря партиционированию и оптимизациям, таким как батчинг и zero-copy.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Лог — это кровь в организме данных&lt;/b&gt;: Без него невозможно построить гибкую, реактивную и отказоустойчивую архитектуру.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Kappa лучше Lambda&lt;/b&gt;: Одна кодовая база для realtime и batch обработки.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;Ваш пошаговый план к Data-Driven Архитектуре, управляемой логами:&lt;/b&gt;&lt;/p&gt;
&lt;ol start="1"&gt;
&lt;li&gt;&lt;b&gt;Начните с аудита источников данных&lt;/b&gt;:
&lt;ul&gt;
  &lt;li&gt;Определите, какие данные генерируются вашими системами, какие из них критически важны, какие меняются со временем.&lt;/li&gt;
  &lt;li&gt;Поймите, где находятся “узкие места” в текущей интеграции.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="2"&gt;
&lt;li&gt;&lt;b&gt;Выберите платформу логов&lt;/b&gt;:
&lt;ul&gt;
  &lt;li&gt;&lt;b&gt;Выбор&lt;/b&gt;: Apache Kafka — это де-факто стандарт. Рассмотрите Apache Pulsar как альтернативу, если вам нужна расширенная гибкость.&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;Развертывание&lt;/b&gt;: Для начала можно использовать управляемые облачные сервисы (Confluent Cloud, AWS MSK, Azure Event Hubs) или самостоятельно развернуть Kafka в Kubernetes с помощью операторов. Не пытайтесь строить свой велосипед.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="3"&gt;
&lt;li&gt;&lt;b&gt;Внедрите Schema Registry&lt;/b&gt;:
&lt;ul&gt;
  &lt;li&gt;Это не опция, а &lt;b&gt;обязательное условие&lt;/b&gt;.&lt;/li&gt;
  &lt;li&gt;Соберите команды, которые генерируют данные, и начните совместно разрабатывать строгие схемы для каждого типа событий (Avro/Protobuf).&lt;/li&gt;
  &lt;li&gt;*Рекомендация*: Внедрите процесс `data contract` – соглашения между командами о формате и семантике данных.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="4"&gt;
&lt;li&gt;&lt;b&gt;Инструментируйте ключевые сервисы для публикации в лог&lt;/b&gt;:
&lt;ul&gt;
  &lt;li&gt;Начните с одного или двух высоконагруженных сервисов.&lt;/li&gt;
  &lt;li&gt;Используйте &lt;b&gt;Change Data Capture (CDC)&lt;/b&gt; (например, Debezium) для выгрузки изменений из баз данных в лог.&lt;/li&gt;
  &lt;li&gt;Для новых сервисов и пользовательских действий изначально проектируйте их как &lt;b&gt;Event Sourcing&lt;/b&gt;-системы, публикующие события в лог.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="5"&gt;
&lt;li&gt;&lt;b&gt;Настройте базовых потребителей и хранилища&lt;/b&gt;:
&lt;ul&gt;
  &lt;li&gt;Автоматизируйте загрузку данных из лога в ваше основное аналитическое хранилище (Data Warehouse, Data Lake, например, S3/HDFS + Spark/Hive).&lt;/li&gt;
  &lt;li&gt;Подключите первый “реальный” потребитель, например, систему мониторинга, которая отслеживает ключевые показатели бизнеса на основе событий из лога.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="6"&gt;
&lt;li&gt;&lt;b&gt;Разверните платформу потоковой обработки&lt;/b&gt;:
&lt;ul&gt;
  &lt;li&gt;Начните с Apache Flink или Kafka Streams. Они позволят вам обрабатывать данные из лога, обогащать их, агрегировать и создавать новые, производные потоки данных.&lt;/li&gt;
  &lt;li&gt;*Рекомендация*: Сначала решайте простые задачи (агрегаты, фильтрация), затем переходите к более сложным (stateful processing, windowing).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="7"&gt;
&lt;li&gt;&lt;b&gt;Сосредоточьтесь на Observability и Автоматизации&lt;/b&gt;:
&lt;ul&gt;
  &lt;li&gt;Внедрите комплексный мониторинг всей лог-инфраструктуры (брокеры, топики, потребители) с ключевыми метриками (consumer lag!).&lt;/li&gt;
  &lt;li&gt;Настройте алерты.&lt;/li&gt;
  &lt;li&gt;Автоматизируйте процессы развертывания, масштабирования и восстановления лог-компонентов.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="8"&gt;
&lt;li&gt;&lt;b&gt;Имплементируйте принципы безопасности&lt;/b&gt;:
&lt;ul&gt;
  &lt;li&gt;Шифрование, аутентификация, авторизация. Пусть это будет часть каждого нового внедрения.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="9"&gt;
&lt;li&gt;&lt;b&gt;Готовьтесь к репроцессингу&lt;/b&gt;:
&lt;ul&gt;
  &lt;li&gt;Убедитесь, что ваши логи хранят достаточно истории (длительный retention).&lt;/li&gt;
  &lt;li&gt;Проектируйте свои потоковые приложения с учетом возможности запуска нового экземпляра для пересчета исторических данных.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;ol start="10"&gt;
&lt;li&gt;&lt;b&gt;Примите философию Data Mesh&lt;/b&gt;:
&lt;ul&gt;
  &lt;li&gt;Меняйте культуру: поощряйте команды владеть своими данными как продуктами.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Эпилог: Лог – это не просто техническая деталь, а отражение бизнес-процессов. Каждая запись – атом вашей организационной ДНК. Превратите хаос данных в нарратив, где каждая транзакция – это предложение, а каждый поток – глава вашей бизнес-истории, благодаря надежной и гибкой кровеносной системе, управляемой логами.&lt;/b&gt;&lt;/p&gt;
</description>
</item>

<item>
<title>Кликозявый эластикозавр обзёрнообразный – ClickStack</title>
<guid isPermaLink="false">243</guid>
<link>https://gavrilov.info/all/klikozyavy-elastikozavr-obzyornoobrazny-clickstack/</link>
<pubDate>Thu, 05 Jun 2025 21:41:03 +0300</pubDate>
<author></author>
<comments>https://gavrilov.info/all/klikozyavy-elastikozavr-obzyornoobrazny-clickstack/</comments>
<description>
&lt;p&gt;&lt;b&gt;Представляем ClickStack&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Сегодня мы рады анонсировать ClickStack — новое опенсорсное решение для обсервабилити, созданное на базе ClickHouse. ClickStack предоставляет полноценное решение «из коробки» для работы с логами, метриками, трейсами и воспроизведением сессий. Оно работает на основе производительности и эффективности ClickHouse, но спроектировано как полноценный стек для обсервабилити — открытый, доступный и готовый для всех.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/image-192.png.jpg" width="2560" height="1320" alt="" /&gt;
&lt;div class="e2-text-caption"&gt;Оригинал статья тут: &lt;a href="https://clickhouse.com/blog/clickstack-a-high-performance-oss-observability-stack-on-clickhouse"&gt;https://clickhouse.com/blog/clickstack-a-high-performance-oss-observability-stack-on-clickhouse&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Подробнее тут: &lt;a href="https://clickhouse.com/use-cases/observability?loc=o11y"&gt;https://clickhouse.com/use-cases/observability?loc=o11y&lt;/a&gt;&lt;br /&gt;
Попробовать тут: &lt;a href="https://clickhouse.com/docs/use-cases/observability/clickstack/getting-started"&gt;https://clickhouse.com/docs/use-cases/observability/clickstack/getting-started&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;В течение многих лет крупные инженерные команды, такие как в Netflix и eBay, выбирали ClickHouse в качестве основной базы данных для обсервабилити. Её колоночная структура, сжатие и высокопроизводительный векторизованный движок запросов сделали её идеальной для хранения «широких событий» — записей с богатым контекстом и высокой кардинальностью, которые объединяют логи, метрики и трейсы. Этот современный подход к обсервабилити (некоторые называют его «Observability 2.0») отходит от традиционной модели «трёх столпов» и устраняет сложность объединения разрозненных источников телеметрии.&lt;/p&gt;
&lt;p&gt;До сих пор все преимущества этой модели были в основном доступны только командам, обладавшим ресурсами для создания специализированных решений для обсервабилити на базе ClickHouse. А все остальные? Они полагались на универсальные инструменты визуализации или сторонние проприетарные платформы, созданные на ClickHouse. Хотя эти инструменты предоставляли базовые интерфейсы для ClickHouse, они иногда требовали длинных SQL-запросов для рутинных задач обсервабилити или не в полной мере использовали производительность и открытую архитектуру ClickHouse.&lt;/p&gt;
&lt;p&gt;Сегодня всё меняется. С выпуском ClickStack на базе HyperDX мы уравниваем шансы. Этот полностью опенсорсный стек включает в себя готовый коллектор OpenTelemetry, пользовательский интерфейс, разработанный для «широких событий», запросы на естественном языке, воспроизведение сессий, оповещения и многое другое.&lt;/p&gt;
&lt;p&gt;И всё это работает на том же высокопроизводительном движке ClickHouse с высоким уровнем сжатия, которому доверяют крупнейшие имена в сфере обсервабилити.&lt;/p&gt;
&lt;p&gt;Раньше командам часто приходилось выбирать между дорогими проприетарными SaaS-продуктами и сборкой собственных решений из опенсорсных альтернатив. Поисковые движки предлагали быстрые и гибкие запросы, но их эксплуатация в больших масштабах и достижение высокой производительности агрегации оказывались сложными. Хранилища метрик обеспечивали лучшую производительность агрегации, но требовали жёсткой предварительной агрегации и не имели возможностей для глубокого поиска. Ни один из подходов не справлялся хорошо с данными высокой кардинальности, а их объединение добавляло сложности, не решая основной проблемы.&lt;/p&gt;
&lt;p&gt;С ClickStack вам не придётся выбирать — наслаждайтесь быстрым поиском и быстрыми агрегациями по данным высокой кардинальности в формате «широких событий». В больших масштабах. С открытым исходным кодом. И теперь — для всех.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Эволюция ClickHouse для обсервабилити&lt;/b&gt;&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/image-192.png" width="1600" height="1566" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;&lt;b&gt;Всего лишь очередная задача по работе с данными&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Первые пользователи ClickHouse осознали нечто фундаментальное: обсервабилити — это задача по работе с данными. Выбранная вами база данных определяет стоимость, масштабируемость и возможности вашей платформы для обсервабилити, поэтому её выбор часто является самым важным архитектурным решением при создании собственного решения или запуске компании в этой сфере.&lt;/p&gt;
&lt;p&gt;Именно поэтому ClickHouse уже много лет находится в основе стеков обсервабилити. От отраслевых гигантов, таких как Netflix и eBay, до стартапов в сфере обсервабилити, таких как Sentry и Dash0, ClickHouse обеспечивает работу с логами, метриками и трейсами в огромных масштабах. Её колоночное хранилище, агрессивное сжатие и векторизованный движок выполнения запросов значительно снижают затраты и обеспечивают выполнение запросов за доли секунды, что необходимо инженерам для отладки систем в реальном времени без ожидания медленных инструментов.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Всё, что вам нужно, — это «широкие события»… и колоночное хранилище&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;В нашей предыдущей статье «Состояние обсервабилити на основе SQL» и последующих публикациях мы подробно исследовали этот тренд. Хотя тогда мы не дали ему названия, он идеально совпадает с сегодняшним движением «Observability 2.0»: единая модель, построенная вокруг «широких событий», а не «столпов». Слишком долго команды полагались на отдельные хранилища для логов, метрик и трейсов, что приводило к фрагментации, ручной корреляции и ненужной сложности. «Широкие события» устраняют эти разрозненные хранилища, объединяя все сигналы обсервабилити в единую, запрашиваемую структуру.&lt;/p&gt;
&lt;p&gt;«Широкое событие» фиксирует полный контекст приложения в одной записи — пользователя, сервис, HTTP-путь, код состояния, результат кеширования и многое другое. Эта унифицированная структура является ключом к устранению разрозненности и обеспечению быстрого поиска и агрегации по данным высокой кардинальности — при условии, что у вас есть движок хранения, способный эффективно их сжимать и хранить!&lt;/p&gt;
&lt;p&gt;Хотя NoSQL-решения, такие как поисковые движки, приняли эту структуру, им не хватало производительности агрегации, чтобы реализовать её потенциал — они отлично подходили для поиска и «нахождения иголок в галактиках», но не для агрегации по широким диапазонам. Секретный ингредиент ClickHouse для решения этой проблемы остаётся неизменным: колоночное хранение, богатая библиотека кодеков для глубокого сжатия и массивно-параллельный движок, оптимизированный для аналитических нагрузок.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Эффективность ресурсов и масштабируемость&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;В ClickHouse Cloud мы пошли дальше и внедрили объектное хранилище, чтобы обеспечить разделение хранения и вычислений, что крайне важно, если вам нужно масштабировать вашу систему обсервабилити до петабайт и более, а также эластично масштабироваться. Для поддержки ещё более требовательных сценариев мы также ввели разделение вычислений, позволяя пользователям выделять вычислительные ресурсы для конкретных нагрузок (например, для приёма данных и для выполнения запросов), читая при этом одни и те же данные.&lt;/p&gt;
&lt;p&gt;По мере усложнения потребностей в обсервабилити мы поняли, что нативная поддержка JSON для полуструктурированных событий стала необходимым минимумом. ClickHouse развивался, чтобы удовлетворить эту потребность, добавив первоклассную поддержку полуструктурированных данных, сохраняя при этом преимущества колоночной обработки. Колонки создаются автоматически по мере поступления данных, и ClickHouse автоматически управляет повышением типов и ростом колонок. Это та самая «схема при записи» (schema-on-write), которая вам нужна для обсервабилити, с производительностью, сжатием и гибкостью, ожидаемыми от современного аналитического движка.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Рост популярности OpenTelemetry&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Эта эволюция совпала с ростом популярности OpenTelemetry (OTel), который сейчас является стандартом де-факто для сбора телеметрии, включая логи, метрики и трейсы. Мы начали официально поддерживать и вносить вклад в OpenTelemetry Exporter для ClickHouse.&lt;/p&gt;
&lt;p&gt;OpenTelemetry стал большим прорывом для нашей экосистемы. Он предлагает стандартизированный, независимый от поставщика способ сбора и экспорта данных обсервабилити, а его коллектор можно настроить для отправки данных напрямую в ClickHouse с помощью экспортёра, который мы теперь помогаем поддерживать. Мы тесно сотрудничали с сообществом, чтобы убедиться, что экспортёр надёжен, масштабируем и соответствует основным принципам ClickHouse.&lt;/p&gt;
&lt;p&gt;Одной из самых сложных проблем, которую мы решили на раннем этапе, был дизайн схемы. Не существует универсальной схемы для обсервабилити; у каждой команды свои паттерны запросов, потребности в хранении и архитектуры сервисов. Поэтому экспортёр поставляется со схемами по умолчанию для логов, метрик и трейсов, которые хорошо подходят большинству пользователей, но мы призываем команды настраивать их в соответствии со своими собственными нагрузками.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Недостающие элементы&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Но, как мы быстро поняли, просто иметь отличную базу данных, хорошую схему и надёжные средства сбора и приёма данных недостаточно. Инженерам нужен готовый к использованию приём данных, визуализация, оповещения и пользовательский интерфейс, адаптированный под их рабочий процесс. До сих пор это означало использование OpenTelemetry для сбора и Grafana для дашбордов.&lt;/p&gt;
&lt;p&gt;Это работало достаточно хорошо — даже наша собственная команда по обсервабилити заменила Datadog стеком на базе ClickHouse, сэкономив миллионы и добившись снижения затрат более чем в 200 раз. Сегодня наша внутренняя система логирования хранит более 43 петабайт данных OpenTelemetry, со схемами и первичными ключами, настроенными специально для такого масштаба. Это доказало производительность и экономическую эффективность подхода, но мы знали, что опыт может быть проще.&lt;/p&gt;
&lt;p&gt;Мы хотели чего-то более продуманного. Более простого способа для начала работы. Но самое главное — интерфейс, созданный для ClickHouse. И не просто любой интерфейс, а тот, который понимает, как строить эффективные запросы, выявлять паттерны в «широких событиях» и обеспечивать исключительный пользовательский опыт, не скрывая при этом мощь базы данных.&lt;/p&gt;
&lt;p&gt;Наконец, хотя мы считаем, что обсервабилити на основе SQL сыграла важную роль в укреплении модели «широких событий», мы также понимали, что должны пойти навстречу пользователям. Поисковые движки, такие как стек ELK, добились успеха, потому что они предлагали нечто интуитивно понятное: естественный язык для запроса логов. Мы хотели предоставить такой же опыт нашим пользователям, но на базе ClickHouse.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Добро пожаловать, HyperDX&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Именно тогда мы нашли HyperDX — опенсорсный слой для обсервабилити, специально созданный на ClickHouse. Когда HyperDX открыл исходный код своего интерфейса v2 в конце 2024 года, мы протестировали его внутри компании и быстро поняли, что это и есть недостающий элемент. Настройка была бесшовной, опыт разработчика — превосходным, и мы знали, что наши пользователи заслуживают того же.&lt;/p&gt;
&lt;p&gt;HyperDX принёс всё, что мы искали: &lt;a href="https://github.com/hyperdxio/hyperdx"&gt;https://github.com/hyperdxio/hyperdx&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Сбор данных на основе стандартов:** HyperDX с самого начала использовал OpenTelemetry, что идеально совпало с нашими инвестициями в экспортёр OpenTelemetry для ClickHouse.&lt;/li&gt;
&lt;li&gt;Опенсорс в первую очередь:** Мы считаем, что надёжные инструменты для обсервабилити должны быть доступны всем, и HyperDX разделяет эту философию. Его облачно-нативная архитектура обеспечивает простую и экономичную эксплуатацию.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Помимо соответствия стандартам, HyperDX создан с учётом особенностей ClickHouse. Команда серьёзно относится к оптимизации запросов, так что вам не придётся об этом думать. Пользовательский интерфейс тесно связан с движком, обеспечивая быструю и надёжную производительность там, где миллисекунды имеют значение, особенно во время расследования инцидентов.&lt;/p&gt;
&lt;p&gt;В сочетании со встроенным шлюзом для коллектора OpenTelemetry и схемой, оптимизированной для интерфейса HyperDX, ClickStack объединяет приём, хранение и визуализацию данных в единое решение. Схема по умолчанию спроектирована так, чтобы работать «из коробки», поэтому пользователям не нужно о ней думать — если только они не захотят настроить её под свои конкретные нужды.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://gavrilov.info/pictures/image-193.png" width="1200" height="708" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Простота ClickStack означает, что каждый слой масштабируется независимо. Нужна более высокая пропускная способность приёма данных? Просто добавьте больше шлюзов коллектора OpenTelemetry. Нужно больше ресурсов для запросов или хранения? Масштабируйте ClickHouse напрямую. Эта модульная конструкция позволяет легко расти вместе с вашими данными и вашей командой — без полной перестройки стека.&lt;/p&gt;
&lt;p&gt;С момента приобретения HyperDX мы сосредоточились на упрощении продукта и расширении его гибкости. Вы можете использовать схему по умолчанию для бесшовной настройки «из коробки» или использовать собственную схему, адаптированную под ваши нужды. Как и в случае с самим ClickHouse, мы понимаем, что универсального решения не существует, и гибкость — ключ к масштабированию.&lt;/p&gt;
&lt;p&gt;&lt;video controls style="width: 100%; max-width: 740px; height: auto;"&gt;&lt;br /&gt;
&lt;source src="http://a.gavrilov.info/data/posts/clickstack_simple_v2_0c8e38c417.mp4" type="video/mp4"&gt;&lt;br /&gt;
Ваш браузер не поддерживает видео.&lt;br /&gt;
&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;В то же время мы остались верны своим SQL-корням. SQL остаётся универсальным языком данных, и для многих опытных пользователей ClickHouse это по-прежнему самый выразительный и эффективный способ исследования данных. Именно поэтому интерфейс HyperDX включает поддержку нативных SQL-запросов, предоставляя продвинутым пользователям прямой доступ к движку без компромиссов.&lt;/p&gt;
&lt;p&gt;&lt;video controls style="width: 100%; max-width: 740px; height: auto;"&gt;&lt;br /&gt;
&lt;source src="http://a.gavrilov.info/data/posts/clickstack_sql_small_a55c2027c3.mp4" type="video/mp4"&gt;&lt;br /&gt;
Ваш браузер не поддерживает видео.&lt;br /&gt;
&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Мы также добавили новые функции для облегчения отладки и исследования. Одним из примеров являются дельты событий, которые помогают пользователям быстро выявлять аномалии и регрессии производительности. Сэмплируя данные по уникальным значениям заданного атрибута, интерфейс выявляет различия в производительности и отклонения, облегчая понимание того, что изменилось и почему.&lt;/p&gt;
&lt;p&gt;&lt;video controls style="width: 100%; max-width: 740px; height: auto;"&gt;&lt;br /&gt;
&lt;source src="http://a.gavrilov.info/data/posts/event_deltas_simple_3bcfb720b3.mp4" type="video/mp4"&gt;&lt;br /&gt;
Ваш браузер не поддерживает видео.&lt;br /&gt;
&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;Возможно, самое важное — стек стал проще. С утверждением OpenTelemetry в качестве повсеместного стандарта все данные теперь поступают через OTel-коллектор. Настройка по умолчанию использует продуманную схему для быстрого старта, но пользователи могут изменять или расширять её по мере необходимости. Стек является нативным для OpenTelemetry, но не эксклюзивным для него: благодаря открытой схеме HyperDX может работать и с вашими существующими пайплайнами данных и схемами.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Заключение и взгляд в будущее&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;ClickStack представляет собой следующий этап развития инвестиций ClickHouse в экосистему обсервабилити, предлагая интуитивно понятное и продуманное полностековое решение на базе открытого исходного кода и открытых стандартов. Объединяя высокопроизводительный колоночный движок ClickHouse, стандарты инструментирования OpenTelemetry и специализированный интерфейс HyperDX в единое решение, мы наконец делаем современный подход к обсервабилити доступным для всех.&lt;/p&gt;
&lt;p&gt;Наша приверженность открытому исходному коду гарантирует, что ClickStack останется доступным для всех — от развёртываний с одним сервисом до систем объёмом в несколько петабайт. Мы продолжим инвестировать как в ядро базы данных для высокопроизводительной обсервабилити, так и в интеграции с уже зарекомендовавшими себя инструментами, такими как Grafana, обеспечивая бесшовную совместимость с существующими стеками.&lt;/p&gt;
&lt;p&gt;С ClickStack мы предлагаем больше, чем просто очередной инструмент — мы предоставляем единую основу, где все телеметрические сигналы сходятся в высокопроизводительной колоночной базе данных, дополненной запросами на естественном языке, воспроизведением сессий и возможностями оповещения прямо «из коробки».&lt;/p&gt;
&lt;p&gt;Начните свой путь с ClickStack, ознакомившись с нашим руководством по началу работы в документации.&lt;/p&gt;
&lt;p&gt;Начните работать с ClickHouse Cloud сегодня и получите $300 в виде кредитов. По окончании 30-дневного пробного периода вы можете продолжить работу по плану с оплатой по мере использования или связаться с нами, чтобы узнать больше о наших скидках за объём. Посетите нашу страницу с ценами для получения подробной информации.&lt;/p&gt;
&lt;p&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;Молниеносные запросы и мощные агрегации по логам, метрикам, трейсам, воспроизведениям сессий и ошибкам с непревзойденной эффективностью использования ресурсов даже для данных с самой высокой кардинальностью. Всё в одном стеке — на базе ClickHouse.&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;&lt;b&gt; Поиск, дашборды и оповещения&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;ClickStack объединяет логи, метрики, трейсы и воспроизведение сессий на одной платформе с помощью интерфейса HyperDX. Оптимизированный для ClickHouse, он поддерживает быстрый поиск в стиле Lucene и полный доступ по SQL для углубленного анализа с использованием более 100 встроенных функций.&lt;br /&gt;
Создавайте дашборды и оповещения с минимальной настройкой. Выявляйте аномалии с помощью дельт событий и ускоряйте анализ первопричин, используя паттерны событий.&lt;/p&gt;
&lt;p&gt;&lt;b&gt; Хранилище на базе ClickHouse&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Работая на базе ClickHouse, HyperDX выполняет поиск по терабайтам данных за секунды и ежедневно принимает миллиарды событий высокой кардинальности. ClickStack поставляется с оптимизированными схемами, что устраняет необходимость в ручной настройке и позволяет вам сосредоточиться на получении инсайтов.&lt;/p&gt;
&lt;p&gt;В ClickHouse Cloud ClickStack получает эластичное масштабирование и экономическую эффективность благодаря полному разделению хранения и вычислений. Приём данных и запросы могут выполняться независимо на выделенных ресурсах благодаря разделению между вычислительными мощностями, что обеспечивает стабильную производительность при любом масштабе.&lt;/p&gt;
&lt;p&gt;&lt;b&gt; Сбор данных&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;ClickStack нативно поддерживает стандарт OpenTelemetry, собирая логи, метрики и трейсы в виде «широких событий» — записей с богатым контекстом, которые объединяют данные обсервабилити в ClickHouse.&lt;br /&gt;
Благодаря нативной поддержке JSON, ClickHouse эффективно обрабатывает развивающиеся, полуструктурированные данные. Поля создаются автоматически при приёме данных, а сжатое колоночное хранилище обеспечивает быстрые запросы и высокую степень сжатия без необходимости предварительного определения схемы.&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;&lt;b&gt; Хотите собрать свой собственный стек?&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Нужен собственный пайплайн или схема? Интерфейс HyperDX не зависит от схемы и работает с любым пайплайном телеметрии, подключаясь к любому экземпляру ClickHouse для полного контроля над вашими данными обсервабилити.&lt;br /&gt;
Создаёте свой собственный стек? ClickHouse предоставляет все необходимые инструменты: высокопроизводительный движок SQL, приём данных по HTTP, масштабируемое хранилище MergeTree и материализованные представления для трансформации данных в реальном времени. Для гибкой работы с дашбордами используйте плагин для Grafana, чтобы сопоставлять данные из ClickHouse с другими источниками.&lt;/p&gt;
&lt;p&gt;---&lt;/p&gt;
&lt;p&gt;&lt;b&gt; Снизьте ваши затраты на обсервабилити&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;ClickHouse обеспечивает исключительную экономическую эффективность, избегая накладных расходов систем на базе JVM, благодаря аппаратно-оптимизированной колоночной структуре, которая сокращает объём хранения до 90% без ущерба для скорости.&lt;br /&gt;
Бесшовное масштабирование от одной машины до сотен ядер, с автоматическим ярусным хранением данных между локальными дисками и объектным хранилищем для максимальной производительности и эффективности.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;✨ Простое развертывание и обслуживание&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Оцените простоту эксплуатации благодаря однородной архитектуре ClickHouse — один исполняемый файл справляется со всем, от автономных развертываний до огромных кластеров.&lt;br /&gt;
Для нулевых накладных расходов выберите ClickStack в ClickHouse Cloud для автоматического масштабирования, резервного копирования и обслуживания. Разделение хранения и вычислений обеспечивает как бесконечную масштабируемость, так и производительность запросов менее чем за секунду благодаря интеллектуальному кэшированию.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;📄 Откройте для себя обсервабилити в реальном времени&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;ClickHouse спроектирован для обработки огромных объёмов непрерывных потоков входящих данных, поддерживая скорость приёма данных в гигабайты в секунду, при этом обеспечивая доступность новых данных для поиска с задержкой менее секунды.&lt;br /&gt;
Созданный для самых интенсивных нагрузок в реальном времени, HyperDX использует мощный набор функций агрегации и анализа ClickHouse с глубокими оптимизациями для обеспечения молниеносных запросов в системе обсервабилити.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;💡 Не только для обсервабилити&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;ClickHouse — это не просто хранилище для обсервабилити, это высокопроизводительная SQL база данных, созданная для быстрой аналитики.&lt;br /&gt;
Обсервабилити — это просто еще одна задача по работе с данными, и с ClickHouse вы можете бесшовно объединять данные обсервабилити, бизнес-данные и данные безопасности в одной системе, получая более глубокие инсайты по всему вашему стеку с помощью вашего любимого инструмента визуализации.&lt;/p&gt;
&lt;p&gt;&lt;b&gt; Инструментируйте ваши приложения&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Отслеживайте каждый лог, API-запрос, запрос к БД и многое другое всего несколькими строками кода. Инструментируйте и наблюдайте за своим стеком за считанные минуты с ClickStack.&lt;/p&gt;
</description>
</item>


</channel>
</rss>