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

В данной статье я хочу рассказать о паттерне Write-Audit-Publish, о предпосылках его появления, а также наглядно рассмотреть как он работает.

История зарождения

С момента появления концепции data lake, компании старались собирать как можно данных, иногда не слишком задумываясь об их качестве. Появилось четкое понимание, что данные "когда-нибудь" могут быть использованы. Так, согласно исследованиям market.us объемы данных хранящихся в мире выросли приблизительно в 90 раз за 15 лет.

Объем обрабатываемых данных по всему миру
Объем обрабатываемых данных по всему миру

Концепция Map-Reduce отлично подходит для работы с большими данными, учитывает непостоянство схем и прочее, однако, действительно годный отчет можно построить только на качественных данных. А эволюция слоевой модели данных (те самые raw, ods/dds/dm и ещё миллиарды аббревиатур, которые придумают разработчики в каждой отдельной компании) привела к тому, что получив незначительную ошибку в начале pipeline данных, поймать её проблематично из-за обилия этих самых слоев и join'ов, необходимых для формирования итогового отчета.

Ответом на такую проблему стало развитие data-quality направления. Суть заключается в том, чтобы написать какие-то условия для данных, пройдя которые, мы можем считать, что с данными все хорошо. И в идеале, написав quality-check'и для всех элементов pipeline на каждом слое ведь мы не копируем проверки из слоя в слой за счет их уникальности мы можем быстро отследить, с какого момента начал рушиться финальный отчет.

В 2017 году инженеры Netflix опубликовали доклад Whoops the Numbers are wrong! Scaling Data Quality @ Netflix., в котором описали проблемы некачественных данных и описали новый подход к управлению качеством данных, который назвали Write-Audit-Publish.

Что такое Write-Audit-Publish?

Для начала условимся, WAP - именно патерн. Это общий подход, не дающий указаний как конкретно его релизовывать. Как есть несколько реализаций Singleton в зависимости от языка программирования, так есть несколько реализаций WAP, в зависимости от используемых в вашем кластере решений.

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

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

Пример данных таблицы Orders
Пример данных таблицы Orders

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

Давайте разберем на примере, как же нужно работать с таблицей Orders так, чтобы данные можно было проверить, но до проверки они не были доступны читателям raw слоя.

Наглядное описание

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

На 1 августа у нас есть все данные до 31 июля. Мы хотим загрузить данные за 31 июля безопасно.
На 1 августа у нас есть все данные до 31 июля. Мы хотим загрузить данные за 31 июля безопасно.

Чтобы загрузить данные безопасно, применим паттерн WAP

Шаг 1: Write

Запишите обрабатываемые данные в место, недоступное для чтения последующими пользователями. Это может быть некоторая временная таблица/директория, бранч. Есть реализации с флагом "enabled".
Таким образом данные уже в нашем datalake, и мы можем их анализировать, но это никак не влияет на работу пайплайнов данных.

Загрузили данные в audit хранилище. Данные уже в кластере, но недоступны читателям raw orders.
Загрузили данные в audit хранилище. Данные уже в кластере, но недоступны читателям raw orders.

Шаг 2: Audit

Проверьте данные с помощью Quality checks. Тут все просто, есть большое множество фреймворков вроде spark-expectations, soda. В нашем случае для проверки положительности суммы заказа достаточно простого sql запроса. Единственное, я рекомендую хранить где-то результаты проверок, чтобы иметь статистику корректности данных.

Началась проверка данных, по итогам которой данные помечаются как "качественные"
Началась проверка данных, по итогам которой данные помечаются как "качественные"

Шаг 3: Publish

Опубликуйте данные для чтения из таблицы Orders. Есть варианты с изменением флага в таблице таким образом, чтобы пользователи, выполняющие запросы, теперь включали эти данные в свои результаты. Коллеги по цеху из Netflix придумали систему с 2 таблицами, которые смотрят на один и тот же каталог в s3, что позволяет уменьшить количество движения данных (а в S3 это важно), но на мой взгляд это довольно сложная система и на текущий день есть более оптимальные решения.

Качественные данные опубликованы и доступны любому читателю
Качественные данные опубликованы и доступны любому читателю

Заключение

Таким образом, мы за 3 довольно простых шага смогли загрузить данные так, чтобы гарантировать качество поставляемых данных. Отмечу, что почему-то многие стремятся реализовать WAP как одну жирную джобу. Это излишнее требование, так как WAP не накладывает никаких требований атомарности. Например, вполне допускается, что разработчик quality-check проверок ошибся и проверял все ордера на отрицательность сумм. И как раз отсутствие атомарности позволяет нам быстро поправить datacontract и перезапустить проверку без дополнительных загрузок.

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

Буду рад узнать ваше мнение относительно данного паттерна и насколько вы применяете его в работе!

Комментарии (1)


  1. BogdanPetrov
    16.08.2025 06:47

    Спасибо за статью!

    однако я не нашел никакой информации о паттернах работы с данными

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

    Что касается Write-Audit-Publish, у нас такие проверки называют "блокирующими" в том плане, что они блокируют дальнейшую работу пайплайна при срабатывании проверки. И, например, в статье Ростелеком используется такое же название: https://habr.com/ru/companies/rostelecom/articles/675554/