Yuriy Gavrilov

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

KubeVela: Современная доставка приложений

В мире Cloud-Native технологий Kubernetes стал операционной системой облака. Однако, как было отмечено в материалах про Rainbond, «ванильный» Kubernetes сложен для разработчиков. Если Rainbond решает эту проблему, предлагая готовый PaaS «из коробки» с упором на UI, то KubeVela подходит к задаче с другой стороны: это двигатель для построения собственной платформы (Platform Engine), основанный на модели OAM (Open Application Model).

KubeVela позволяет создавать простые и ориентированные на приложение (Application-centric) абстракции, сохраняя при этом полную гибкость и управляемость через код (Infrastructure as Code).

Основная философия: OAM и разделение ответственности

В основе KubeVela лежит стандарт OAM (Open Application Model). Эта модель разделяет ответственность между двумя ролями:

  1. Разработчиĸи (Developers): Описывают что нужно запустить (образ контейнера, порт, параметры запуска).
  2. Платформенные инженеры (Platform Engineers): Описывают ĸаĸ это должно работать (инфраструктура, политики масштабирования, Ingress, безопасность).

Математически модель приложения в KubeVela можно выразить формулой:

$$ Application = Components + Traits + Workflow $$

Где:

  • Components: Основная рабочая нагрузка (Workload). Например, Docker-образ, Helm-чарт или даже Terraform-модуль.
  • Traits (Свойства/Черты): Операционные характеристики, подключаемые к компоненту. Например: `ingress`, `scaler`, `sidecar`.
  • Workflow: Цепочка шагов доставки (Deploy -> Test -> Promote).

Пример манифеста KubeVela

Вместо десятков Kubernetes-ресурсов (Deployment, Service, Ingress, HPA), разработчик пишет один упрощенный файл:

apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
  name: website
spec:
  components:
    - name: frontend
      type: webservice
      properties:
        image: nginx
      traits:
        - type: scaler
          properties:
            replicas: 3
        - type: gateway
          properties:
            domain: test.example.com

Сравнение: KubeVela vs Rainbond

Основываясь на прошлой статье про Rainbond, сделаем детальное сравнение. Оба инструмента решают проблему сложности Kubernetes, но нацелены на разные аудитории.

Хараĸтеристиĸа Rainbond KubeVela
Философия No-Code / Low-Code PaaS. Готовая платформа с полным UI. Ориентация на визуальное управление. Platform Engine / IaC. Инструментарий для создания платформы. Ориентация на GitOps и конфигурацию как код.
Входной порог Очень низкий. Не нужно знать Kubernetes. Можно собрать приложение из `.jar` или исходного кода одной кнопкой. Средний. Требует понимания концепций OAM. Инженерам платформы нужно знать CUE (язык конфигурации).
Гибĸость Ограничена возможностями UI платформы. Сложно кастомизировать внутреннюю логику деплоя нестандартных вещей. Высочайшая. Любая абстракция настраивается через X-Definitions (на языке CUE). Можно описать любой ресурс K8s или Terraform.
Интеграция IaC Базируется на внутренних механизмах. Нативная интеграция с Terraform. KubeVela может разворачивать облачные базы данных (AWS RDS, Cloud SQL) как часть приложения.
Multi-cluster Есть управление несколькими кластерами, но фокус на единой панели управления. Сильная сторона. Мощный движок развертывания приложений сразу в несколько кластеров с политиками (Placement Policies).
Для ĸого SMB, стартапы, команды без сильной экспертизы в K8s, желающие получить опыт Heroku на своих серверах. Enterprise, Platform Engineering команды, желающие построить свой внутренний PaaS (IDP) по стандартам Spotify/Netflix.

Сравнение с другими аналогами

  1. Crossplane:
    • Crossplane фокусируется на «Инфраструктуре» (создание баз данных, кластеров, сетей в облаках через K8s API).
    • KubeVela фокусируется на «Приложении».
    • Итог: Они часто используются вместе. KubeVela использует Crossplane для заказа ресурсов.
  1. ArgoCD / Flux (GitOps):
    • Это инструменты непрерывной доставки (CD), которые синхронизируют Git и K8s.
    • KubeVela может использовать их под капотом или использовать свой собственный Workflow-контроллер для сложных сценариев (например, «засуспендить деплой, пока не пройдет тест, затем отправить уведомление в Slack»).
  1. Backstage:
    • Backstage — это «Портал» (Frontend). KubeVela — это «Движок» (Backend).
    • Существует плагин `vela-backstage`, который позволяет визуализировать приложения KubeVela внутри интерфейса Backstage. Это идеальная связка для построения IDP.

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

1. Программируемая абстраĸция (CUE Language)

В отличие от Helm, где шаблонизация — это просто подстановка строк, KubeVela использует язык CUE (Configure Unify Execute). Это позволяет платформенным инженерам создавать «умные» шаблоны.

Пример логики на CUE внутри KubeVela: «Если пользователь не указал CPU, автоматически поставить `requests: 100m`, но если это ‘prod’ окружение, то поставить `500m`».

2. Единый Workflow для всего

KubeVela позволяет оркестрировать не только Kubernetes-ресурсы. В одном пайплайне вы можете:

  1. Создать S3 бакет в AWS (через Terraform/Crossplane).
  2. Дождаться готовности.
  3. Задеплоить Deployment в Kubernetes.
  4. Отправить уведомление в Telegram.

3. Отсуствие «Config Drift»

KubeVela активно борется с дрейфом конфигураций, постоянно сверяя желаемое состояние приложения с реальным (State Reconciliation).

Итог и реĸомендации

Выбор между Rainbond и KubeVela зависит от того, ĸто будет обслуживать платформу и ĸаĸие цели стоят перед бизнесом.

Выбирайте Rainbond, если:

  • У вас небольшая или средняя команда разработчиков.
  • Нет выделенного отдела Platform Engineering / DevOps.
  • Нужно «вчера» перенести легаси (Java/PHP/Monolith) в контейнеры без переписывания кода.
  • Вам нужен визуальный интерфейс для управления связями сервисов и мониторинга без написания YAML.
  • Цель: Быстрый Time-to-market с минимальными затратами на инженерию.

Выбирайте KubeVela, если:

  • Вы строите серьезный Internal Developer Platform (IDP) в крупной компании.
  • У вас есть инженеры, знающие Kubernetes, но вы хотите скрыть его сложность от продуктовых разработчиков.
  • Вам нужен строгий GitOps подход (все через репозиторий).
  • Требуется гибридное развертывание: часть в K8s, часть в Serverless, часть в облачных RDS.
  • Вы планируете использовать Backstage в качестве фронтенда.
  • Цель: Стандартизация, масштабируемость, полный контроль над абстракциями (Platform as Product).

Рекомендация по стеĸу для Enterprise:
Для максимальной эффективности современный стек платформенной инженерии часто выглядит так:
$$ \text{Backstage (UI)} + \text{KubeVela (Engine)} + \text{Crossplane (Infra)} $$
Эта связка дает удобство портала (как в Rainbond), мощь оркестрации (KubeVela) и управление облаком (Crossplane).

Сравнительный анализ self-hosted S3-совместимых хранилищ

Четкое сравнение семи self-hosted S3-совместимых решений для хранения данных.

Оригинал тут: Команда RepoFlow. 9 августа 2025 г.

Локальное (self-hosted) объектное хранилище — это отличный выбор для разработчиков и команд, которые хотят иметь полный контроль над хранением и доступом к своим данным. Независимо от того, заменяете ли вы Amazon S3, размещаете внутренние файлы, создаете CI-конвейер или обслуживаете репозитории пакетов, уровень хранения может значительно повлиять на скорость и стабильность.

Мы протестировали семь популярных решений для объектного хранения, поддерживающих протокол S3. Цель состояла в том, чтобы сравнить их производительность в идентичных условиях, используя реальные операции загрузки и скачивания.

Тестируемые решения

Каждое из следующих решений было развернуто с помощью Docker на одном и том же сервере без монтирования томов и без специальной настройки:

  1. `MinIO`
  2. `Ceph`
  3. `SeaweedFS`
  4. `Garage`
  5. `Zenko` (Scality Cloudserver)
  6. `LocalStack`
  7. `RustFS`

Скорость последовательного скачивания

Средняя скорость скачивания одного файла разного размера.

[Изображение: График скорости последовательного скачивания для малых файлов размером 50 КБ и 200 КБ. По оси Y — скорость в МБ/с, по оси X — размер файла. Сравниваются Garage, Localstack, Minio, Zenko, Ceph, RustFS, SeaweedFS.]

[Изображение: График скорости последовательного скачивания для больших файлов размером 10 МБ, 50 МБ, 100 МБ и 1 ГБ. По оси Y — скорость в МБ/с, по оси X — размер файла. Сравниваются те же решения.]

Скорость последовательной загрузки

Средняя скорость загрузки одного файла разного размера.

[Изображение: График скорости последовательной загрузки для малых файлов размером 50 КБ и 200 КБ. По оси Y — скорость в МБ/с, по оси X — размер файла. Сравниваются те же решения.]

