Резюме Flashcards

(43 cards)

1
Q

Почему именно gpfdist / external tables, как вышли на 350 MB/s и что стало новым bottleneck? — YuMoney

A

Мы взяли gpfdist, потому что это самый быстрый и простой способ массово заливать файлы в Greenplum: каждый из 42 сегментов напрямую «сосёт» свой поток HTTP, минуя master. На двух ETL-серверах крутится 16 gpfdist-процессов, а таблица разбивается на 32 файла. 40-гигабитная сеть полностью забивается — спид-тест показал ~350 MB/s, поэтому 1,4 ТБ истории ушли за час небольшим.
После этого улучшения нехватка уже не в CPU и не в сети, а в дисковых IOPS сегмент-узлов — SSD кипят, CPU скучает. Чтобы ускоряться дальше, надо ставить NVMe-диски или масштабировать кластeр, а не крутить ещё gpfdist-процессов.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
2
Q

Как планировали cut-over; сколько длилось финальное переключение? — YuMoney

A

Мы держали «двойную запись» (dual-write) почти три недели для всех таблиц: все 200 ключевых таблиц одновременно попадали и в ClickHouse, и в новый Greenplum. Инкременты летели через Debezium → Kafka → UPSERT-джобу, так что отставания почти не было.

Что именно переключали. У нас не одна таблица, а целый пул отчётных витрин. Когда каждая из них неделю подряд проходила DQ-тесты без расхождений, мы включали dual-write и шли к следующей.

Финальный шаг. В ночь на 24 февраля 2024 в 02:17 я сменил целевой пул у Application Load Balancer: вместо ClickHouse-backend указал Greenplum-backend.

Сколько длилась «темнота». Последний «догоняющий» пакет на 11 742 строки залился за 24 секунды; пока перекатывался ALB, отчёты были недоступны ~40 секунд. SLA 99 % мы не нарушили, бизнес даже не заметил.

Что было бы, если что-то пошло не так. Возврат DNS-записи + выключение dual-write — одна команда, меньше минуты на откат.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
3
Q

Какие проверки целостности автоматизированы и где исполнялись? — YuMoney

A

После каждой выгрузки в STG автоматически срабатывает проверка в GitLab CI — джоба dq_smoke. Она гоняется на каждый merge request и проверяет:

количество строк (row_count),

контрольную сумму CRC32 каждой партиции,

минимум и максимум по шести ключевым числовым колонкам.

Если отклонение хотя бы одной метрики превышает 0,01 %, MR помечается как «красный», а результат проверки пишется в JUnit-отчёт — это позволяет сразу увидеть проблему прямо в CI-интерфейсе.

Уже в проде, по расписанию, в Airflow работает таска dq_post_cut. Она делает всё то же самое, что и dq_smoke, но дополнительно считает sha256_agg на случайной выборке 1 % строк — это помогает ловить случайные ошибки, не видимые на агрегациях.

Если где-то есть рассинхрон или нарушение, срабатывает метрика dq_mismatch_total в Prometheus, по которой настроен алерт в Slack.

Этот шаблон проверок — с hash’ами, row count’ами и метриками — я reuse’ил и в других местах: в банке это были AWR-хэши, в YuMoney — CRC + hash. Главное — придерживаться одинакового формата отчётов, чтобы Grafana могла строить единую тепловую карту и визуально подсвечивать зоны проблем.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
4
Q

Что делали с ClickHouse-типами (LowCardinality, DateTime64…) при миграции? — YuMoney

A

Сгенерировал маппинг в ноутбуке ch2gp_types.ipynb: LowCardinality(String) → text + ENCODING compresstype=lz4, DateTime64(3) → timestamp(3) with time zone; Enum в CH превратили в SMALLINT + lookup-таблицу. Скрипт-генератор Avro-схемы (для Debezium) автоматически применял те же правила — так CDC и bulk-load оставались совместимыми.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
5
Q

Как измеряли реальное улучшение time-to-DB и какие метрики сохранили? — YuMoney

A

Говорим цифрами, а не ощущениями.

Метрика загрузки — gp_load_seconds: сколько реально длится bulk-insert через gpfdist.

Метрика для бизнеса — bi_dashboard_latency_seconds: p95 времени ответа CFO-дашборда.

Что увидели: до миграции p95 = 155 с; через неделю после cut-over — 68 с (-56 %).

