A B C D E F G H I J K L M N O P Q R S T V W Y Z А Б В Г Е И К М О П С Т Ц

Data observability

Data observability (Наблюдаемость данных) это практика непрерывного сбора метаданных о датасетах и конвейерах, при которой состояние витрины оценивается не по фиксированному порогу, а по её собственной истории. Термин пришёл из наблюдаемости в эксплуатации приложений, где по метрикам, логам и трассировкам восстанавливают поведение системы, которую нельзя остановить и разобрать. С данными история та же. Конвейер отработал без единой ошибки, все задачи зелёные, а витрина при этом наполнилась на четверть от обычного объёма, и узнает об этом первым аналитик, у которого поехал дашборд.

 

Что такое наблюдаемость данных и чем она отличается от проверок

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

Второе отличие в охвате. Тест знает про одну таблицу, наблюдаемость знает про граф происхождения (data lineage) и поэтому умеет считать не факт поломки, а её масштаб. Ответ «сломалась витрина заказов» и ответ «сломалась витрина заказов, вниз по потоку затронуто пять потребителей, включая недельный отчёт для руководства» это два разных ответа с разной ценой промедления.

 

Пять столпов наблюдаемости данных

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

  • Свежесть. Как давно обновлялись данные. Метрика это разница между текущим временем и максимальной отметкой времени в таблице.
  • Объём. Сколько строк пришло. Метрика это счётчик строк за период, обычно за сутки.
  • Схема. Состав и типы колонок. Изменение типа в источнике ломает всё, что стоит ниже по потоку, причём молча.
  • Распределение. Как выглядят значения внутри колонок. Сюда идут доля пропусков, доля значений вне допустимого словаря, среднее и квантили числовых полей.
  • Происхождение. Кто читает датасет и кто его наполняет. Единственный столп, который описывает не таблицу, а связи между таблицами.

Первые четыре столпа отвечают на вопрос, что именно сломалось, пятый отвечает на вопрос, кому от этого станет плохо.

Пять столпов наблюдаемости данных и метрики, которые собирает каждый

 

Архитектура решения

Практически любая платформа наблюдаемости, от коммерческой Monte Carlo до открытых Soda Core и Elementary, разложима на четыре слоя. Понимание этих слоёв важнее знания конкретного продукта, потому что продукты меняются, а слои остаются.

 

Сборщики метаданных

Компонент, который ходит в источник и снимает метрики. Дешёвый сборщик работает по системным каталогам и статистике СУБД, не трогая сами строки. Дорогой запускает агрегирующие запросы по таблице, платит за это временем и нагрузкой на источник, зато видит распределение значений. Скан пяти правил по таблице на 15 483 строки в демо ниже занял 3,24 секунды, но на витрине в сотни миллионов строк то же самое считается уже минутами.

 

Хранилище истории

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

 

Правила и детекторы

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

 

Алерты и интерфейс

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

Путь метаданных от источника к алерту через хранилище истории и детектор отклонений

Сквозной формат для пятого столпа даёт открытый стандарт OpenLineage, описывающий события о запусках задач и датасетах. Он поддержан Apache Airflow, Apache Spark и dbt, популярным инструментом трансформации данных в хранилище на SQL, а собирает эти события референсный сервер Marquez. Стандарт снимает главную боль слоя происхождения, а именно необходимость писать отдельный парсер под каждый движок.

Архитектура Данных

Код курса
ARMG
Ближайшая дата курса
28 сентября, 2026
Продолжительность
24 ак.часов
Стоимость обучения
76 800

 

Базовая линия и детекция отклонения

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

Рабочий вариант это устойчивые оценки на медиане и медианном абсолютном отклонении (median absolute deviation, MAD). Медиана не сдвигается от одного выброса, а MAD, помноженный на константу 0,6745, переводится в сигмы нормального закона, и дальше отклонение считается привычной z-оценкой. Порог в демо ниже взят равным 3,5 сигмы, и это не универсальная константа, а величина, которую подбирают под конкретную витрину по числу ложных тревог.

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

 

Наблюдаемость, качество данных и мониторинг инфраструктуры

Три понятия постоянно путают, хотя отвечают они на разные вопросы и живут в разных слоях платформы.

Критерий Мониторинг инфраструктуры Качество данных Наблюдаемость данных
Объект наблюдения Процессы, узлы, задачи оркестратора Содержимое таблицы Метаданные датасета и конвейера во времени
Критерий тревоги Отказ или превышение лимита ресурса Нарушение заданного правила Отклонение от собственной истории
Кто формулирует норму Администратор Инженер данных Сама история метрики
Известные и неизвестные риски Известные Известные Оба
Оценка последствий Нет Нет Есть, через граф происхождения