[Изображение: График скорости последовательной загрузки для больших файлов размером 10 МБ, 50 МБ, 100 МБ и 1 ГБ. По оси Y — скорость в МБ/с, по оси X — размер файла. Сравниваются те же решения.]

Производительность листинга

Измеряет время, необходимое для получения списка всех 2000 тестовых объектов в бакете с использованием разных размеров страницы (100, 500 и 1000 результатов на запрос).

[Изображение: График производительности листинга. По оси Y — время в мс, по оси X — количество результатов на страницу (100, 500, 1000). Сравниваются те же решения.]

Скорость параллельной загрузки

Измеряет время, необходимое для параллельной загрузки нескольких файлов одинакового размера. Скорость загрузки рассчитывается по формуле:

(number of files × file size) ÷ total time

Скорость параллельной загрузки – файлы 1 МБ

[Изображение: График скорости параллельной загрузки файлов размером 1 МБ. По оси Y — скорость в МБ/с, по оси X — количество параллельных потоков (5, 10, 20). Сравниваются те же решения.]

Скорость параллельной загрузки – файлы 10 МБ

[Изображение: График скорости параллельной загрузки файлов размером 10 МБ. По оси Y — скорость в МБ/с, по оси X — количество параллельных потоков (5, 10, 20). Сравниваются те же решения.]

Скорость параллельной загрузки – файлы 100 МБ

[Изображение: График скорости параллельной загрузки файлов размером 100 МБ. По оси Y — скорость в МБ/с, по оси X — количество параллельных потоков (5, 10, 20). Сравниваются те же решения.]

Скорость параллельного скачивания

Измеряет время, необходимое для параллельного скачивания нескольких файлов одинакового размера. Скорость скачивания рассчитывается по формуле:

(number of files × file size) ÷ total time

Скорость параллельного скачивания – файлы 1 МБ

[Изображение: График скорости параллельного скачивания файлов размером 1 МБ. По оси Y — скорость в МБ/с, по оси X — количество параллельных потоков (5, 10, 20). Сравниваются те же решения.]

Скорость параллельного скачивания – файлы 10 МБ

[Изображение: График скорости параллельного скачивания файлов размером 10 МБ. По оси Y — скорость в МБ/с, по оси X — количество параллельных потоков (5, 10, 20). Сравниваются те же решения.]

Скорость параллельного скачивания – файлы 100 МБ

[Изображение: График скорости параллельного скачивания файлов размером 100 МБ. По оси Y — скорость в МБ/с, по оси X — количество параллельных потоков (5, 10, 20). Сравниваются те же решения.]

Как проводились тесты

Для каждого решения мы:

  1. Загружали и скачивали файлы 7 различных размеров: 50 КБ, 200 КБ, 1 МБ, 10 МБ, 50 МБ, 100 МБ и 1 ГБ.
  2. Повторяли каждую загрузку и скачивание 20 раз для получения стабильных средних значений.
  3. Измеряли среднюю скорость загрузки и скачивания в мегабайтах в секунду (МБ/с).
  4. Выполняли все тесты на одной и той же машине, используя стандартный Docker-контейнер для каждой системы хранения, без внешних томов, монтирования или кешей.

Все решения тестировались в одноузловой конфигурации для обеспечения согласованности. Хотя некоторые системы (например, `Ceph`) спроектированы для лучшей производительности в кластерной среде, мы использовали одинаковые условия для всех решений, чтобы гарантировать справедливое сравнение.

Заключительные мысли

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

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

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

Сводная таблица exchange-compression: LZ4 vs NONE vs ZSTD в Trino

Сводная таблица: LZ4 vs NONE vs ZSTD (простые запросы + дополнение для сложных запросов)

Простые запросы (шарфл ~42 MB)
Метрика NONE 🚀 LZ4 ZSTD 📦
Wall Time 0.95 s 1.68 s 1.47 s
Network 42.0 MB (1.0x) 24.8 MB (1.7x) 12.8 MB (3.3x)
Total CPU 7.52 s 7.56 s 7.49 s
Processed Input 1.86 GB 1.86 GB 1.86 GB
Сложные запросы (шарфл ~11.7 GB, 3 JOIN + DISTINCT, ~732M строк, 5.9 GB input)
Метрика NONE LZ4 ZSTD 📦
Wall Time 13.49 s 13.93 s 12.27 s 🚀
Network 11.69 GB (1.0x) 6.87 GB (~1.7x) 3.54 GB (~3.3x)
Total CPU 214 s ~220 s 214 s
Processed Input 13.19 GB 13.19 GB 13.19 GB

Коэф. сжатия рассчитан относительно NONE по `internalNetworkInputDataSize` (шарфл-трафик):

  • NONE: 11.686 GB
  • LZ4: ~6.87 GB (коэф. 1.7x, как в простых тестах; точные данные из логов подтверждают пропорцию)
  • ZSTD: ~3.54 GB (коэф. 3.3x)

Анализ результатов (простые + сложные запросы)

ZSTD — король сжатия (подтверждено на больших объемах)
  • Простые запросы (малый шарфл 42 MB): ZSTD сжал до 12.8 MB (3.3x лучше NONE).
  • Сложные запросы (большой шарфл 11.7 GB): ZSTD сжал до ~3.54 GB (экономия ~8.15 GB на узел). Если шарфл 400 GB, ZSTD сэкономит ~300 GB трафика по сети — критично для кластера.
Производительность (Speed vs Overhead)
  • NONE: Быстрее на малых объемах (0.95s), но на сложных — 13.49s (сетевой bottleneck).
  • ZSTD: На простых 1.47s (лучше LZ4), на сложных 12.27s (🚀 быстрее всех). Сильное сжатие сокращает сетевой IO, компенсируя CPU overhead.
  • LZ4: На простых худший (1.68s, возможно шум), на сложных 13.93s (хуже ZSTD). Быстрое сжатие, но слабое (1.7x).
CPU (Процессор)
  • Все варианты: ~7.5s (простые), ~214s (сложные). Сжатие (LZ4/ZSTD) не увеличивает CPU на фоне чтения Parquet/ORC + JOIN (732M строк).
Ключевые insights из сложных тестов
  • Сетевой трафик: ZSTD выигрывает на 70% (3.3x), LZ4 на 41% (1.7x). На больших шарфлах (JOINы генерируют GB) сеть — bottleneck для NONE/LZ4.
  • Время выполнения: ZSTD быстрее (12.27s vs 13.49s NONE, 13.93s LZ4). Компенсация сжатием > overhead.
  • Dynamic Filters: Работают одинаково (df_1013/1014), сжатие не влияет.
  • Memory: Peak ~25 GB (user), сжатие снижает пики на exchange.

Итог

  • ZSTD доминирует: Лучшее сжатие (3.3x), минимальный Wall Time на больших данных, нулевой CPU-штраф. На простых — баланс скорости/сжатия, на сложных — разгружает сеть.
  • LZ4: Средний вариант (быстрее сжатие, слабее компрессия). Хуже ZSTD по всем метрикам.
  • NONE: Только для микрокластерами/очень малых шарфлов (<10 MB).

Рекомендации

Внедрить `exchange-compression-codec=ZSTD` для всего кластера, особенно для многоузлового:

или

Управлять сессионно

SET SESSION exchange_compression_codec = ‘NONE’;
SET SESSION exchange_compression_codec = ‘LZ4’;
SET SESSION exchange_compression_codec = ‘ZSTD’;

exchange-compression-compression-level=3  # Баланс скорость/сжатие (по умолчанию и поменять в Trino нельзя пока)
  • Почему ZSTD: 3x+ экономия bandwidth на JOIN-ах (ваш workload). CPU современный — справляется.
  • Тестировать: На production-трафике (GB шарфл) — speedup 10-20%.
  • Доп. тюнинг: `exchange.compression-enabled=true` (уже по умолчанию). Если CPU bottleneck — LZ4, но ZSTD лучше.
  • Мониторинг: Смотреть `internalNetworkInputDataSize` в Trino UI — цель <30% от uncompressed.

ZSTD — золотой стандарт для вашего кластера! 🚀📦

Создание масштабируемого сервиса для скриншотов сайтов на Node.js, Puppeteer и Kubernetes

В современном вебе часто возникает задача автоматического создания скриншотов веб-страниц. Это может быть нужно для генерации превью ссылок, мониторинга доступности сайтов, создания PDF-отчетов или даже для работы сервисов по автоматизации контента.

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

  • Node.js & Express: для создания легковесного API.
  • Puppeteer: для управления headless-браузером Chromium и создания скриншотов.
  • Docker: для упаковки нашего приложения в изолированный контейнер.
  • Kubernetes (k3s): для оркестрации, масштабирования и обеспечения отказоустойчивости нашего сервиса.

В итоге мы получим простое API, которое по GET-запросу с URL-адресом будет возвращать готовую картинку.

Зачем нужен собственный сервис?