Чтобы не откатиться назад график закрепили («pin») на борде SRE; если p95 снова ползёт вверх, PagerDuty звонит раньше, чем CFO заметит.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
6
Q

Где в оркестраторе живут проверки pandera? — YuMoney

A

Во всех landing-пайплайнах Airflow сначала срабатывает FileSensor, как только приходит новый файл. Следом запускается отдельная Python-таска validate_raw (это функция с декоратором @task, внутри группы validate). В ней pandera проверяет, что в загруженном датафрейме колонки и типы корректны. Для бэк-филлов вызывают тот же модуль из скрипта, чтобы не писать проверку заново.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
7
Q

Как синхронизируете pandera-контракты при изменениях схемы? — YuMoney

A

Ночной Spark-джоб schema_diff проверяет, не изменилась ли схема у датасетов в Datalake (чаще всего Parquet-файлы от landing- и CDC-пайплайнов).

Снимаем «фактическую» схему свежего датасета через spark.read.parquet().schema.

Конвертируем эту Spark-схему в pandera.DataFrameSchema.

Сравниваем её с YAML-контрактом этого датасета из Git (этот YAML — общий источник правды, из него downstream-пайплайны строят валидации и модели).

Дифф классифицируем:

    Safe — добавили nullable-колонку, увеличили длину строки, добавили колонку в конец: скрипт сам создаёт MR с обновлённым YAML, CI зелёный.

    Breaking — удалили колонку, переименовали, поменяли тип: CI падает, нужен ручной апрув архитектора.

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

Покрываем и landing (где схемы приходят через Spark), и CDC (где Avro-схемы берём из Schema Registry). В downstream-слоях (Airflow, dbt) никто не пишет валидацию руками — всё читается из YAML.
Что важно

DAG-ов мы не трогаем — они всегда подтягивают YAML на старте. Обновляется именно контракт, не код.

Safe/Breaking определяется строго: даже rename — это breaking (иначе downstream не поймёт, что колонку переименовали).

Если producer случайно откатил код — на следующее утро schema_diff это тоже заметит и предложит MR в обратную сторону.

Если partition ещё не долетел, возможны false breaking-сигналы — решаем через выборку sample-файлов или кэш Parquet footer.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
8
Q

Какие правила валидации чаще всего ловили ошибки и как они влияли на SLA 99,3 %? — YuMoney

A

Топ-3 триггера: (1) purchase_dt вне диапазона 2020-01-01…today() — поймали 173 строки 31-11-2023; (2) amount < 0; (3) NULL в payment_id (PK). До внедрения было в среднем 5-6 SLA-miss/месяц; после — 1-2 (-60 %), что дало итоговые 99,3 % SLA за Q4-2023.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
9
Q

Чем мониторите сам SLA? — YuMoney

A

В коде имеется Airflow SLA_miss_callback → StatsD. Дальше Prometheus собирает sla_miss_total и dag_run_latency_seconds; Grafana дашборд «DAG Health» строит p95 и rate( ). Alert «rate > 0,001 / 5 мин» шлётся в Slack #airflow-alerts и поднимает on-call.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
10
Q

Инцидент, когда pandera спасла отчёт: что случилось и как вы починили? — YuMoney

A

12 октября 2023 в 04:12 (MSK) упал DAG landing_cashback_2023: на этапе валидации Pandera не обнаружила колонку currency_cd. Причиной оказался breaking change: внутренний cashback-сервис, выгружающий nightly-файл в NFS, внёс схему без этого поля.

Поскольку пайплайн напрямую писал данные в Greenplum, а currency_cd участвовала в расчётах сумм, нельзя было допустить, чтобы в витрины ушли строки с NULL вместо валюты.

Что сделал дежурный:

Восстановил поле вручную — добавил колонку currency_cd = 'RUB' в raw-файл (значение было фиксированное для всего датасета);

Перезалил исправленный файл в папку, откуда его забирает DAG;

Инициировал backfill DAG-а на конкретную дату (одна партиция), чтобы перегнать только проблемный кусок;

Проверил, что данные успешно прогрузились в Greenplum, и NULL не утекли в BI-витрины.

Результат: CFO-отчёт успел пересчитаться к 07:30, SLA не нарушен. Pandera сработала как предохранитель: остановила пайплайн до появления ошибок в проде, а ручное восстановление поля позволило избежать простоев.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
11
Q

Как выбирали распределяющий ключ и проверяли до выката? — YuMoney