Из таблицы видно, что наблюдаемость не отменяет два других механизма, а надстраивается над ними. Зелёная задача в Apache Airflow и пройденный тест качества это необходимые условия, но далеко не достаточные. Подробный обзор инструментов рынка с примерами внедрения разобран в статье Что такое наблюдаемость данных и как её реализовать.

 

Ограничения подхода

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

  • Шум алертов. Детектор без учёта сезонности и без порога на значимость превращается в источник ежедневных ложных срабатываний, после чего команда перестаёт их читать.
  • Стоимость сканов. Метрики распределения требуют полного прохода по таблице. На облачном хранилище с поминутной тарификацией регулярный скан широкой витрины становится заметной строкой счёта.
  • Слепые зоны без происхождения. Если граф не собран или собран частично, оценка масштаба недоступна, и платформа вырождается в набор разрозненных проверок.
  • Холодный старт. Пока истории нет, детектор бесполезен. Первые недели работают только жёсткие правила, а базовой линии нужно накопить хотя бы несколько десятков точек.
  • Риск цепочки поставок. Инструменты наблюдаемости получают доступ ко всем витринам сразу и потому сами становятся привлекательной мишенью. В апреле 2026 года пакет elementary-data был скомпрометирован в PyPI и GHCR через подделанный релиз, так что версии зависимостей здесь стоит фиксировать жёстко.

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

 

Когда внедрять, а когда хватит обычных тестов

Полноценная платформа оправдана, когда витрин десятки, у них разные владельцы и внешние потребители вроде отчётности или онлайн-моделей. Признак готовности простой, а именно наличие инцидентов, о которых команда данных узнала от бизнеса, а не от своих инструментов. Если конвейеров пять, все они в одних руках и потребитель один, набор тестов в dbt или в библиотеке проверок Great Expectations закроет ту же потребность дешевле. Управленческая рамка, в которую наблюдаемость встраивается вместе с Data Governance, разбирается на курсе Аналитика больших данных для руководителей.

Практическая архитектура данных

Код курса
PRAR
Ближайшая дата курса
14 сентября, 2026
Продолжительность
24 ак.часов
Стоимость обучения
76 800

 

Практика, снимок метрик и детекция аномалии

По традиции весь код используемый в статье выкладываем на наш GitHub репозиторий

НАБЛЮДАЕМОСТЬ ДАННЫХ (DATA OBSERVABILITY) from airflow import DAG from airflow.operators.bash import BashOperator from datetime import datetime with DAG( dag_id="spark_submit_demo", start_date=datetime(2025, 1, 1), schedule="@daily", catchup=False ) as dag: run = BashOperator( task_id="run_job", bash_command="spark-submit app.py" ) GitHub code example НАБЛЮДАЕМОСТЬ ДАННЫХ (DATA OBSERVABILITY)

Демо развёрнуто на PostgreSQL 18.4 с таблицей заказов и тридцатью днями ровной истории. Правила описаны на языке SodaCL и покрывают четыре столпа из пяти, в файле checks.yml.

# soda-core 3.5.6, синтаксис SodaCL, прогнано на стенде 2026-08-25
# Четыре из пяти столпов наблюдаемости, выраженные декларативными правилами.
checks for orders:
  # Свежесть: последняя запись не старше часа
  - freshness(created_at) < 1h

  # Объём: жёсткий порог, ниже которого витрина считается пустой
  - row_count > 100

  # Схема: обязательные колонки и тип суммы
  - schema:
      name: состав колонок витрины заказов
      fail:
        when required column missing: [id, customer_id, amount, status, created_at]
        when wrong column type:
          amount: numeric

  # Распределение: пропуски и словарь допустимых статусов
  - missing_count(customer_id) = 0
  - invalid_count(status) = 0:
      valid values: [paid, refunded, cancelled]

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

INFO   |       row_count > 100 [PASSED]
INFO   |       freshness(created_at) < 1h [FAILED]
INFO   |         max_column_timestamp_utc: 2026-08-25 07:09:39.149788+00:00
INFO   |         now_timestamp_utc: 2026-08-25 12:34:40.457351+00:00
INFO   |         freshness: 5:25:01.307563
код возврата скана: 2
метрики в историю: {'row_count_today': 120.0, 'staleness_minutes': 325.0, 'column_count': 5.0, 'avg_amount': 119.54416666666667}

Объём дня упал до 120 строк против 430 в первом скане, а по тридцатидневной истории обычный день это 500 строк, то есть витрина недобрала три четверти нормы. Правило row_count > 100 при этом отчиталось об успехе. Формально оно право, ста строк там действительно больше. Ровно так и выглядит слепая зона жёстких порогов, и именно её закрывает детектор базовой линии из файла demo_baseline.py.

# PostgreSQL 18.4, psycopg 3.3.4, прогнано на стенде 2026-08-25
# Детекция аномалии по базовой линии. Здесь нет ни одного жёсткого порога:
# нормой считается то, что витрина сама показывала последние тридцать дней.