Хотя существуют готовые SaaS-решения вроде https://urlbox.com, создание собственного сервиса дает несколько ключевых преимуществ:

  1. Контроль: Вы полностью контролируете окружение, версии браузера и параметры рендеринга.
  2. Безопасность: Вы можете запускать сервис в своей приватной сети для обработки внутренних ресурсов, недоступных извне.
  3. Стоимость: При большом объеме запросов собственный сервис может оказаться значительно дешевле SaaS.
  4. Гибкость: Вы можете легко расширить функциональность, добавив, например, генерацию PDF, выполнение кастомных скриптов на странице и многое другое.

Шаг 1: Создание Node.js приложения

Сначала создадим основу нашего сервиса — Express-приложение, которое будет принимать запросы и управлять Puppeteer.

Структура проекта

Создадим папку для нашего проекта и внутри нее — необходимые файлы.

puppeteer-k8s/
├── dockerb/
│   ├── Dockerfile
│   ├── .dockerignore
│   ├── server.js
│   ├── package.json
│   └── package-lock.json
└── deployment.yaml

*Обратите внимание: мы поместили все, что относится к Docker, в подпапку `dockerb` для удобства.*

Код сервера (`server.js`)

Это ядро нашего приложения. Оно принимает HTTP-запросы, запускает Puppeteer, переходит на указанный URL и делает скриншот. Мы также добавим полезные параметры для управления качеством и размером.

// server.js. -- в моем докере server_v3.js

const express = require('express');
const puppeteer = require('puppeteer');

const app = express();
const PORT = 3000;

app.get('/render', async (req, res) => {
    // Добавляем новые параметры: quality и dsf (deviceScaleFactor)
    const { 
        url, 
        width, 
        height, 
        format = 'png', 
        fullPage = 'false',
        quality, // Качество для jpeg/webp (0-100)
        dsf = '1' // Device Scale Factor. Для Retina-качества используйте '2'
    } = req.query;

    if (!url) {
        return res.status(400).json({
            error: 'Параметр "url" обязателен.',
            example: '/render?url=https://example.com'
        });
    }

    let browser;
    try {
        console.log(`[${new Date().toISOString()}] Начинаем рендеринг для: ${url}`);
        
        // Добавляем аргументы для улучшения рендеринга
        browser = await puppeteer.launch({
            args: [
                '--no-sandbox',
                '--disable-setuid-sandbox',
                '--font-render-hinting=none', // Может улучшить отрисовку шрифтов
                '--disable-infobars'       // Убирает инфо-панели
            ]
        });
        
        const page = await browser.newPage();

        const viewportWidth = parseInt(width, 10) || 1280;
        const viewportHeight = parseInt(height, 10) || 720;
        const deviceScaleFactor = parseInt(dsf, 10) || 1;

        // Устанавливаем viewport с учетом deviceScaleFactor
        await page.setViewport({
            width: viewportWidth,
            height: viewportHeight,
            deviceScaleFactor: deviceScaleFactor
        });

        console.log(`Viewport: ${viewportWidth}x${viewportHeight}, DeviceScaleFactor: ${deviceScaleFactor}`);

        await page.goto(url, { waitUntil: 'networkidle2' });

        // Если есть "ленивая" загрузка изображений, можно "проскроллить" страницу
        // Это необязательный шаг, но он помогает прогрузить все картинки
        if (fullPage === 'true') {
             await page.evaluate(async () => {
                await new Promise((resolve) => {
                    let totalHeight = 0;
                    const distance = 100;
                    const timer = setInterval(() => {
                        const scrollHeight = document.body.scrollHeight;
                        window.scrollBy(0, distance);
                        totalHeight += distance;

                        if (totalHeight >= scrollHeight) {
                            clearInterval(timer);
                            resolve();
                        }
                    }, 100);
                });
            });
        }
        
        const screenshotOptions = {
            type: (format === 'jpeg' || format === 'webp') ? format : 'png',
            fullPage: fullPage === 'true'
        };

        // Устанавливаем качество, если параметр был передан
        if ((screenshotOptions.type === 'jpeg' || screenshotOptions.type === 'webp') && quality) {
            screenshotOptions.quality = parseInt(quality, 10);
        } else if (screenshotOptions.type === 'jpeg') {
            screenshotOptions.quality = 90; // Ставим хорошее качество по умолчанию для JPEG
        }

        const imageBuffer = await page.screenshot(screenshotOptions);
        
        console.log(`[${new Date().toISOString()}] Рендеринг успешно завершен.`);

        res.setHeader('Content-Type', `image/${screenshotOptions.type}`);
        res.send(imageBuffer);

    } catch (error) {
        console.error(`[${new Date().toISOString()}] Ошибка рендеринга для ${url}:`, error.message);
        res.status(500).json({ 
            error: 'Не удалось отрендерить страницу.',
            details: error.message 
        });
    } finally {
        if (browser) {
            await browser.close();
        }
    }
});


app.get('/', (req, res) => {
    res.setHeader('Content-Type', 'text/plain; charset=utf-8');
    res.send(`
    API для рендеринга сайтов (v2 - Улучшенное качество)
    ----------------------------------------------------
    Используйте GET-запрос на /render с параметрами.

    Обязательные параметры:
      - url: Адрес сайта для скриншота.

    Необязательные параметры:
      - width: Ширина окна (по умолч. 1280).
      - height: Высота окна (по умолч. 720).
      - format: Формат файла ('png', 'jpeg', 'webp'). По умолч. 'png'.
      - fullPage: Сделать скриншот всей страницы ('true' или 'false'). По умолч. 'false'.
      - dsf: Device Scale Factor для Retina/HiDPI качества (например, '2'). По умолч. '1'.
      - quality: Качество для jpeg/webp от 0 до 100.

    Пример для высокого качества (Retina):
    curl -o site_retina.png "http://localhost:3000/render?url=https://github.com&dsf=2&width=1440&height=900"
    
    Пример для JPEG с максимальным качеством:
    curl -o site_hq.jpeg "http://localhost:3000/render?url=https://apple.com&format=jpeg&quality=100&width=1920&height=1080"
    `);
});

app.listen(PORT, () => {
    console.log(`Сервис рендеринга запущен на http://localhost:${PORT}`);
});

*Запустите `npm install` в папке `dockerb`, чтобы сгенерировать `package-lock.json`.*

Шаг 2: Создание Docker-образа

Теперь упакуем наше приложение. Этот шаг — самый каверзный, так как Puppeteer требует особого подхода к правам доступа и зависимостям.

мой пример тут образа

Файл `.dockerignore`

Крайне важно не копировать локальную папку `node_modules` в образ. Они должны устанавливаться внутри контейнера для правильной архитектуры.

# .dockerignore
node_modules

Финальный `Dockerfile`

Этот `Dockerfile` — результат множества проб и ошибок. Он решает все основные проблемы:

  • Устанавливает необходимые системные библиотеки для Chromium.
  • Создает непривилегированного пользователя `pptruser` с домашней директорией.
  • Устанавливает `npm`-зависимости и браузер от имени этого пользователя, чтобы избежать проблем с правами доступа.
# 1. Базовый образ
FROM node:18-slim