A

Задача: убедиться, что данные в Greenplum ложатся ровно, без «жирных» сегментов и потери JOIN-производительности.

Сняли факты о данных

    На DEV-кластер выгрузили 1 % реальных строк и с помощью gp_toolkit.gp_stats_missing() собрали кардинальность по всем кандидат-колонкам.

    Дополнительно прогнали скрипт gp_skew_check.sql (считает % строк и % байт на каждый сегмент).

Отфильтровали кандидатов

    Правило № 1: ключ должен участвовать в 99 % основных JOIN-ов (подсмотрели в DataHub lineage).

    Правило № 2: кардинальность ≥ 100 × число сегментов, чтобы избежать дублей на одном узле.

Прогоны «на скорость»

    Создали три копии таблицы transactions_sample с тремя разными DISTRIBUTED BY (...).

    Прогнали типовое BI-джойны EXPLAIN ANALYZE × 10.

    Смотрели qt_total_time и skew_rows — победил вариант DISTRIBUTED BY (account_id) (скошенность < 6 %).

Генеральная репетиция

    На STG загрузили 100 ГБ той же таблицы, снова проверили skew — не выше 8 %.

    Только после этого посадили ключ в DDL-миграцию Flyway V20240215\_\_transactions.sql.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
12
Q

Какие партиции (range/list) и как это влияло на pruning в палмне при разрботке? — YuMoney

A

На базовом слое исторических данных мы используем секционирование по диапазону: PARTITION BY RANGE (txn_month) — с шагом в месяц от января 2022 до декабря 2024. Это нужно потому, что типовые запросы (например, от финконтроля или аудиторов) всегда идут по периоду. Такой подход позволяет физически читать только нужные месяцы, а не весь объём — вместо 24 миллиардов строк читаются ровно те, что нужны.

Для «горячего» квартала — октябрь, ноябрь, декабрь 2024 — добавили поддерево: внутри диапазона txn_month = 2024-10 … 12 сделали дополнительное секционирование по регионам (sub-partition by LIST(region_cd)). Причина — в Новый год нагрузка возрастает вдвое, а BI-дашборды чаще строятся по регионам.

В реальности это дало сильный прирост: EXPLAIN по живым запросам показывает pruning 92–95 % блоков, а p95-латентность запроса упала с 2,4 секунды до 0,9.

Перед выкладкой мы это проверяли руками: брали пять настоящих BI-запросов и гоняли EXPLAIN (ANALYZE, VERBOSE), чтобы посмотреть, сколько секций реально читается. Порог в 90 % pruning стал для нас зелёным флажком: если его не добивались — секционирование дорабатывали.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
13
Q

Как без блокировок добавляете партиции и собираете статистику? — YuMoney

A

Добавление новой секции

На STG создаём пустую таблицу-«скорлупу» p202508 LIKE parent INCLUDING DEFAULTS.

ALTER TABLE parent ATTACH PARTITION p202508 FOR VALUES IN ('2025-08') — операция чисто в системных каталогах, доли секунды, только ACCESS SHARE-лок на родителя.

Если нужно пересыпать данные (реже), используем EXCHANGE PARTITION … WITHOUT VALIDATION, так же без длинного ACCESS EXCLUSIVE.

Статистика

Greenplum 7 умеет incremental analyze: ANALYZE ROOTPARTITION parent PARTITION p202508; — считает только свежую часть, не трогая 2-ТБ историю.

Job analyze_nightly в Airflow собирает stats на все новые секции перед 06:00, так что утренние отчёты уже опираются на актуальный план.

Результат

Окно «maintenance» для месячной секции — < 1 мин, без блокировок отчётов.

BI-запросы сразу бьют в актуальную статистику, планы не «прыгают» на следующий день.
How well did you know this?
1
Not at all
2
3
4
5
Perfectly
14
Q

Resource queues / workload management при разработке гринпалма? — YuMoney

A

В Greenplum мы использовали встроенный механизм управления ресурсами — resource queue. Мы завели две очереди: etl_q — под тяжёлые ночные загрузки (до 4 одновременных запросов, 70 % оперативной памяти сегмента), и bi_q — под дневную BI-аналитику (до 32 лёгких запросов, 25 % памяти). Эти очереди жёстко привязаны к ролям пользователей, и каждый запрос от Airflow-worker-а поступает именно от нужной роли.