import psycopg
from statistics import median

DSN = "postgresql:///observability_demo"
Z_THRESHOLD = 3.5          # общепринятый порог для устойчивой z-оценки
MAD_TO_SIGMA = 0.6745      # перевод медианного отклонения в сигмы нормального закона

# Упрощённый граф происхождения: кто читает витрину заказов вниз по потоку.
# По нему считается не факт поломки, а её масштаб.
LINEAGE = {
    "orders": ["mart_daily_revenue", "dash_sales_overview",
               "ml_churn_features", "report_finance_monthly"],
    "mart_daily_revenue": ["dash_ceo_weekly"],
}


def daily_counts() -> list[tuple[str, int]]:
    """История дневных объёмов прямо из данных. В боевом решении её собирает
    сборщик метаданных, здесь достаточно группировки по дню."""
    with psycopg.connect(DSN) as conn:
        return conn.execute("""
            SELECT to_char(created_at::date, 'YYYY-MM-DD') AS day, count(*)
            FROM orders
            GROUP BY 1
            ORDER BY 1
        """).fetchall()


def robust_zscore(value: float, history: list[float]) -> float:
    """Устойчивая z-оценка на медиане и MAD. Обычные среднее и стандартное
    отклонение здесь не годятся: один выброс тянет базовую линию за собой
    и следующая такая же аномалия уже выглядит нормой."""
    base = median(history)
    mad = median([abs(x - base) for x in history])
    if mad == 0:
        return 0.0
    return (value - base) * MAD_TO_SIGMA / mad


def impact(dataset: str) -> list[str]:
    """Обход графа вниз по потоку: все потребители, до которых дойдёт проблема."""
    affected, queue = [], list(LINEAGE.get(dataset, []))
    while queue:
        node = queue.pop(0)
        if node not in affected:
            affected.append(node)
            queue.extend(LINEAGE.get(node, []))
    return affected


if __name__ == "__main__":
    rows = daily_counts()
    history = [float(c) for _, c in rows[:-1]]   # прошлые дни это база
    today_day, today_count = rows[-1]

    base = median(history)
    z = robust_zscore(float(today_count), history)

    print(f"дней в истории: {len(history)}")
    print(f"базовая линия (медиана дневного объёма): {base:.0f} строк")
    print(f"текущий день {today_day}: {today_count} строк")
    print(f"отклонение от базовой линии: {(today_count / base - 1) * 100:.1f}%")
    print(f"устойчивая z-оценка: {z:.1f} при пороге {Z_THRESHOLD}")

    # Тот же день глазами жёсткого правила из checks.yml
    print(f"\nправило row_count > 100 говорит: "
          f"{'провал' if today_count <= 100 else 'всё в порядке'}")

    if abs(z) > Z_THRESHOLD:
        consumers = impact("orders")
        print(f"детектор базовой линии говорит: АНОМАЛИЯ")
        print(f"затронуто потребителей вниз по потоку: {len(consumers)}")
        print("список:", ", ".join(consumers))
    else:
        print("детектор базовой линии говорит: в пределах нормы")

На том же самом дне детектор даёт противоположный вердикт.

дней в истории: 30
базовая линия (медиана дневного объёма): 500 строк
текущий день 2026-08-25: 121 строк
отклонение от базовой линии: -75.8%
устойчивая z-оценка: -25.6 при пороге 3.5

правило row_count > 100 говорит: всё в порядке
детектор базовой линии говорит: АНОМАЛИЯ
затронуто потребителей вниз по потоку: 5
список: mart_daily_revenue, dash_sales_overview, ml_churn_features, report_finance_monthly, dash_ceo_weekly

Устойчивая z-оценка минус 25,6 при пороге 3,5 это не пограничный случай, а разрыв на порядок. Обход графа происхождения добавляет к вердикту то, чего нет ни в одном правиле, а именно список из пяти конкретных потребителей, включая недельный отчёт для руководства.

Третий скан демонстрирует столп схемы. В источнике появляется колонка amount текстового типа вместо числового, и правило схемы падает с явной причиной fail_column_type_mismatch[amount] expected(numeric) actual(text), а сборщик метрик на следующем прогоне ломается на функции усреднения. Так одна незамеченная смена типа выносит и витрину, и саму наблюдаемость.

Из практических граблей стоит запомнить одну. Soda Core версии 3.5.6 не закрывает подключение к источнику после скана, соединение остаётся в состоянии idle in transaction, и следующая операция изменения таблицы встаёт на блокировке намертво. Штатный метод close_all_connections в этой версии не работает, потому что обходит словарь, который никогда не наполняется, и закрывать подключение приходится вручную через приватный менеджер источников.

 

Заключение

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

 

Референсные ссылки