2750
Лучшие посты по анализу данных и работе с Big Data на русском и английском языке Разместить рекламу: @tproger_sales_bot Правила общения: https://tprg.ru/rules Другие каналы: @tproger_channels
Почему быстрый запрос ClickHouse ждёт лишний RTT
У клиента ClickHouse простой SELECT после простоя соединения занимал около 64 мс вместо 32 мс. Команда обнаружила дополнительный сетевой обмен, хотя вычисление запроса было быстрым.
В Native-протоколе клиент ждёт пакет EndOfStream. Перед ним сервер отправляет результат и служебные пакеты с логами, прогрессом и метриками. После простоя TCP уменьшает окно перегрузки: в него может не поместиться вся эта последовательность.
С TCP_NODELAY небольшие записи уходят сразу и создают много отдельных TCP-сегментов. Сервер исчерпывает окно и ждёт подтверждения клиента, прежде чем отправить остаток. Так появляется лишний RTT.
В разборе расследования проблему воспроизводят через Linux network namespaces. Исправление — собрать служебные пакеты в буфер и отправлять вместе. Число 32 мс относится к сети конкретного клиента; причина полезна для диагностики хвоста задержек после простоя.
#clickhouse #производительность
Как менять таблицу Iceberg без переписывания старых файлов
Таблица выросла, диапазона числового поля больше не хватает, а запросы требуют другого партиционирования. В Iceberg такие изменения можно выполнить через метаданные.
В практическом разборе Redshift показаны добавление, удаление и переименование колонок, безопасное расширение типов и изменение полей партиционирования через ALTER TABLE. Колонки отслеживаются по уникальным идентификаторам. Для добавленного поля старые строки возвращают NULL.
При смене партиционирования новые данные записываются по обновлённой схеме, а старые файлы сохраняют прежнюю раскладку. Движок учитывает оба варианта при чтении. Для замены одного преобразования другим предусмотрена атомарная операция REPLACE PARTITION FIELD.
Изменение метаданных не перераспределяет уже записанные данные. Схему стоит выбирать под реальные фильтры и соединения; если нужно изменить физическую раскладку старых файлов, потребуется отдельная переработка данных.
Как сократить паузы при ребалансировке Kafka
Добавление потребителя в большую группу может задержать обработку событий: участникам нужно перераспределить партиции. Протокол KIP-848 переносит координацию на брокер и выполняет перераспределение инкрементально. Потребители с неизменившимися назначениями продолжают работу.
В Amazon MSK нужен Kafka 4.0+ и клиент с поддержкой протокола. На клиенте задают group.protocol=consumer. Интервал heartbeat, таймаут сессии и алгоритмы назначения теперь управляются на стороне брокера; прежние клиентские параметры нужно убрать.
Новый протокол не отменяет диагностику задержек. Проверьте фактически используемый протокол по логам, стабильность потребителей и корректное завершение через consumer.close().
В инструкции AWS разобраны переход на KIP-848 и проверка результата по consumer lag. Материал пригодится для потоковых пайплайнов с частыми перезапусками и масштабированием обработчиков.
Как анализировать IP-адреса и подсети встроенными SQL-функциями
В сетевых журналах IP выглядит как строка, но проверка попадания в подсеть требует работы с диапазонами. Разбор адресов регулярками и собственные UDF усложняют такие запросы на больших объёмах.
В Databricks Runtime 18 LTS и новее доступны встроенные функции для IPv4, IPv6 и CIDR. Они принимают строковое и бинарное представления адресов.
Функция ip_cidr_contains(cidr, needle) проверяет, входит ли адрес или другая подсеть в заданный блок. Её можно использовать для соединения журналов соединений со справочником опасных сетей.
В статье таким запросом обогащают сетевые события и ищут источники, сканирующие много адресов и портов. Операции встроены в движок, поэтому оптимизатор и Photon могут ускорять их выполнение.
Пример SQL для анализа сетевых журналов
Как искать ближайшие векторы массовым SQL-соединением
Для каждой строки с вектором нужно найти k ближайших строк в другой таблице. Когда запросов миллионы, отдельное сетевое обращение для каждого поиска ограничивает скорость всего задания.
Databricks реализовала эту операцию как SQL-соединение NEAREST BY. Оно поддерживает точный и приближённый пакетный поиск; Photon вычисляет расстояния блоками с помощью специализированного ядра матричного умножения.
Для приближённого поиска IVF-индекс хранится в обычной Delta-таблице с liquid clustering. При чтении движок отсекает большую часть разделов и проверяет кандидатов.
Подход рассчитан на массовое сопоставление сущностей, обогащение записей и подготовку рекомендаций. Здесь оценивают пропускную способность всего задания и соблюдение SLA.
Устройство соединения и векторного индекса
Почему резервное копирование вытесняет данные из кеша PostgreSQL
Во время бэкапа PostgreSQL запросы могут замедлиться из-за page cache Linux. Последовательное чтение всей базы заполняет кеш данными для копирования и вытесняет страницы, нужные рабочей нагрузке.
Команда ClickHouse Managed Postgres проверила это на базе размером 467 ГБ. Буферизованный бэкап вытеснил все 40 GiB прогретой неактивной таблицы. В вариантах с direct I/O её данные остались в кеше.
Direct I/O обходит page cache, но отключает у этих чтений автоматическое упреждающее чтение — readahead. Поэтому маленькие запросы к массиву NVMe могут недогружать диски.
В разборе подбирают размер блока под полную полосу RAID0 и число параллельных читателей под оборудование. Проверять нужно и скорость бэкапа, и задержки запросов во время него.
Эксперимент с четырьмя режимами чтения
Как обслуживать большой dbt-проект и находить медленные модели
В IFCO миллиарды событий отслеживания превращаются в показатели движения тары. Некоторые данные опаздывают на недели и месяцы, поэтому пайплайн должен корректировать уже рассчитанную историю.
Команда настраивала инкрементальные dbt-модели по реальному плану выполнения: проверяла объём чтения и записи, стратегию MERGE, liquid clustering и dynamic file pruning. Время основного задания сократилось более чем на 60%; ночной полный пересчёт убрали.
Для эксплуатации каждую модель вынесли в отдельную задачу Databricks Jobs через открытый databricks-dbt-factory. Так видно, какой шаг задерживает запуск, а повторно выполнять можно конкретные модели.
Скомпилированный SQL показывает намерение модели. План выполненного запроса помогает проверить, сколько данных она действительно обработала.
Разбор моделей, диагностики и запуска dbt
Как ускорить запросы Spark без переписывания SQL
Тяжёлый запрос приходит из BI-дашборда, а изменить его SQL сложно. В AWS Spark runtime можно ускорить такой запрос через материализованное представление Iceberg.
Оптимизатор сравнивает логический план с доступными представлениями. Если одно из них покрывает запрос целиком или частично, план читает заранее вычисленный результат. Если совпадения нет, выполняется исходный запрос.
Статья разбирает разные варианты покрытия: JOIN, агрегации и точное совпадение более сложных вычислений. Представление хранится как Iceberg-таблица; обновление можно настроить по расписанию.
Автоматическая подстановка доступна в Amazon EMR начиная с 7.12.0 и AWS Glue с 5.1. При выборе представления учитывайте частоту запросов, стоимость обновления и допустимую задержку данных.
Примеры планов и настройка подстановки
Когда DuckDB хватает для ETL вместо Spark
В примере AWS задание на DuckDB выполнилось примерно за 56 секунд, а эквивалентное на Spark — за 117. Оба запускались в Glue 6.0 с конфигурацией 2 DPU и вернули 1176 строк.
DuckDB работает внутри одного воркера: читает Parquet из S3, выполняет SQL-преобразования и записывает результат в S3 Tables через Iceberg REST catalog. Выходную таблицу можно запрашивать из Athena.
Для небольших регулярных заданий время запуска и накладные расходы движка могут заметно влиять на итог. Здесь DuckDB уложился в минимальную минуту тарификации, а Spark потребовал две.
Это замер одного сценария. Для своего ETL сравните объём входных данных, сложность JOIN, доступную память и полное время задания.
Код пайплайна и условия сравнения
Почему RLS в PostgreSQL может замедлить запрос с индексом
В тесте PostgreSQL 17.10 поиск по lower(customer_email) занимал 0,21 мс без RLS и 34–45 мс с политикой доступа. Это результат для крупнейшего клиента: около 267 тысяч строк в таблице почти на 2 млн записей.
Составной индекс использовался только для tenant_id, а условие по email стало фильтром. Причина в правилах RLS: функция lower() не помечена как leakproof, поэтому её нельзя свободно применять к строкам до проверки доступа.
В этом сценарии помогла сохранённая вычисляемая колонка с email в нижнем регистре и индексом по паре «клиент, email»: время вернулось к 0,25 мс. Замеры сделаны с прогретым кэшем. Проверяйте план под ролью приложения: владелец таблицы обычно обходит RLS.
Замеры, планы и варианты политик
Как Zalando проверяет качество поиска до запуска нового рынка
В 2025 году Zalando выходила в Люксембург, Португалию и Грецию. Данных о запросах и кликах ещё не было, поэтому качество поиска заранее оценивали с помощью LLM-судьи.
Пайплайн проверки релевантности берёт запросы действующих рынков: NER-модель выделяет атрибуты, а похожие запросы переводят на язык нового рынка.
Airflow запускает получение выдачи в Kubernetes, затем GPT-4o оценивает товары по шкале от 0 до 4 с учётом описания и изображения. Низкие оценки помогают найти ошибки в товарных данных, атрибутах и ранжировании.
Кеш хранит товары и оценки пар «запрос — товар», поэтому после исправлений прогон можно повторить без лишних обращений к API.
Как выявить перекос долей выборки в A/B-тесте с NumPy и SciPy
В тесте на миллионе пользователей группы 502 470 и 497 530 кажутся равными, но для плана 50/50 это почти пять стандартных отклонений.
Такой перекос называют Sample Ratio Mismatch, или SRM. Его ищут χ²-тестом: сравнивают фактические размеры групп с плановыми долями. Достаточно счётчиков, NumPy и scipy.stats; метрика теста не участвует.
Если SRM сработал, сначала проверьте логирование и фильтрацию участников, затем оценивайте эффект. Код проверки и симуляция потери пользователей показывают, почему малый перекос опасен на большой выборке.
PySpark завис на 99%: как найти и устранить перекос данных
199 из 200 задач завершаются за секунды, а последняя работает 30 минут. Строки с одинаковым ключом попадают в одну партицию, и горячий ключ задерживает весь этап.
В Spark UI сравните максимальные Duration, Shuffle Read Size и Spill с медианой. Разница в десятки раз укажет на перекос. Затем посчитайте строки по ключам.
В разборе для Spark 3.5 советуют включить AQE: он дробит перекошенные партиции при соединении. Для малой таблицы используйте broadcast join, а для горячих ключей — salting, добавляющий суффиксы и распределяющий строки по партициям.
Как Apache Celeborn сохраняет shuffle-данные Spark при потере исполнителей
Spot-инстансы могут отключить за две минуты. Если Spark хранит shuffle-данные на локальном диске исполнителя, потеря узла запускает повторное вычисление стадий.
Apache Celeborn выносит shuffle в отдельный кластер: исполнители отправляют блоки общим worker-узлам, поэтому их можно заменять без потери промежуточных данных. Каждый раздел shuffle реплицируется ещё на два worker-узла.
Схема развёртывания для EMR on EC2 и EMR on EKS включает настройки Spark и мониторинг через Prometheus и Grafana.
Почему 1000 файлов на процесс в PostgreSQL не жёсткий лимитmax_files_per_process по умолчанию равен 1000. Это размер кэша открытых дескрипторов, а не порог ошибки. Когда пул заполнен, бэкенд закрывает давно не использованный файл и открывает нужный. Запрос работает, но тратит время на системные вызовы.
В PostgreSQL 18.6 таблица из 3000 разделов создала 6000 файлов. При значении 8192 повторное сканирование обошлось без open() и ускорилось примерно на 8%: со 180 до 165 мс. Данные уже были в shared_buffers.
Одной настройки мало: systemd даёт процессу мягкий лимит 1024. Сначала посчитайте файлы в каталоге базы и увеличьте LimitNOFILE, затем задайте пул с запасом и перезапустите PostgreSQL. В PostgreSQL 18 ориентируйтесь на весь сервер: воркеры асинхронного ввода-вывода обслуживают все бэкенды.
Как поделиться Parquet через небольшой каталог DuckDB
Чтобы дать коллегам доступ к набору Parquet-файлов, можно подготовить DuckDB-файл только с представлениями. Он хранит запросы и имена отношений, а сами данные остаются в объектном хранилище.
В руководстве команды DuckDB создают VIEW над удалённым файлом и публикуют каталог по URL. Получатель подключает его в режиме READ_ONLY и обращается к представлениям как к таблицам.
В определениях VIEW можно закрепить названия колонок, фильтры и соединения. Если данные разделили на файлы по годам или переименовали поле, автор обновляет представление, сохраняя привычный запрос для потребителей.
Каталог не заменяет доступ к источникам: читателю нужны права и на DuckDB-файл, и на данные, на которые он ссылается. Для изменения опубликованного каталога редактируют локальную копию и загружают её заново. Скорость запросов зависит от сети и устройства Parquet-файлов.
#duckdb #dataengineering
Как выполнять свой код рядом с данными в ClickHouse
Чтобы посчитать токены в сохранённых запросах к LLM, обычно выгружают тексты, вызывают библиотеку и загружают результат обратно. Executable UDF позволяет вызвать такой код из SQL внутри ClickHouse Cloud.
В разборе рабочего примера Rust-функция считает токены при вставке данных через материализованное представление. Отдельная Python-функция с сетевым доступом периодически отправляет выборку ответов на оценку модели.
Функции используют CPU и память того же сервиса, что и запросы. Их расходы видны в system.query_log: время выполнения, ожидание пула и объём переданных данных. Версии можно закреплять отдельно для каждого сервиса.
В тесте подсчёта токенов Rust оказался в 1,4 раза быстрее Python. Это результат конкретных библиотек и нагрузки: сама смена языка ускорения не гарантирует. Сетевой доступ пока доступен Python-функциям; Native runtime предназначен для вычислений.
Как ускорить GROUP BY по повторяющимся строкам в DuckDB
В наборе железнодорожных данных 380 959 строк, но всего 537 названий станций. При группировке по названию движок снова и снова хеширует и сравнивает одни и те же строки.
Команда DuckDB предлагает вынести названия в таблицу измерений, а в основной таблице хранить числовые ключи. Для 537 значений достаточно двухбайтового USMALLINT. Запрос сначала агрегирует по ключам, затем возвращает названия через JOIN уже небольшого результата. Для top-N соединение можно выполнить после LIMIT.
Числовые ключи уменьшают размер записей хеш-таблицы и стоимость сравнения. При компактном диапазоне ключей оптимизатор может выбрать агрегацию с прямой индексацией массива.
В разборе с SQL-примерами показаны создание справочника и его обновление. Приём полезен для повторных запросов по длинным строкам с частыми повторами. Он не уменьшает число групп; для почти уникальных значений выгода ограничена.
Как Delivery Hero сократила задержку обработки рекламных событий
В рекламном пайплайне Delivery Hero средний промежуток между событием и его записью сократился с 61 минуты до 1,2 секунды. Команда перешла с часовых пакетов на Apache Flink.
Пайплайн расшифровывает события, удаляет дубликаты и асинхронно обогащает их данными из DynamoDB. Затем многодневное соединение связывает взаимодействия с заказами, а агрегаты сохраняются в отчётную базу каждые пять минут.
Дедупликация держит ключи в RocksDB-состоянии 30 часов. Инкрементальные checkpoints уходят в S3; после сбоя повторно доставленные события отсеиваются. Так команда получила фактически однократный биллинг поверх доставки at-least-once.
Эксплуатационные расходы снизились примерно на 57%. Задержка 1,2 секунды относится к записи событий, а не к обновлению отчётных агрегатов.
Архитектура обработки и результаты миграции
Как Flink SQL понимает нестандартные CDC-события
CDC-источник может обозначать изменения как INSERT, MODIFY и REMOVE, а Flink ждёт свои типы операций. FROM_CHANGELOG позволяет задать соответствие в SQL и превратить журнал событий в обновляемую таблицу.
TO_CHANGELOG выполняет обратное преобразование: выдаёт изменения как обычные записи с колонкой операции. Это помогает передавать результат потоковой агрегации в приёмник, который принимает только вставки.
Соответствие операций нужно проверять: ошибочная настройка может испортить состояние таблицы без исключения. FROM_CHANGELOG также не разделяет одно событие со старым и новым состоянием на две строки.
В Flink 2.3 поддержка ограничена. Расширенные параметры из статьи доступны с 2.4 и уже есть в Confluent Cloud for Apache Flink.
SQL-примеры и ограничения CDC-функций
🧑💻 Какие навыки помогают вам в разработке в 2026 году?
Что вы чаще используете в работе? В каких задачах помогает ИИ, а где проще справиться самостоятельно?
Мы решили собрать портрет современного разработчика — и приглашаем вас поделиться своим опытом. Расскажите, какие навыки вам пригодились и как вы используете ИИ. Если обходите его стороной, нам тоже интересно узнать почему.
Опрос анонимный и займёт около 5 минут. Результаты опубликуем в общем большом исследовании.
👉 Пройти опрос
Как передавать данные датчиков из MQTT в Kafka
Датчик публикует JSON в локальный MQTT-брокер. Чтобы отправить эти события в Kafka, нужно выбрать маршрут, схему сообщений и способ сохранить сведения об источнике.
Автор проверил несколько вариантов, включая MQTT Source Connector, Pro Mosquitto и HiveMQ. Коннектор забирает сообщения из доступного ему брокера и использует полное имя MQTT-топика как ключ Kafka-сообщения.
У MQTT нет встроенной схемы данных. Для дальнейшей обработки автор предлагает задать и проверять её, например, во Flink. В отдельных интеграциях имя исходного топика не переносится: идентификатор площадки придётся добавить в payload.
Есть и нюанс эксплуатации: изменение числа задач или списка топиков MQTT Source Connector может привести к потере данных из-за перераспределения подписок.
Схемы подключения, конфигурации и ограничения
Как LinkedIn ищет метрики среди миллиардов записей
Индекс метаданных метрик LinkedIn обслуживает более 150 тысяч запросов в минуту со средней задержкой 68 мс. Он работает с более чем 13 млрд метрик, около 30% которых меняются за день.
Раньше запросы распределялись между собственным поисковым индексом, Elasticsearch и KV-хранилищем. Теперь общий шлюз переводит их в SQL для ClickHouse, поэтому потребителям не пришлось менять интеграции.
Данные лежат в ReplacingMergeTree. Поток изменений поддерживает актуальность индекса, а свежая ежедневная таблица догоняет изменения перед переключением. Отдельные колонки заменяют поиск регулярками по составным именам; projections ускоряют тяжёлые агрегации.
По оценке команды, расход памяти сократился примерно в пять раз. 68 мс — среднее по разным типам запросов, включая аналитические.
Архитектура индекса и результаты миграции
Polars: как отличить медленный JOIN от ожидания данных
В примере профилирования Polars запрос выполнялся около 5 секунд, а CPU-время JOIN составило примерно 103 мс. Основным ограничением было чтение из S3.
Профилировщик показывает логический и физический планы, потоки строк и прогресс узлов. Для локального запроса нужно установить polars_cloud и включить pl.Config.enable_monitoring(). Возможность описана для streaming- и distributed-движков.
Запрос исполняется на вашей инфраструктуре; планы и телеметрия передаются в платформу Polars Cloud. Там можно смотреть текущие и завершённые запросы, находить дорогие операции и проверять, насколько рано применяются фильтры.
Такой профиль помогает выбрать, что оптимизировать первым: загрузку данных, JOIN или агрегацию.
Подключение и разбор профиля Polars
Как инкрементальный ETL в Apache Hudi сокращает повторную обработку данных
Если таблица на 10 ТБ получает 50 ГБ изменений в час, полный пересчёт читает все 10 ТБ. Инкрементальный пайплайн берёт только дельту: объём чтения сокращается в 200 раз.
Apache Hudi читает изменения после сохранённой контрольной точки. Запрос возвращает последнее состояние изменённых записей, а CDC-журнал — каждую операцию до и после изменения.
Для цепочки таблиц нужны первичные ключи и порядок коммитов. Частые записи создают мелкие файлы, поэтому Hudi асинхронно уплотняет и очищает данные, не останавливая запись.
Как согласовывать JSON-события в DuckDB без Python
В CDC-потоке событие часто меняет одно-два поля. В DuckDB v2.0 json_merge_patch_diff вычисляет патч между старым и новым состоянием, а json_merge_patch восстанавливает документ.json_deep_merge объединяет JSON из разных источников, сохраняя исходное значение при JSON null. Для дедупликации json_normalize сортирует ключи перед хешированием.
Примеры SQL и тест на 500 000 синтетических CDC-событий
Как подготовить Parquet для быстрых запросов Power BI Direct Lake
На столбце из 142 млн строк запись encoding_stats в футере Parquet сократила первое обращение с 10 857,5 до 689,3 мс. VertiPaq выбрал быстрый путь после подтверждения словарного кодирования в метаданных.
Direct Lake загружает только затронутые запросом столбцы. Без словарного кодирования значения приходится декодировать и хешировать заново.
Эксперименты с DuckDB и delta-rs рекомендуют 2–6 млн строк на группу, словарное кодирование столбцов и сортировку по полям фильтров. Результат измеряйте на холодном и прогретом кеше.
Как ограничить память GROUP BY в ClickHouse при высокой кардинальности
22,82 GiB против 9,57 GiB пиковой памяти: такой результат даёт max_bytes_before_external_group_by в эксперименте с высококардинальной группировкой. Когда объём промежуточных данных достигает заданного порога, ClickHouse продолжает агрегацию с использованием диска. Цена экономии памяти: время запроса выросло с 9,433 до 13,930 секунды.
Для динамических атрибутов авторы предлагают Map. Поля, по которым часто фильтруют или считают агрегаты, стоит материализовать в отдельные типизированные колонки: так запросам не приходится каждый раз читать карту и преобразовывать строки в числа.
Разбор высокой кардинальности в ClickHouse поможет выбрать компромисс между памятью и скоростью, а также спроектировать хранение атрибутов под реальные запросы.
Как в Zalando сократили состояние Flink на 75%
В пайплайне обогащения товарных данных цепочка SQL JOIN раздула состояние Flink до 235–245 ГБ. Каждый независимый оператор хранил собственную копию входных и промежуточных записей. Часовые снимки загружали процессор на 100% почти на 12 минут, увеличивали задержку и провоцировали перезапуски.
Команда объединила входящие потоки в DataStream[BaseEvent], сгруппировала события по SKU и заменила цепочку JOIN одной KeyedProcessFunction. Данные каждого товара теперь лежат в одном ValueState: событие обновляет нужные поля, а записи со старой временной меткой отбрасываются до записи состояния.
Переход на собственный MultiStreamJoinProcessor уменьшил состояние до 56 ГБ, а восстановление после перезапуска сократил с 12–20 до 4–5 минут. Полезный повод проверить, не дублируют ли последовательные stateful JOIN промежуточные данные в ваших Flink-задачах.
Как подготовить медицинские изображения и честно проверить модель
Два рентгеновских снимка 512 × 512 могут показывать разные физические области: масштаб пикселя хранится в DICOM. Перед обучением нужно удалить идентификаторы, учесть положение пациента и пересчитать масштаб после изменения размера. Разбор пути снимка до предсказания содержит ноутбук с pydicom, NumPy и OpenCV.
Нормализация приводит пиксели к общей шкале, гармонизация уменьшает различия между сканерами. Данные делят по пациентам: иначе снимки одного человека попадут и в обучение, и в тест.
Для классификации нужна метка снимка, для детекции — область, для сегментации — маска. Модель проверяют на данных другой больницы и оценивают не только перекрытие, но и форму находок.