Дополнительно мы включили параметр gp_resqueue_priority, благодаря которому Greenplum может временно понижать приоритет bulk-запросов из etl_q, если в кластер параллельно поступают BI-запросы из bi_q. Это гарантирует, что даже в пике ночью важные отчёты (например, CFO) не будут ждать конца загрузки.

Чтобы исключить «просачивание» тяжёлых DAG-ов за рамки очередей, мы синхронизировали лимиты и на уровне Kubernetes: каждому Airflow-worker-у через LimitRange выставлены ресурсы, строго соответствующие очереди Greenplum, под которую он работает. Таким образом, и в базе, и на уровне pod-а действует один и тот же предел — и никаких накладок.

Наконец, за загрузкой очередей мы следили через Prometheus: метрика pg_resq_active_total показывает, сколько запросов в каждой очереди активно. Если etl_q стабильно упирается в потолок, это явный сигнал — пора масштабировать кластер или пересматривать режим загрузки.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
15
Q

Как замеряли эффективность схемы после запуска проекта клика в гп? — YuMoney

A

После выката завели два дэшборда:

“Query Time” — p95 и p99 для пяти «тяжёлых» запросов (те же, что крутили в EXPLAIN до релиза).

“Skew & Hit Ratio” — gp_stat_database + pg_statio_all_tables: доля блоков, прочитанных не со «своего» сегмента, и средний skew по 15-минутному окну.

Пороговые алерты: если p95 > 1 с или skew > 15 %, PagerDuty дёргает дежурного. За первый месяц p95 держался < 900 мс, skew прыгал до 12 % только на конец квартала — значит выбор распределяющего ключа и под-лист-партиций был удачный.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
16
Q

Почему Patroni, а не Stolon/Crunchy? — YuMoney

A

Мы выбрали Patroni по ряду прагматичных причин, протестировав в DEV-среде и сравнив с альтернативами — Stolon и Crunchy Postgres Operator.

Во-первых, по времени failover Patroni оказался самым быстрым: 6–8 секунд против 12–15 у Stolon и 10–12 у Crunchy. Это критично для SLA.

Во-вторых, Patroni не требовал поднимать ничего нового в инфраструктуре. Он использует уже развёрнутый у нас Etcd — то самое key-value-хранилище, которое мы и так держим для Vault и Flink. Stolon требовал бы тащить в кластер либо Consul, либо Etcd с нуля. Crunchy вообще работает через свой Custom Resource Definition (CRD) и требует установки отдельного контроллера и операторского чарта — ещё одной точки отказа.

Третье — наблюдаемость. У Patroni из коробки есть REST API, метрики health и история — и всё это легко читается через Prometheus-exporter. У Stolon API сильно примитивнее, у Crunchy — нужный bundle приходится докручивать вручную.

Наконец, сам стек. Patroni — это Python + YAML, что знакомо нашим DevOps. Stolon — Go с кастомной логикой конфигурации. Crunchy — огромный Helm-чарт и довольно тяжёлая модель, не подходящая для лёгкой кастомизации.

В итоге: Patroni дал нам быстрый failover (<10 с), не потребовал ни одного нового сервиса в кластере и хорошо вписался в уже существующую инфраструктуру — поэтому и выбрали его.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
17
Q

Bootstrap кластера: secrets, WAL, init SQL? — YuMoney

A

Всё параметризовано в values.yaml чарта pg-single: * Kubernetes-secret c superuser_password & replicator_password создаётся Helm-template-ом;. * WAL-архив указываем wal_gcs_bucket = «yumoney-pg-wal» — Patroni сам пушит через wal-e; * init-SQL — список файлов в initScripts:; Helm запускает post-install hook, который монтирует их в /docker-entrypoint-initdb.d.

How well did you know this?
1
Not at all
2
3
4
5
Perfectly
18
Q

Что значит «кластер под ключ»? — YuMoney

A

Когда мы говорим «PostgreSQL-кластер под ключ», это буквально один Helm-релиз helm install svc-payments pg-single и через ~15 минут команда получает:

Patroni-кластер (мастер + реплика, health-API сразу готов).

pgBouncer c настроенным пулом.

Prometheus-экспортёр и alert-rule «checkpoint > 2 с».

Готовый ServiceMonitor — метрики тут же появляются в Grafana.

Никаких ручных действий DBA; единственное, что девы заполняют в values.yaml, — имя сервиса и размер PVC.

19
Q

Обновления без downtime в хелме релизовали? — YuMoney