# 2. Установка системных зависимостей
RUN apt-get update && apt-get install -y \
    ca-certificates fonts-liberation libappindicator3-1 libasound2 libatk-bridge2.0-0 \
    libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgbm1 \
    libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libnss3 \
    libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 \
    libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 \
    libxrender1 libxss1 libxtst6 lsb-release wget xdg-utils \
    && rm -rf /var/lib/apt/lists/*

# 3. создаем пользователя с домом
# Флаг -m (--create-home) гарантирует создание папки /home/pptruser
RUN useradd -r -m -g root -s /bin/bash pptruser

# 4. Устанавливаем рабочую директорию
WORKDIR /app

# 5. Копируем файлы зависимостей и сразу назначаем владельцем pptruser
# (современный и более чистый способ, чем chown после)
COPY --chown=pptruser:root package*.json ./

# 6. Переключаемся на нашего пользователя
USER pptruser

# 7. Устанавливаем всё от имени pptruser. Кэш ляжет в /home/pptruser/.cache
RUN npm ci
RUN npx puppeteer browsers install chrome

# 8. Копируем остальной код, также сразу назначая владельца
COPY --chown=pptruser:root . .

# 9. Открываем порт и запускаем
EXPOSE 3000
CMD [ "node", "server.js" ]

Сборка и отправка образа

Замените `your_docker_id` на ваш логин в Docker Hub.

# Переходим в папку с Dockerfile
cd puppeteer-k8s/dockerb

# Собираем образ
docker build -t your_docker_id/puppeteer-renderer:v1 .

# Отправляем в репозиторий
docker push your_docker_id/puppeteer-renderer:v1

Шаг 3: Развертывание в Kubernetes

Мы будем использовать `k3s` — легковесный дистрибутив Kubernetes. Можно еще тут посмотреть пример https://github.com/jamesheronwalker/urlbox-puppeteer-kubernetes-demo

или вот статейка еще https://urlbox.com/guides/kubernetes-website-screenshots

Установка окружения (Local)

# Установка lima и k3s (если еще не сделано)
brew install lima
limactl start template://k3s

# Настройка kubectl для работы с кластером
export KUBECONFIG=$(limactl list k3s --format 'unix://{{.Dir}}/copied-from-guest/kubeconfig.yaml')

# Проверка, что все работает
kubectl get nodes

Манифест развертывания (`deployment.yaml`)

Этот YAML-файл описывает желаемое состояние нашего приложения в кластере. Мы будем использовать тип сервиса `LoadBalancer` — он идеально подходит для будущего развертывания в облаке, а для локальной разработки мы будем использовать `port-forward`.

# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: puppeteer-renderer
spec:
  replicas: 2 # Запускаем два пода для отказоустойчивости
  selector:
    matchLabels:
      app: puppeteer-renderer
  template:
    metadata:
      labels:
        app: puppeteer-renderer
    spec:
      containers:
      - name: renderer
        image: your_docker_id/puppeteer-renderer:v1 # <<< ВАШ ОБРАЗ (мой тут docker pull 1325gy/my_dev:v4)
        ports:
        - containerPort: 3000
        resources:
          requests:
            cpu: "500m"
            memory: "1Gi"
          limits:
            cpu: "1"
            memory: "2Gi"
        readinessProbe:
          httpGet:
            path: /
            port: 3000
          initialDelaySeconds: 15
          periodSeconds: 10
        livenessProbe:
          httpGet:
            path: /
            port: 3000
          initialDelaySeconds: 30
          periodSeconds: 20
        volumeMounts:
        - name: dshm
          mountPath: /dev/shm
      volumes:
      - name: dshm
        emptyDir:
          medium: Memory
---
apiVersion: v1
kind: Service
metadata:
  name: pptr-renderer-service
spec:
  # Тип LoadBalancer - стандарт для облаков. Локально он останется в <pending>,
  # но это не помешает нам использовать port-forward.
  type: LoadBalancer 
  selector:
    app: puppeteer-renderer
  ports:
  - protocol: TCP
    port: 80 # Внешний порт сервиса
    targetPort: 3000 # Порт, на который нужно перенаправлять трафик внутри пода

Важные моменты в манифесте:

  • `resources:`: Puppeteer очень требователен к ресурсам. Указание запросов и лимитов помогает Kubernetes правильно размещать поды.
  • `readiness/livenessProbe`: Пробы готовности и жизнеспособности позволяют Kubernetes понять, работает ли под корректно.
  • `/dev/shm`: Chromium использует разделяемую память. Увеличение её размера через `emptyDir` предотвращает частые сбои.

Запуск и проверка

# Переходим в корневую папку проекта
cd ..

# Применяем манифест
kubectl apply -f deployment.yaml

# Наблюдаем за созданием подов
kubectl get pods -l app=puppeteer-renderer -w

# Проверяем сервис. EXTERNAL-IP будет <pending>, это нормально.
kubectl get service pptr-renderer-service
# NAME                  TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)        AGE
# pptr-renderer-service LoadBalancer   10.43.123.123   <pending>     80:31185/TCP   1m

Шаг 4: Тестирование через Port-Forward

`kubectl port-forward` — это мощный инструмент для отладки, который создает безопасный тоннель с вашего компьютера напрямую к сервису в кластере.

  1. Откройте новый терминал и выполните команду:
kubectl port-forward service/pptr-renderer-service 8080:80
  • `8080` — это порт на вашем локальном компьютере (`localhost`).
  • `80` — это порт, который слушает наш `Service` в Kubernetes.

Вы увидите сообщение `Forwarding from 127.0.0.1:8080 -> 3000`. Не закрывайте этот терминал.

  1. Откройте третий терминал и отправьте тестовый запрос на `localhost:8080`:
curl -o k8s-site.png "http://localhost:8080/render?url=https://kubernetes.io&width=1440&height=900&dsf=2"

Если все сделано правильно, в вашей текущей папке появится файл `k8s-site.png` со скриншотом сайта Kubernetes в высоком разрешении!

Итоги и рекомендации для продакшена

Мы успешно создали и развернули масштабируемый сервис для создания скриншотов. Мы убедились, что он работает локально в `k3s`, используя `LoadBalancer` и `port-forward` для удобной отладки.

Когда придет время переходить в продуктивное окружение (например, в облако Google/AWS):

  1. Тип Сервиса: Вам не нужно ничего менять! Просто примените тот же `deployment.yaml` с `type: LoadBalancer`. Облачный провайдер автоматически подхватит этот сервис и выделит ему настоящий публичный IP-адрес.
  2. Ingress: Для более гибкого управления трафиком (маршрутизация по хостам, SSL/TLS) используйте `Ingress Controller`. Он будет направлять внешний трафик на ваш сервис, который уже можно будет сделать типа `ClusterIP`.
  3. Автомасштабирование: Настройте `HorizontalPodAutoscaler` (HPA), чтобы Kubernetes автоматически добавлял или удалял поды в зависимости от нагрузки (например, по CPU).
  4. Логирование и Мониторинг: Настройте централизованный сбор логов (EFK/Loki) и мониторинг метрик (Prometheus/Grafana), чтобы следить за здоровьем и производительностью сервиса.

Этот пример — отличная основа, которую можно развивать и адаптировать под самые разные задачи, от простых утилит до сложных систем автоматизации контента.

Мне вот удалось rbc заскринить вот так, потом может что то сделаю для статеек с медиума.

curl -o rbc111.png "http://localhost:8080/render?url=https://rbc.ru&width=1440&height=900&dsf=2"

Вот что вышло png тут

Просто duckdb 🦆 ну красота же 😍

echo "cnt\n1\n2\n3" | duckdb -c "SELECT count(distinct cnt) FROM read_csv('/dev/stdin')"
┌─────────────────────┐
│ count(DISTINCT cnt) │
│        int64        │
├─────────────────────┤
│          3          │
└─────────────────────┘

echo "cnt\n1\n2\n3" | duckdb -c "SELECT sum(cnt) FROM read_csv('/dev/stdin')" 
┌──────────┐
│ sum(cnt) │
│  int128  │
├──────────┤
│    6     │
└──────────┘

А тут еще много всякой дополнительно утиной косметики https://query.farm/duckdb_extensions.html

Обработка логов Trino из Kafka с помощью Vector для удаления полей

В современных архитектурах данных, построенных на Kafka, часто возникает задача обработки или фильтрации потока событий “на лету”. Один из распространенных кейсов — удаление чувствительной информации из логов перед их передачей в следующую систему (например, в SIEM или систему долгосрочного хранения).

Kafka: https://hub.docker.com/r/apache/kafka
Vector: https://vector.dev/docs

Рассмотрим реальный пример:

  • Кластер Trino (или Presto) пишет подробные логи о каждом выполненном запросе в топик Kafka.
  • Эти логи содержат как полезные метаданные (пользователь, время, объем данных), так и полную текстовую версию самого SQL-запроса в поле, например, `query`.
  • Задача: Переложить эти логи в другой топик Kafka, но уже без** поля `query`, чтобы система-подписчик не имела доступа к потенциально конфиденциальной информации в текстах запросов.

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

План действий

  1. Создадим два топика в Kafka: `trino-logs-raw` (для сырых логов) и `trino-logs-cleaned` (для очищенных).
  2. Настроим Vector для чтения из первого топика, удаления поля `query` и всех служебных метаданных.
  3. Настроим Vector на запись результата во второй топик.
  4. Запустим всю цепочку в Docker и протестируем.

Шаг 1: Подготовка Kafka

Предполагается, что у вас уже запущен Kafka-брокер в Docker. На основе нашего примера, у вас есть контейнер с именем `broker1`, который является частью Docker-сети `minimal_iceberg_net`.

Откройте терминал и подключитесь к контейнеру Kafka, чтобы создать топики:

Создадим сеть 

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

Теперь, находясь внутри контейнера, выполните команды:

# Создаем "сырой" топик для входящих логов Trino
./kafka-topics.sh --create --topic trino-logs-raw --bootstrap-server localhost:29092 --partitions 1 --replication-factor 1

# Создаем "чистый" топик для обработанных логов
./kafka-topics.sh --create --topic trino-logs-cleaned --bootstrap-server localhost:29092 --partitions 1 --replication-factor 1

*Обратите внимание: я использую внутренний порт брокера `29092`, который узнали ранее.*

Выйдите из контейнера командой `exit`.

Шаг 2: Конфигурация Vector

На вашей локальной машине создайте структуру папок:

vector-trino-processor/
└── config/
    └── vector.toml

Поместите в файл `vector.toml` следующую конфигурацию. Это сердце нашего решения.

# vector-trino-processor/config/vector.toml

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

# ==================================
#             ТРАНСФОРМАЦИЯ
# ==================================
# Удаляем поле `query` и служебные метаданные Vector
[transforms.clean_trino_log]
  type = "remap"
  # Получаем данные от нашего источника
  inputs = ["trino_raw_logs"]
  # Скрипт на языке Vector Remap Language (VRL)
  source = '''
  # 1. Удаляем чувствительное поле "query" из лога.
  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 = "kafka"
  # Принимаем на вход данные, прошедшие трансформацию
  inputs = ["clean_trino_log"]
  bootstrap_servers = "broker3:29092"
  # Указываем топик для записи
  topic = "trino-logs-cleaned"
  # Кодируем итоговое событие обратно в JSON
  encoding.codec = "json"

Шаг 3: Запуск и Тестирование

Нам понадобится три терминала.

В Терминале №1 — Запустим Vector

Перейдите в папку `vector-trino-processor` и выполните команду:

docker run \
  -d \
  --name vector-processor \
  -v "$(pwd)/config:/etc/vector/" \
  --network=my_net \
  --rm \
  timberio/vector:latest-alpine --config /etc/vector/vector.toml

Эта команда:

  • Запускает контейнер Vector в фоновом режиме (`-d`).
  • Дает ему имя `vector-processor`.
  • Монтирует ваш локальный конфиг (`-v`).
  • Подключает его к той же сети, что и Kafka (`--network`).
  • Явно указывает, какой файл конфигурации использовать (`--config`).

В Терминале №2 — Симулируем отправку лога Trino

Запустим интерактивный Kafka-продюсер.

docker exec --workdir /opt/kafka/bin -it broker3 ./kafka-console-producer.sh --topic trino-logs-raw --bootstrap-server localhost:29092

Теперь вставьте в этот терминал JSON, имитирующий лог от Trino, и нажмите Enter:

{"user":"yuriy","source":"trino-cli","queryId":"20231120_123456_00001_abcde","query":"SELECT * FROM sensitive_table a JOIN other_table b ON a.id = b.id WHERE a.credit_card = '1234-5678-9012-3456'","state":"FINISHED"}

В Терминале №3 — Проверяем результат

Запустим Kafka-консьюмер, который будет слушать очищенный топик `trino-logs-cleaned`.

docker exec --workdir /opt/kafka/bin -it broker3 ./kafka-console-consumer.sh --topic trino-logs-cleaned --bootstrap-server localhost:29092 --from-beginning

Вы практически мгновенно увидите результат работы Vector — тот же самый лог, но уже без поля `query`:

{"user":"yuriy","source":"trino-cli","queryId":"20231120_123456_00001_abcde","state":"FINISHED"}

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

Nimtable: Единая панель управления для зоопарка Iceberg-каталогов

В современных компаниях, активно использующих данные, часто возникает проблема “зоопарка” технологий. Данные хранятся в озере данных (Data Lake), а метаданные об этих данных — в каталогах. Со временем таких каталогов становится много: один `Hive Metastore` для унаследованной аналитики, другой — `REST Catalog` для новой платформы на Trino, третий — `JDBC Catalog` для специфичного микросервиса, а где-то в среде разработки таблицы вообще создаются напрямую в S3. Каждая система решает свою задачу, но вместе они создают хаос.

https://github.com/nimtable/nimtable

Платформенным дата-командам становится сложно управлять этим разнообразием, отслеживать состояние таблиц, проводить оптимизацию и обеспечивать единые стандарты. Именно для решения этой проблемы и был создан open-source проект Nimtable. Это не просто очередной каталог для Iceberg, а полноценная платформа для наблюдения и управления (*observability platform*) существующими каталогами из одного окна.

Что такое Nimtable?

Nimtable — это легковесная веб-платформа с открытым исходным кодом, предназначенная для исследования и управления каталогами и таблицами Apache Iceberg. Его ключевая идея — предоставить единый интерфейс для подключения к различным существующим каталогам, агрегируя метаданные и предоставляя инструменты для их анализа и обслуживания.

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

Ключевая функциональность

Nimtable предлагает набор функций, которые делают его мощным инструментом для управления озером данных.

пы: картинки можно листать, если что) там много, почти все меню.

  1. Агрегация каталогов: Это главная особенность проекта. Nimtable позволяет в одном интерфейсе подключить и работать с несколькими типами каталогов Apache Iceberg, включая:
    • `REST Catalog`
    • `AWS Glue`
    • `PostgreSQL` (через JDBC)
    • Каталоги на основе S3 (`S3 Tables`)
  1. Исследование и визуализация: Платформа предоставляет удобный UI для навигации по метаданным:
    • Просмотр каталогов, пространств имен (схем) и таблиц.
    • Анализ схемы таблиц, их партиций, снэпшотов и манифестов.
    • Визуализация распределения файлов и снэпшотов, что помогает быстро находить таблицы, требующие оптимизации (например, с большим количеством мелких файлов).
  1. Управление оптимизацией: Nimtable не просто показывает проблемы, но и помогает их решать. Он интегрируется с внешними вычислительными движками, такими как Apache Spark или RisingWave, позволяя запускать и отслеживать задачи по обслуживанию таблиц (например, `compaction` или `expire_snapshots`) прямо из веб-интерфейса.
  1. Встроенный SQL-редактор: Для быстрой проверки данных или метаданных в Nimtable встроен простой SQL-редактор, позволяющий выполнять запросы к таблицам напрямую из браузера.
  1. Собственный REST API: Помимо агрегации других каталогов, Nimtable сам может выступать в роли стандартного Iceberg REST-каталога. Это позволяет использовать его как единую точку входа для различных движков запросов (Trino, Spark, Flink).

Варианты использования в большой компании

Представим себе компанию, где исторически сложился разнородный ландшафт данных:

  • Прод-кластер Hadoop использует `Hive Metastore` для аналитических витрин.
  • Аналитическая платформа на Trino работает с CedrusData Catalog, который реализует `Iceberg REST API` habr.com.
  • Команда разработки для своих экспериментов использует таблицы, зарегистрированные напрямую в S3, чтобы не “загрязнять” общие каталоги.
  • Какой-то сервис использует собственную `PostgreSQL` базу как JDBC-каталог.

В такой среде Nimtable становится незаменимым инструментом:

  • Единая точка входа: Платформенная команда подключает все четыре каталога к Nimtable. Теперь для мониторинга состояния всех Iceberg-таблиц в компании достаточно зайти на один дашборд, не переключаясь между разными консолями и инструментами.
  • Централизованная оптимизация: Инженер замечает, что в одной из таблиц на прод-кластере накопилось тысячи мелких файлов. Прямо из интерфейса Nimtable он может запустить `compaction-job` на общем Spark-кластере, выбрав нужную таблицу, независимо от того, в каком каталоге она зарегистрирована.
  • Упрощение доступа: Вместо того чтобы объяснять новому аналитику, как настроить 4 разных подключения, ему можно дать доступ к Nimtable, где он сможет исследовать все доступные данные в едином, понятном интерфейсе.
  • Контролируемая миграция: Если команда решит перенести таблицы из `Hive Metastore` в новый `REST Catalog`, Nimtable позволит одновременно наблюдать за источником и приемником, контролируя процесс и сверяя метаданные.

Архитектура и развертывание

Архитектурно Nimtable располагается между конечными пользователями (или движками запросов) и нижележащими каталогами метаданных.

Проект очень прост в развертывании. Самый быстрый способ начать работу — использовать Docker:

# Переходим в директорию с docker-файлами в репозитории проекта
cd docker
# Запускаем сервисы в фоновом режиме
docker compose up -d

После этого веб-интерфейс будет доступен по адресу `http://localhost:3000`.

Сравнение с другими решениями

Чтобы понять нишу, которую занимает Nimtable, сравним его с другими популярными решениями для управления метаданными.

Параметр Nimtable Project Nessie Hive Metastore CedrusData Catalog
Основное назначение Платформа для наблюдения и управления несколькими каталогами. Каталог с Git-подобным версионированием данных. Хранилище метаданных для экосистемы Hadoop. Высокопроизводительный Iceberg REST каталог.
Поддержка нескольких каталогов (агрегация) Да (ключевая функция) Нет (является самостоятельным каталогом) Нет (является самостоятельным каталогом) Нет (является самостоятельным каталогом)
Встроенный UI для управления Да, с фокусом на агрегацию и оптимизацию. Да, с фокусом на ветки, теги и коммиты. Нет (обычно управляется через CLI или сторонние UI). Управляется через API; UI не является основной частью docs.cedrusdata.ru.
Управление оптимизацией (Compaction) Да, через интеграцию с внешними движками. Нет, это задача движков запросов. Нет, это задача движков запросов (Spark/Hive). Нет, это задача движков запросов.
Git-подобные операции Нет Да (ключевая функция) Нет Нет

Как видно из таблицы, Nimtable не конкурирует напрямую с каталогами вроде Nessie или Hive и другими, а дополняет их, выступая в роли “менеджера менеджеров”.

Заключение

Nimtable — это многообещающий проект, который пока не собрал много звёзд, но уже готов решать реальную боль платформенных дата-команд в крупных организациях. Вместо того чтобы создавать еще один стандарт каталога, он предлагает удобный слой абстракции для управления уже существующим “зоопарком”. Возможность в одном месте видеть, анализировать и оптимизировать таблицы из разных систем (`Hive`, `JDBC`, `REST`) делает его уникальным и крайне полезным инструментом для построения зрелой и управляемой платформы данных на базе Apache Iceberg.

Кстати, у меня после запуска он сначала жутко тупил, а потом прочихался, на третий день работы в докере))) я уже даже не надеялся, а он смог. ниче не делал) оно само) Но, видимо, если таблиц очень много, то первый запуск надо как то отдельно планировать. В общем зверь интересный и полезный, а запускать не сложно. Ну почти не сложно и баги есть. вот эту нашел например? https://github.com/nimtable/nimtable/issues/200 но это не критично.

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

Да точно, дело в ресурсах, теперь 16 файлов.

Теперь кстати хочет оптимизации)), хороший тула, можно и сломать табличку им))

Ранее писал о разных каталогах тут: https://gavrilov.info/all/rukovodstvo-po-rest-katalogam-dlya-trino-i-iceberg/

Новые архитектуры современной инфраструктуры данных: a16z

Источник: Emerging Architectures for Modern Data Infrastructure
Авторы: Matt Bornstein, Jennifer Li, and Martin Casado
PDF: Тут


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

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

Обновленные эталонные архитектуры

Статья предлагает два общих взгляда на современный стек данных.

1. Единая инфраструктура данных (Unified Data Infrastructure 2.0)

Эта схема дает комплексное представление о стеке данных, охватывая все основные варианты использования — от аналитики до операционных систем.

Notes: Excludes OLTP, log analysis, and SaaS analytics apps.

Схема демонстрирует путь данных от источников (`Sources`) через этапы загрузки и транспортировки (`Ingestion and Transport`), хранения (`Storage`), обработки запросов (`Query and Processing`), трансформации (`Transformation`) до конечного анализа и вывода (`Analysis and Output`).

2. Инфраструктура для машинного обучения (Machine Learning Infrastructure 2.0)

Вторая схема подробно рассматривает сложную и все более независимую цепочку инструментов для машинного обучения.

Здесь показан жизненный цикл ML-модели: от трансформации данных и разработки модели (`Data Transformation`, `Model Training and Development`) до ее развертывания (`Model Inference`) и интеграции в конечные продукты (`Integration`).

Что изменилось? Стабильное ядро и “Кембрийский взрыв”

Что не изменилось: стабильность в ядре

Несмотря на активное развитие рынка, базовые архитектурные паттерны сохранили свою актуальность. По-прежнему существует разделение между:

  • Аналитическими системами (Analytic Systems), которые помогают принимать решения на основе данных (`data-driven decisions`).
  • Операционными системами (Operational Systems), которые являются основой для продуктов, использующих данные (`data-powered products`).

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

  • В аналитике связка `Fivetran` (для репликации данных), `Snowflake`/`BigQuery` (облачные хранилища данных) и `dbt` (для SQL-трансформаций) стала почти стандартом де-факто.
  • В операционных системах укрепились такие стандарты, как `Databricks`/`Spark`, `Confluent`/`Kafka` и `Airflow`.
Что нового: “Кембрийский взрыв”

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

  1. Новые инструменты для поддержки ключевых процессов обработки данных:
    • Data Discovery: Каталоги данных для поиска и понимания имеющихся активов (`Amundsen`, `DataHub`, `Atlan`).
    • Data Observability: Инструменты для мониторинга состояния и качества конвейеров данных (`Monte Carlo`, `Bigeye`).
    • ML Model Auditing: Решения для аудита и валидации ML-моделей.
  1. Новые приложения для извлечения ценности из данных:
    • Data Workspaces: Интерактивные среды для совместной работы аналитиков и Data Scientist’ов (`Mode`, `Hex`, `Deepnote`).
    • Reverse ETL: Сервисы, которые возвращают обогащенные данные из хранилища обратно в операционные системы (CRM, ERP), такие как `Census` и `Hightouch`.
    • ML Application Frameworks: Фреймворки для создания приложений на основе ML-моделей (`Streamlit`).

Три основных архитектурных шаблона (Blueprints)

Шаблон 1: Современная Business Intelligence (BI)

Этот шаблон предназначен для компаний любого размера, которые строят облачную BI-аналитику.

Darker boxes are new or meaningfully changed since v1 of the architecture in 2020; lighter colored boxes have remained largely the same. Gray boxes are considered less relevant to this blueprint.
  • Что не изменилось: Основой по-прежнему является комбинация репликации данных (`Fivetran`), облачного хранилища (`Snowflake`) и SQL-моделирования (`dbt`). Дашборды (`Looker`, `Tableau`, `Superset`) остаются главным инструментом анализа.
  • Что нового:
    • Metrics Layer: Появился активный интерес к слою метрик — системе, которая предоставляет стандартизированные бизнес-определения поверх хранилища данных (`Transform`, `LookML`). `dbt` также движется в этом направлении. ( dbt кстати открыла в общий доступ свои метрики тут
    • Reverse ETL: Этот инструмент позволяет операционализировать аналитику, отправляя результаты (например, скоринг лидов) из хранилища напрямую в `Salesforce` или `Hubspot`. ( теперь мы знаем как эта штука называется по-модному, когда кто-то просит excele’чку всунуть к табличке рядышком :) )
    • Data Workspaces: Новые приложения для более гибкого и глубокого анализа, чем стандартные дашборды.
Шаблон 2: Мультимодальная обработка данных

Этот шаблон развивает концепцию “озера данных” (`Data Lake`) для поддержки как аналитических, так и операционных задач. Часто используется компаниями, которые “мигрировали” с `Hadoop`.

  • Что не изменилось: Ядром остаются системы обработки (`Databricks`, `Starburst`), транспортировки (`Confluent`, `Airflow`) и хранения (`AWS S3`).
  • Что нового:
    • Архитектура Lakehouse: Получила широкое признание концепция `Lakehouse` — гибрид, объединяющий гибкость озера данных и производительность/управляемость хранилища данных. Она позволяет использовать поверх одного и того же хранилища (`S3`) множество движков: `Spark`, `Presto`, `Druid`/`ClickHouse` и др.
    • Форматы хранения: Быстрое распространение получают открытые табличные форматы, такие как `Delta Lake`, `Apache Iceberg` и `Apache Hudi`, которые привносят транзакционность и надежность в озера данных.
    • Stream Processing: Растет популярность потоковой обработки данных в реальном времени. Появляются новые, более простые в использовании инструменты (`Materialize`, `Upsolver`), а существующие (`Databricks Streaming`, `Confluent`/`ksqlDB`) наращивают функциональность.
Шаблон 3: Искусственный интеллект и машинное обучение (AI/ML)

Стек для разработки, тестирования и эксплуатации ML-моделей.

Note: Darker boxes are new or meaningfully changed since v1 of the architecture in 2020; lighter colored boxes have remained largely the same. Gray boxes are considered less relevant to this blueprint.
  • Что не изменилось: Инструменты для разработки моделей в целом остались прежними: облачные платформы (`AWS Sagemaker`, `Databricks`), ML-фреймворки (`PyTorch`, `XGBoost`) и системы для отслеживания экспериментов (`Weights & Biases`, `Comet`).
  • Что нового:
    • Data-Centric AI: Произошел сдвиг парадигмы в сторону подхода, ориентированного на данные. Вместо бесконечного улучшения кода модели, фокус сместился на улучшение качества и управления данными для обучения. Это привело к росту сервисов разметки данных (`Scale AI`, `Labelbox`).
    • Feature Stores: Увеличилось внедрение хранилищ признаков (`Tecton`, `Feast`) для совместной разработки и использования ML-признаков в production.
    • Pre-trained Models: Использование предобученных моделей (особенно в NLP) стало стандартом. Компании, как `OpenAI` и `Hugging Face`, играют здесь ключевую роль.
    • MLOps: Инструменты для эксплуатации моделей стали более зрелыми, особенно в области мониторинга (`Arize`, `Fiddler`) на предмет деградации качества и дрифта данных.

Гипотеза о “платформе данных”

Ключевая идея статьи — объяснить наблюдаемые изменения через формирование платформ данных.

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

Применительно к данным, “бэкенд” стека (загрузка, хранение, обработка) консолидируется вокруг небольшого числа облачных вендоров. Эти вендоры (`Snowflake`, `Databricks`) активно инвестируют в то, чтобы сделать данные легкодоступными для других через стандартные интерфейсы (например, SQL).

В свою очередь, “фронтенд” разработчики пользуются этим, создавая множество новых приложений поверх единой точки интеграции, не беспокоясь о сложностях базовой инфраструктуры. Это приводит к появлению нового класса `warehouse-native` (или `lakehouse-native`) приложений, которые работают непосредственно с данными клиента в его хранилище.

Эта модель объясняет, почему поставщики ядра данных (`Snowflake`, `Databricks`) так высоко ценятся (они борются за долгосрочную позицию платформы) и почему наблюдается взрывной рост в экосистеме инструментов (`Reverse ETL`, `Metrics Layer`) — они становятся важными компонентами, встроенными в эту новую платформенную архитектуру.

Итог и акценты в трендах

  1. Стабилизация ядра и консолидация. Ключевые компоненты стека (хранилище/озеро, движки обработки) консолидируются вокруг нескольких крупных игроков, которые становятся де-факто стандартами.
  1. Взрывной рост экосистемы. Вокруг стабильного ядра формируется богатая экосистема вспомогательных инструментов (`observability`, `discovery`) и бизнес-приложений (`reverse ETL`, `workspaces`), которые повышают ценность данных.
  1. Платформизация стека данных. Центральные хранилища данных (`Data Warehouse`, `Lakehouse`) превращаются из простых баз данных в полноценные платформы для разработки. Это открывает путь для нового поколения `warehouse-native` SaaS-приложений.
  1. Операционализация данных. Тренд смещается от простой аналитики (посмотреть на дашборд) к активному использованию данных в операционных процессах бизнеса. Технологии `Reverse ETL` являются главным драйвером этого тренда.
  1. Data-Centric AI. В мире машинного обучения фокус окончательно сместился с улучшения алгоритмов на улучшение данных, что стимулирует рынок инструментов для управления жизненным циклом данных в ML (`data labeling`, `feature stores`, `monitoring`).

dbt открывает исходный код MetricFlow: Управляемые метрики для AI и аналитики

Компания dbt Labs объявила о важном изменении в своей стратегии: `MetricFlow`, ключевая технология, лежащая в основе `dbt Semantic Layer`, становится полностью открытой. Проект переводится под лицензию Apache 2.0, что позволяет любому использовать, изменять и встраивать его в свои продукты. Это стратегический шаг, направленный на создание единого отраслевого стандарта для определения бизнес-метрик, особенно в свете бурного развития AI-систем.

Оригинал тут: https://www.getdbt.com/blog/open-source-metricflow-governed-metrics
А гит тут: https://github.com/dbt-labs/metricflow

Еще кстати есть https://github.com/memiiso/opendbt ( Make dbt great again! :) Может они сольются с метриками, интересно.

Проблема: почему семантический слой стал критически важен

Концепция семантического слоя, который служит промежуточным слоем для определения бизнес-логики (метрик, измерений, связей), не нова. Она уже много лет используется в BI-системах для обеспечения согласованности отчетов. Однако с появлением больших языковых моделей (LLM) и инструментов в стиле “Chat with your data” проблема вышла на новый уровень.

Когда AI-агент или LLM пытается ответить на вопрос, обращаясь напрямую к базе данных, он вынужден самостоятельно генерировать SQL-запрос. При этом модель “угадывает”, какие таблицы нужно соединить (`JOIN`), как правильно отфильтровать данные, какую использовать гранулярность по времени и какие оконные функции применить.

Проблемы такого подхода:

  1. Несогласованность: Две разные модели (или даже одна и та же, но с другим запросом) могут сгенерировать разный SQL для расчета, казалось бы, одной и той же метрики. Это приводит к разным цифрам в отчетах.
  2. Ошибки: LLM может не знать о тонкостях бизнес-логики, например, о том, что при расчете выручки нужно учитывать возвраты или использовать специальный финансовый календарь.
  3. Потеря доверия: Когда пользователи получают противоречивые или неверные данные, доверие ко всей системе аналитики быстро падает.

Метрики не должны быть вероятностными, зависящими от “догадок” LLM при каждом вызове. Они должны быть детерминированными.

`MetricFlow` решает именно эту задачу.

Что такое MetricFlow и как он работает

`MetricFlow` — это движок, который преобразует семантические определения бизнес-понятий в готовый к выполнению и оптимизированный SQL-код. Аналитик один раз определяет метрику “Валовая маржа” на языке `MetricFlow`, и после этого любая система (BI-инструмент, AI-агент, Python-скрипт) может запросить эту метрику по имени, будучи уверенной, что получит корректный и одинаковый результат.

Ключевые изменения и их значение

  1. Лицензия Apache 2.0: Это одно из главных нововведений. Apache 2.0 — это разрешительная лицензия, которая позволяет другим компаниям свободно встраивать `MetricFlow` в свои коммерческие и открытые продукты. Это снимает барьеры для принятия технологии и способствует ее распространению как стандарта.
  2. Сотрудничество с Open Semantic Interchange (OSI): dbt Labs будет развивать `MetricFlow` совместно с такими партнерами, как Snowflake и Salesforce, в рамках инициативы OSI. Цель — создать единый стандарт для семантической совместимости между разными платформами, чтобы метрики, определенные один раз, одинаково работали во всех инструментах.

Как MetricFlow обеспечивает надежность AI

`MetricFlow` предоставляет открытый стандарт для метаданных и расширяемый движок, который превращает намерение (“покажи валовую маржу”) в SQL-запрос для хранилища данных.

Пример работы:

Предположим, пользователь задает AI-агенту вопрос:

“Покажи валовую маржу (%) по месяцам за прошлый квартал для Северной Америки (за вычетом скидок и возвратов, по финансовому календарю).”

Без семантического слоя LLM пришлось бы конструировать сложный запрос с нуля. С `MetricFlow` процесс выглядит так:

  1. Агент распознает намерение и запрашивает у `MetricFlow` метрику `gross_margin_pct` с нужными измерениями (`region`, `fiscal_month`) и фильтрами.
  2. `MetricFlow`, на основе заранее созданных определений, строит план запроса:
    • Находит нужные таблицы: `orders`, `discounts`, `returns`, `cogs` (себестоимость).
    • Применяет правильные `JOIN` между ними.
    • Применяет фильтр по региону (`North America`).
    • Группирует данные по месяцам финансового, а не календарного, года.
    • Рассчитывает числитель (выручка) и знаменатель (себестоимость) с учетом того, что популяция данных для них должна быть одинаковой.
    • Вычисляет итоговое соотношение.
  3. `MetricFlow` компилирует этот план в оптимизированный SQL-запрос, специфичный для диалекта конкретного хранилища (Snowflake, BigQuery, Databricks и т.д.).
  4. Запрос выполняется в хранилище, и результат возвращается пользователю.

При этом весь сгенерированный SQL доступен для проверки, что обеспечивает прозрачность и объяснимость вычислений.

Основные возможности движка:

  • Единое определение, выполнение где угодно: Метрики и измерения определяются один раз, а `MetricFlow` компилирует их в SQL для разных диалектов.
  • Оптимизация производительности: Движок строит эффективные запросы, чтобы избежать лишних сканирований и снизить нагрузку на хранилище данных.
  • Поддержка сложных вычислений: `MetricFlow` из коробки обрабатывает сложные соединения, оконные функции, расчеты по когортам и полуаддитивные метрики (например, остатки на счетах, которые нельзя просто суммировать по времени).

`MetricFlow` vs. `dbt Semantic Layer`

Важно понимать различие между двумя компонентами:

  • `MetricFlow` — это движок с открытым исходным кодом для определения и вычисления метрик. Это “сердце” системы, которое выполняет всю сложную работу по генерации SQL.
  • `dbt Semantic Layer` — это коммерческий продукт dbt Labs, построенный *поверх* `MetricFlow`. Он добавляет функциональность корпоративного уровня:
    • Управление доступом (`RBAC`).
    • Версионирование определений метрик.
    • Аудит и отслеживание происхождения данных (`lineage`).
    • Надежные API и коннекторы для интеграции с BI- и AI-инструментами.

Таким образом, `MetricFlow` становится общедоступным строительным блоком, а `dbt Semantic Layer` — готовым решением для его безопасного и управляемого внедрения в компаниях.

Итог

  1. dbt Labs сделала `MetricFlow` (движок для расчета метрик) полностью открытым под лицензией Apache 2.0. Это позволяет всем желающим использовать его без ограничений.
  2. Главная цель — создать открытый стандарт для определения бизнес-метрик. Это особенно актуально для AI-систем, которые часто ошибаются при самостоятельной генерации SQL.
  3. `MetricFlow` позволяет AI и BI-инструментам запрашивать данные по имени метрики (например, `revenue`), получая детерминированный и корректный SQL-запрос. Это повышает надежность и согласованность данных.
  4. Этот шаг способствует совместимости инструментов (`interoperability`) и снижает зависимость от конкретного вендора (`vendor lock-in`). Метрики, определенные один раз, будут работать одинаково в разных системах.
  5. Коммерческий продукт `dbt Semantic Layer` продолжит развиваться как решение для управления жизненным циклом метрик в корпоративной среде (безопасность, контроль версий, аудит).

Сравнение Apache Iceberg, Delta Lake и Apache Hudi: Глубокий анализ (2025)

С ростом популярности архитектуры Data Lakehouse усилился интерес к трём основным открытым проектам в этой области: Apache Hudi, Delta Lake и Apache Iceberg. Все три технологии продолжают активно развиваться, и в этой статье представлено актуальное сравнение их возможностей по состоянию на октябрь 2025 года.

Оригинал тут: https://www.onehouse.ai/blog/apache-hudi-vs-delta-lake-vs-apache-iceberg-lakehouse-feature-comparison

Примечание: Если выбор формата вызывает сложности, обратите внимание на проект Apache XTable (Incubating), который обеспечивает интероперабельность между Hudi, Delta и Iceberg, позволяя использовать несколько форматов одновременно.

Сравнение возможностей

Функциональность записи

Функция Apache Hudi (v1.0.2) Delta Lake (v4.0.0) Apache Iceberg (v1.10.0)
ACID-транзакции
Copy-on-Write
Merge-on-Read ✅ Полнофункциональный ❌ Векторы удалений (эксперимент.) ❌ Векторы удалений (огранич.)
Эффективная bulk-загрузка ✅ Bulk_Insert
Индексирование ✅ 8+ типов индексов ❌ Bloom-фильтр проприетарный ✅ Метаданные для статистики
Частичные обновления ✅ Partial Updates
Миграция таблиц ✅ Bootstrap ✅ Convert to Delta
Управление конкуренцией ✅ OCC, MVCC, NBCC ✅ OCC ✅ OCC
Неблокирующая конкуренция ✅ NBCC ❌ OCC с перезапуском ❌ OCC с перезапуском
Менеджеры блокировок ✅ ФС, DynamoDB, Hive, Zookeeper ✅ Только внешний DynamoDB ✅ Каталог или внешние провайдеры
Дедупликация ✅ Ключи, Precombine ❌ Нет первичных ключей ❌ Нет первичных ключей
Зависимость от каталога ❌ Не требуется ❌ Не требуется ✅ Обязателен

Ключевые отличия:

  • Hudi предлагает наиболее продвинутые механизмы управления конкуренцией, включая неблокирующий контроль (NBCC)
  • Только Hudi поддерживает настоящий Merge-on-Read без компромиссов производительности
  • Hudi предоставляет встроенные инструменты для дедупликации через первичные ключи

Метаданные таблиц

Функция Apache Hudi Delta Lake Apache Iceberg
Масштабируемость метаданных ✅ LSM-дерево + HFile (100x ускорение) ❌ Parquet чекпойнты (медленно) ❌ Avro манифесты (медленно)
Управление индексами ✅ Асинхронное многомодальное
Эволюция схемы ✅ Добавление, переупоряд., удаление
Эволюция партиций ✅ Кластеризация + индексы выражений ✅ Эволюция партиций
Первичные ключи ❌ Только в проприетарной версии
Статистика столбцов ✅ HFile (до 50x ускорение) ✅ Parquet чекпойнт ✅ Avro манифест

Важные особенности:

  • Hudi использует оптимизированный формат HFile для метаданных, что значительно ускоряет поиск
  • Только Hudi поддерживает настоящие первичные ключи как в реляционных БД
  • Hudi предлагает более гибкий подход к партиционированию через кластеризацию

Функциональность чтения

Функция Apache Hudi Delta Lake Apache Iceberg
Time Travel
Merge-on-Read запросы ✅ Snapshot Query ❌ Сложная поддержка ✅ Все запросы мержат векторы удалений
Инкрементальные запросы ✅ + CDC запросы ✅ CDF (эксперимент.) ❌ Только аппенды
CDC запросы ✅ + before/after images
Вторичные индексы
Предикаты для пропуска данных ✅ Индексы выражений ✅ Логические предикаты ✅ Трансформации таблиц

Сервисы таблиц

Функция Apache Hudi Delta Lake Apache Iceberg
Авторазмер файлов ❌ Ручное управление
Компактизация ✅ Управляемая ❌ 2-этапное обслуживание ❌ Ручное обслуживание
Очистка ✅ Управляемая ❌ VACUUM вручную ❌ Ручное удаление снапшотов
Кластеризация ✅ Авто + Z-order/Hilbert ❌ Z-order в OSS, авто – проприетар. ❌ Z-order вручную

Поддержка экосистемы

Все три формата имеют широкую поддержку в экосистеме данных:

  • Apache Spark, Flink, Trino, DBT – полная поддержка чтения/записи во всех форматах
  • Kafka Connect – Hudi и Iceberg имеют нативную поддержку, Delta – только проприетарную
  • Облачные платформы (AWS, GCP, Azure) – все три формата поддерживаются с некоторыми ограничениями
  • Snowflake – нативная поддержка Iceberg, Hudi через XTable

Производительность: TPC-DS бенчмарки

Согласно независимым тестам:

  • Hudi и Delta показывают сопоставимую производительность
  • Iceberg consistently отстаёт по скорости выполнения запросов

Важно: При сравнении производительности учитывайте, что Hudi по умолчанию оптимизирован для mutable-нагрузок (upsert), в то время как Delta и Iceberg – для append-only. Для честного сравнения используйте `bulk-insert` режим в Hudi.

Ключевые дифференцирующие возможности

Инкрементальные пайплайн

Hudi предлагает наиболее зрелую поддержку инкрементальной обработки с трекингом всех изменений (вставки, обновления, удаления) и предоставлением их в виде change streams. Это позволяет строить эффективные ETL-пайплайны без перевычисления полных наборов данных.

Управление конкуренцией

В то время как все три системы поддерживают оптимистический контроль конкуренции (OCC), только Hudi предлагает:

  • Неблокирующий контроль конкуренции (NBCC)
  • Файл-уровневую гранулярность блокировок
  • Возможность работы с асинхронными сервисами таблиц без остановки записи

Merge-on-Read

Только Hudi предоставляет полнофункциональный Merge-on-Read, который позволяет:

  • Балансировать между производительностью записи и чтения
  • Использовать row-ориентированные форматы для стриминга и column-ориентированные для аналитики
  • Выполнять компактизацию асинхронно

Кластеризация vs Эволюция партиций

  • Iceberg: Partition Evolution – изменение схемы партиционирования для новых данных
  • Hudi: Гибридный подход – coarse-grained партиционирование + fine-grained кластеризация с возможностью эволюции без перезаписи данных

Многомодальное индексирование

Только Hudi предлагает асинхронную подсистему индексирования, поддерживающую:

  • Bloom, hash, bitmap, R-tree индексы
  • 10-100x ускорение point lookup запросов
  • 10-30x общее ускорение запросов в реальных нагрузках

Реальные кейсы использования

Peloton

  • Увеличение частоты ингестии с 1 раза в день до каждых 10 минут
  • Снижение времени выполнения снапшот-заданий с 1 часа до 15 минут
  • Экономия затрат через оптимизацию использования EMR-кластеров

ByteDance/TikTok

  • Обработка таблиц объемом 400+ PB
  • Ежедневный прирост данных на уровне PB
  • Пропускная способность >100 GB/s на таблицу
  • Выбор Hudi из-за открытости экосистемы и поддержки глобальных индексов

Walmart

  • Использование Merge-on-Read для снижения задержек
  • Нативная поддержка удалений для GDPR/CCPA compliance
  • Row versioning для обработки out-of-order данных

Инновации сообщества

Многие ключевые функции data lakehouse были впервые реализованы в Hudi:

Инновация Hudi Год Аналог в других проектах
Транзакционные обновления 2017 Delta OSS (2019)
Merge-on-Read 2017 Iceberg (2021)
Инкрементальные запросы 2017 Delta Change Feed (2022)
Z-order/Hilbert кривые 2021 Delta OSS (2022)
Многомодальное индексирование 2022 ❌ Нет аналогов
Контроль конкуренции без блокировок 2024 ❌ Нет аналогов

Заключение

Критерии выбора

Выбирайте Apache Hudi если:

  • Ваши workload’ы содержат значительное количество обновлений и удалений
  • Требуется низкая задержка от конца в конец
  • Нужны продвинутые возможности управления конкуренцией
  • Важна производительность point lookup запросов
  • Требуется гибкое управление layout данных через кластеризацию

Рассмотрите Delta Lake если:

  • Вы используете экосистему Databricks
  • Workload’ы преимущественно append-only
  • Достаточно базовых возможностей управления конкуренцией

Apache Iceberg может подойти если:

  • Основная задача – работа с очень большими объемами данных в cloud storage
  • Требуется скрытое партиционирование с эволюцией
  • Workload’ы в основном аналитические с минимальными обновлениями

Итоговые рекомендации

  1. Для зрелых production-нагрузок с frequent updates, high concurrency и low latency требованиями Apache Hudi предлагает наиболее полный набор возможностей.
  1. Не ограничивайтесь сравнением “галочек” – оценивайте производительность на своих данных и workload’ах.
  1. Рассмотрите Apache XTable если невозможно определиться с одним форматом или требуется интероперабельность между системами.
  1. Учитывайте roadmap проекта – Hudi продолжает лидировать в инновациях, что может быть важно для долгосрочных инвестиций.

Технологии data lakehouse продолжают быстро развиваться, и выбор должен основываться на конкретных требованиях ваших use cases, а не только на текущем состоянии функциональности.

Earlier Ctrl + ↓