A

Minor-upgrade Postgres: Patroni делает switchover. Сначала патчится реплика, она становится мастером, старая нода перекатывается и возвращается репликой. Клиенты сидят за pgBouncer и теряют лишь секундную паузу на реконнект.

Helm-чарт приложения: используем strategy RollingUpdate + maxUnavailable=0. Kubernetes выводит pod из Traffic, ждёт, пока pgBouncer отдаст последние соединения, только потом сносит. Пользовательские транзакции не обрываются.

Так мы перешли с Postgres 14.4 → 14.8 и с Airflow 2.5 → 2.6, не нарушив SLA 99 %.

20
Q

Параметры pgBouncer и влияние на латентность? — YuMoney

A

pool_mode: transaction — после коммита соединение сразу возвращается в пул; это экономит ~25 мс на каждый «короткий» BI-запрос.

default_pool_size: 40, reserve_pool_size: 10 — на сервис приходится ≤ 50 активных серверных коннектов, Postgres не душится на max_connections.

server_lifetime: 900 — раз в 15 минут соединение перераз-открывается, чтобы не разрастались temp tables.

query_wait_timeout: 5 s — если пул забит дольше пяти секунд, клиент сразу получает ошибку, а не зависший дэшборд.

Нагрузочный тест Locust показал: cold-latency с 28 мс упала до 6 мс, а пиковый TPS вырос ~×1.7, потому что Postgres тратит время на исполнение, а не на hand-shake.

21
Q

Зачем Flume перед Kafka? — YuMoney

A

Flume — это «привратник» на самом сервере платёжного шлюза. Он:

умеет хвостить syslog-файл строчки-за-строчкой и буферить их, если сеть падает;

прямо на лету маскирует PAN-ы («5100 **** 1234») обычным RegexInterceptor — никакого Java-кода;

добавляет служебные headers (service=fraud, env=prod), по которым Kafka потом раскидывает данные по партициям.

Мы тем самым:

снимаем нагрузку с приложения — ему не нужно знать про Kafka-протокол;

выносим PCI DSS-маску как первый шаг конвейера, чтобы «чистые» номера никогда не покидали доверенный узел;

получаем надёжную «канал-файл» модель Flume: при сети-0 пакеты лежат на диске и догоняют позже.
22
Q

Spark Streaming: micro-batch или Structured, как подобрали параметры? — YuMoney

A

Взяли Structured Streaming (Spark 3.4) в режиме micro-batch; непрерывный режим отсеяли сразу — нужны оконные функции, а они там недоступны.

trigger = 300 s — каждые пять минут пишем кусок, чтобы вписаться в KPI «тревога ≤ 10 мин».

window = 1 day / slide = 5 min, watermark = 10 min — поздняя транзакция может отстать, но не больше десяти минут.

spark.sql.shuffle.partitions = 600 и динамическая аллокация: стартуем с 6 executors, под наплывом растём до 60.

Подбирали цифры на тестовом кластере: гнали реальный трафик сутки, смотрели lag в Kafka и загрузку CPU. Когда lag стабильно держался < 80 k msg, а кластер ночью сворачивался до 5 executors, параметры зафиксировали.

23
Q

Exactly-once до HDFS при retry Spark + дедуп в модели? — YuMoney

A

Чекпоинт (checkpointLocation=/user/hdfs/fraud_cp) сохраняет offset’ы Kafka — при падении поток продолжает с точного места.

Пишем в Partitioned Parquet и полагаемся на «rename atomic» — Spark сперва пишет во временную папку, потом переименовывает. Если драйвер упал до rename, данных «как бы нет» и повторная запись не даёт дублей.

Перед записью делаем dropDuplicates([‘txn_id’,’window’]), а при заливке в Greenplum используем MERGE … ON txn_id — так дупликаты не проходят даже если Spark перезапустили трижды.

24
Q

Как считали +18 % прироста на проекте спарка? — YuMoney

A

Две метрики в Prometheus:

fraud_flag_total — сколько операций поток пометил подозрительными.

fraud_confirmed_total — сколько из них служба ИБ действительно признала мошенничеством.

Мы сравнили отношение
fp_rate = 1 – (fraud_confirmed_total / fraud_flag_total)
на 30-дневном окне до включения Bloom-filter-правил и на 30-дневном окне после. Разница в среднем –18 %. Скрипт лежит в Jupyter-ноуте fp_rate_eval.ipynb, результаты автоматически сохраняются в Confluence-страницу релиза.

25
Какие метрики в Grafana и какие алерты реально спасли проект в спрака? — YuMoney
kafka_consumergroup_lag — если lag > 200 000 сообщений 10 минут подряд, Slack-алерт. Остановили пару «зализавшихся» потоков до того, как BI-витрина опустела. fraud_e2e_seconds p95 — должно быть ≤ 600 с; рост ловили, когда Flume на одном из узлов упёрся в диск. spark_executor_failed_total — > 3 failures за пять минут сигналят, что память кончилась или драйвер «захлебнулся». namenode_disk_used_percent — 90 % порог; однажды спасло за сутки до переполнения, переключили архивацию логов в S3-“cold”. checkpoint_age_seconds — если последний checkpoint старше 2 триггеров, значит поток не успевает; алерт позволил вовремя поднять maxExecutors. Благодаря этим пяти правилам MTTR по P1-инцидентам держится 20–25 минут даже в пиковые распродажи — дежурный видит корень боли, а не просто «что-то красное».
26
Чем профилировали bottleneck и как ускорили >50 % про проекту кредит транзакшенс? — ББР Банк
Как нашли bottleneck и ускорили более чем на 50 % Инструменты. AWR + SQL Monitor → увидели, что 40 % времени съедает full-scan таблицы CASH_FLOW_RAW. DBMS_XPLAN.DISPLAY_CURSOR → заметили, что фильтр по дате применялся поздно, partition pruning не работал. Действия. Разбили таблицу на RANGE(txn_month) и вынесли агрегацию в MV_CASH_DAILY (REFRESH FAST EVERY 15 min). Добавили bitmap-index на status_cd, чтобы выборка «только cleared» не читала весь partition. Переписали часть логики окна в SUM(...) KEEP (DENSE_RANK LAST ...) — убрали корявый подзапрос. Результат. PL/SQL-процедура сработала за 18 с вместо 38 с (-52 %), нагрузка DB CPU в AWR упала на 5 п.п., Physical Reads — на 8 %.
27
Как проверяли, что цифры совпадают при миграции? — ББР Банк
Nightly-скрипт compare_row_hash.sql. Для каждого отчётного дня считает SHA256 агрегата в старой витрине и новой MV, пишет расхождение в таблицу BI_DIFF_LOG. Порог: ≥ 0,01 % расхождения — таска diff_alert в Airflow ставит DAG на failed, дежурный получает Slack-пинг. За два месяца миграции ни одна проверка не превысила порог; финальный CAB-отчёт приложил diff-лог как доказательство.
28
Какие SLA-алерты держат 45 с в пике? — ББР Банк
dashboard_open_seconds_p95 > 45 с 3 мин подряд → канал #ukhd-alerts (Grafana ↔ Slack). mv_refresh_seconds > 120 с → признак, что ночной REFRESH захлебнулся, реагируем до утреннего совещания. db_buffer_cache_hit_ratio < 92 % → сигнал, что MV не помещается в cache, пора пересчитать размер. oracle_waitclass_userio_pct > 40 %** + ora_temp_space_used** > 80 % → чаще всего виноват CFO-запрос со старым планом; DBA сразу делает ALTER TABLE ... MONITORING. Эти четыре правила за последний квартал ловили все три инцидента P0; средний MTTR остался 15–20 мин, даже когда квартальный отчёт ЦБ и CFO-дашборд крутились одновременно.
29
Почему именно partition exchange, а не CTAS/merge? — ББР Банк
Бизнес-контекст. Ночное “окно” 02:00 – 03:00: за час надо загнать 24 млн строк и не сдвинуть отчёт CFO. Тест-гонка на DEV показала: CTAS + TRUNCATE + RENAME ≈ 28 мин, полный дубль данных на диске; MERGE ≈ 17 мин, при пике держит row-lock и душит фронтовые запросы; EXCHANGE PARTITION WITHOUT VALIDATION 42 с, копирования нет, блокировка только на метаданные — в AWR user I/O waits упали на > 90 %. Регуляторная фишка: exchange даёт атомичность «всё-или-ничего», поэтому для ЦБ мы всегда показываем цельную дневную выборку.
30
Как подбирали секционирование и проверяли кардинальность? — ББР Банк
Выкачали txn_dt-гистограмму из DBA_TAB_COL_STATISTICS, построили плотность — Pareto-точка 2.6 млн txn/день. Правило: размер самого горячего partition ≤ два объёма buffer cache; при 32 GB это ~55 млн строк — месяц идеально ложится. Схема RANGE(txn_month) + SUBPARTITION BY HASH(customer_sk) для равномерного I/O. check_cardinality.ipynb сравнивает num_rows и avg_cluster_factor между staging и финальным фактом; дисбаланс > 15 % — красный маркер в Jabber.
31
Какие индексы оказались критичными и как считали ROI? — ББР Банк
Surrogate PK (credit_txn_sk) — вычистили составной ключ, JOIN-ы на числе экономят 19 % buffer gets. Bitmap-index на status_cd — отсекает «только просрочки», CPU –5-6 п.п. при 0.4 GB места. ROI считался так: разница DB CPU / добавленный объём индекса; порог установили 0.3 CPU-п.п./GB. Выжили только два индекса выше порога — остальное не окупалось.
32
Как автоматизировали сбор статистики, чтобы не ловить регрессию? — ББР Банк
Ночной DAG gather_stats_credit_txn стартует сразу после exchange: DBMS_STATS.GATHER_TABLE_STATS с incremental => TRUE, так считаем только новый partition < 90 с. Старая статистика бэкапится в STAT_CREDIT_TXN; если elapsed_time нового плана > 120 % старого — Airflow ставит DAG в failed и пуляет Slack-алерт. За год три предупреждения, дважды откатили статистику, P0-инцидентов не было.
33
После 65 с что стало новым лимитом? — ББР Банк
ничего. мой тим лид сказал что этого достаточно и уже все открывается хорошо
34
Как делали инвентаризацию Informatica-процессов? — ББР Банк
Внутри PowerCenter есть техническая БД; из VPN-сегмента я подключился к ней через sqlplus и выгрузил три ключевые таблицы — OPB_TASK, OPB_MAPPING, OPB_SCHED. Скрипт сохранил всё в export_inf_meta.csv, а дальше в Excel я руками добавил для каждой строки RTO/RPO, приоритет P1–P3 и флажок «ядовито/безопасно». Файл сразу зашили прямо в Confluence: любой менеджер мог отфильтровать «что падает первым, если пришёл квартальный freeze». К вечеру того же дня CIO увидел, что картинка сложилась — значит, можно двигаться дальше.
35
Как устроен генератор DAG-ов и что делали с «ядовитыми» трансформациями? — ББР Банк
Следующим шагом я написал catalog2yaml.py. Скрипт читает тот самый CSV и для каждой строчки формирует YAML под dag-factory: имя DAG, расписание, owners, retries, SLA, а главное — список нативных операторов. Стандартные источники превращались в OracleToStageOperator, lookup-очистки — в PLSQLProcedureOperator, загрузки в StageToDWHOperator. Когда встречались «ядовитые» штуки — нестандартный Java-трансформ, Normalizer, push-down lookup — скрипт вешал на запись тег needs_refactor. Такие DAG-и не выкатывались автоматически: мы вытаскивали XML-бандл, разбирали логику глазами и переносили её либо в чистый SQL, либо в короткий Python-таск с pandas, если без программного кода было никак. Самая «токсичная» цепочка была вокруг Java-трансформации, которая раскладывала XML отчёта в строчки. Мы просто переписали её на xmltable в Oracle — одна строка вместо трёхсот, и DAG сразу перестал требовать отдельного воркера в Celery.
36
Какие бит-в-бит проверки применяли? — ББР Банк
Когда YAML-файл порождал готовый DAG, Jenkins собирал ветку, разворачивал схему AF_LOAD (новый Airflow) рядом со старой INF_LOAD (Informatica). Ночной pytest прогонял три вида сравнений: select count(*) — банальная сверка количества. sum(amount) — ловит перекошенные суммы. MD5-хэш строки || всех колонок — гарантирует побайтовое совпадение. Если хотя бы один тест давал расхождение, Airflow-run помечался failed, а Slack-бот писал «bit-diff on ACCOUNT_BALANCE, check column currency_cd». Семь ночей подряд без отличий — значит, workflow готов к cut-over.
37
Что не переносили и почему? — ББР Банк
Два слоя мы оставили в PowerCenter, потому что стоимость миграции превышала выгоду. Первое — real-time MQ-пайплайны в EDQ: они гоняли события с латенси < 2 с и пользовались специфичным JMS-адаптером, который в Airflow пришлось бы переписывать на Kafka Streams — проект затянул бысь на месяцы, а экономия лицензии была копейки. Второе — однократные «архивные» загрузки из стародавнего EBS: скрипты в ряд попали в категорию «run-once, never touch» и умерли вместе с EBS-апгрейдом.
38
Как считали экономический эффект миграции? — ББР Банк
меньше плата за лицензию больше денег у банка
39
Какие источники метрик подключили на проеке информатки? — ББР Банк
Для старой системы мы уже имели statsd_exporter, поэтому просто расширили его: Airflow слал dag_duration_seconds, task_start_latency_seconds и sla_miss_total. Дополнительно я повесил небольшой Prometheus-экспортер, который раз в пять минут опрашивал таблицу OPB_SESSION_LOG у PowerCenter и клал в метрику inf_session_errors_total. Так на единой Grafana-борде мы одновременно видели, как себя чувствует «старый мир» и как растёт «новый». Alert «dag_duration_seconds p95 вырос > 20 %» спас нас дважды: один раз виновата была утечка памяти в пользовательском UDF, второй — DBA случайно сжали TEMP-табспейс. Итог: за полгода мы безопасно вывели из продакшена 275 workflow, лицензию PowerCenter закопали, а никакой отчёт бухгалтерии не пошёл в красную зону. Всё благодаря тому, что каждый шаг был зафиксирован в инвентаризации, автоматически превращён в код, проверен бит-в-бит и замониторен теми же метриками, которые любит SRE.
40
Как настроили alert-routing без флэка? — ББР Банк
Саму маршрутизацию алертов мы «очистили» почти сразу, как только поняли, что Jabber-чат тонет в сотнях сообщений «partition not attached». В Prometheus Alertmanager задали три принципа: (1) группируем по severity и dag_id, чтобы пять подряд ошибок одной витрины сливались в один инцидент; (2) ставим repeat_interval = 30m, иначе от флапа “отвалился TEMP-табспейс → Airflow ретрайт задачу → снова TEMP full” будем получать пинг каждые две минуты; (3) только алерты уровня P0/P1 идут в дежурный канал #ukhd-alerts, всё, что ниже, сверяется с графиком «ночная тишина» и пишется в Jira как технический долг. Такой роутинг свёл шум с ≈ 200 сообщений за ночь до 4-6.
41
20–25 мин востановление это — MTTR или RTO? — ББР Банк
Число 20–25 минут — это именно MTTR: берём метку времени первого “firing” от Alertmanager и время, когда соответствующий DAG снова закрылся статусом success; усредняем по всем инцидентам P0 за месяц. RTO как формальный контракт у нас стоял 45 минут, то есть запас примерно х2 — менеджеры были довольны, аудит не задавал вопросов.
42
Какие панели в дашборде удалили как лишние? — ББР Банк
Когда упаковывали Grafana-борд “DAG Health”, сознательно выкинули лишнее: отказались от панелей «CPU каждого Celery-воркера» и «load average по хостам». Они красиво двигались, но ничего не говорили о качестве данных. Оставили только p95 dag_duration_seconds, dag_run_latency_seconds, task_sla_miss_total и спарк-лайн оверлея по дням недели — этого хватает, чтобы одним взглядом увидеть «горит / не горит».
43
Кейс из практики: как уложились в 25 мин? — ББР Банк
Практический пример, как уложились в 25 минут: в марте 2023-го отчётность ЦБ, ночь четверга, DAG load_credit_txn падает на ORA-01652 (TEMP full). 00:03 — Alertmanager срабатывает, дежурный получает ссылку сразу на проблемный лог-ран. 00:06 — по шаблону post-mortem фиксируем диагноз: последний exchange-partition бросил 12 GB в TEMP, одновременно DBA запустил клонирование схемы — диски взвыли. 00:10 — вручную добавляем новый tempfile на +8 GB, подтверждаем alter database tempfile ..., online, перезапускаем провалившуюся таску в Airflow. 00:26 — DAG закрывается зеленым, Alertmanager гасит инцидент. Полный цикл «заметили → устранили → отчёт пошёл дальше» занял 23 минуты — в пределах среднего MTTR и вдвое быстрее RTO, именно за счёт того, что алерт пришёл один, с правильной меткой dag_id=load_credit_txn, без флуда и без лишнего копания в метриках CPU.