Модуль 6. Говернанс, безопасность, мульти-арендность и экономичная эксплуатация ClickHouse-витрин
Когда витрины «разбежались» по командам, главным становится не только скорость, но и управляемость: кто и что видит, где «правда», как быстро и безопасно меняем схемы, как разделяем клиентов, сколько это стоит, как восстановиться после аварии и как доказать аудиторам, что PII не утекёт.
Говернанс данных: «правда» как код
Каталог и паспорта метрик
- Для каждой метрики — паспорт (см. Модуль 1): формула, фильтры, календарь, валюта, владельцы, версия, DQ-тесты.
- Храните в Git (/metrics/*.yaml) и генерируйте документацию (md/html) в CI.
Data lineage
- Минимум: таблица lineage (source -> mart -> view -> dashboard).
- Практика: в PR, меняющем SQL VIEW, автоматически обновляйте lineage.json (скриптом, парся SQL).
Политика изменений
- Любая правка семантики → v2 (side-by-side, регресс-сравнение на окне, changelog).
- Срок жизни v1 после переключения: 30–60 дней.
Риски: «тихие» изменения; «две правды».
Митигация: «метрики как код», PR-процесс, автодоки, регресс-тесты v1→v2.
RBAC, RLS и маскирование PII
Роли и практичная модель доступа
Пример ролей:
- semantic_reader — только SELECT на db_marts.vw_*.
- marts_dev — разработка витрин (DDL/VIEW).
- marts_admin — полный админ.
CREATE ROLE semantic_reader, marts_dev, marts_admin; CREATE USER bi_ro IDENTIFIED BY '***'; GRANT semantic_reader TO bi_ro; GRANT SELECT ON db_marts.vw_* TO semantic_reader; GRANT SELECT, CREATE VIEW, ALTER, INSERT, OPTIMIZE ON db_marts.* TO marts_dev;
Риск: BI случайно получает доступ к «сырым» таблицам.
Митигация: гранты только на vw_*; прямые таблицы — без прав для BI.
Политики строк (RLS)
- Вешайте RLS на базовые таблицы витрин (MARTS), BI ходит во VIEW, которые наследуют политику.
CREATE ROW POLICY rp_region
ON db_marts.mart_sales_wide
FOR SELECT
USING region_id = currentSetting('region_id');
ALTER USER bi_ro SETTINGS region_id = 77;
Маскирование PII
- В VIEW — хеш/обрезка или NULL для PII.
CREATE OR REPLACE VIEW db_marts.vw_sales_masked AS SELECT day, shop_id, category_id, net_sales, qty, substring(sha256Hex(toString(customer_id)),1,12) AS customer_hash, NULL AS customer_email FROM db_marts.vw_retail_daily;
Риски: косвенная деанонимизация через редкие комбинации.
Митигации: suppression/бинирование по редким значениям (k-анонимность), запрет детальных выдач ниже заданного уровня.
Квоты и профили (WLM light)
Ограничьте «тяжёлые» запросы для BI-ролей:
CREATE SETTINGS PROFILE bi_limits
SET max_memory_usage = '8G',
max_threads = 8,
max_execution_time = 60;
ALTER USER bi_ro SETTINGS PROFILE bi_limits;
CREATE QUOTA bi_quota KEYED BY user
FOR INTERVAL 1 minute MAX queries 120, MAX errors 20;
Мульти-арендность (multi-tenant) в ClickHouse
Три паттерна разделения
-
Row-level (строки с tenant_id в общих таблицах).
Плюсы: проще эксплуатация, общие агрегаты.
Минусы: сложнее RLS/PII, риск «протечки фильтра». -
Schema-per-tenant (база/схема на тенанта).
Плюсы: физическое разделение данных и доступов.
Минусы: множатся объекты, управление схемами сложнее. -
Cluster-per-tenant (отдельный кластер/шард).
Плюсы: жёсткая изоляция, предсказуемость SLA.
Минусы: цена и операционные накладные, миграции сложнее.
Практический компромисс:
- SMB/много «лёгких» тенантов → row-level + RLS.
- Крупные «тяжёлые» тенанты → выделять схемы или шарды (Distributed + локальные таблицы).
Ключи, партиции, ORDER BY для multi-tenant
- Партиция по времени (месяц/день) + tenant_id в ORDER BY:
CREATE TABLE events_mt ( event_time DateTime, tenant_id UInt32, user_id UInt64, ... ) ENGINE = MergeTree PARTITION BY toYYYYMM(event_time) ORDER BY (tenant_id, event_time, user_id);
- Для Distributed — шардировать по tenant_id, если аналитика почти всегда в рамках одного тенанта.
Риски: «горячие» крупные тенанты на одном шарде; «плохое» ORDER BY под фильтры.
Митигации: балансировка шардинга (хеш + соль по времени), короткий префикс ORDER BY под типовой WHERE (tenant_id, event_time).
Изоляция ресурсов
- Профили/квоты на роль тенанта.
- Сегрегация ingestion (отдельные consumer-group’ы Kafka) и слотов фоновых задач.
PII, комплаенс и аудит
Классификация данных
- Таблица pii_registry(schema, table, column, classification, owner, retention_days).
- Разделы: P0 (критическое PII), P1 (умеренное), P2 (низкое).
Retention и TTL
- Правило: PII не хранить дольше, чем нужно.
- TTL для «сырых» событий и для «холодных» слоёв.\
ALTER TABLE mart_events_wide MODIFY TTL event_time + INTERVAL 365 DAY DELETE;
Журнал доступа и «след аудита»
- Ведите отдельную таблицу с записью «кто/когда/что читал» (на основе system.query_log), и дашборд «подозрительных» запросов (массовые выгрузки PII, обход RLS).
Экономика: вместимость, стоимость, hot/warm/cold
5.1 Storage tiering и политики хранения
- Политика дисков: hot (NVMe) → warm (SAS) → cold (S3/объектное).
- На таблицах — MOVE TO volume по TTL:
ALTER TABLE mart_sales_wide
MODIFY TTL day + INTERVAL 90 DAY TO VOLUME 'warm',
day + INTERVAL 365 DAY TO VOLUME 'cold';
Типы, кодеки, LowCardinality
- Деньги — Decimal, ID/домены — LowCardinality(String).
- Не злоупотребляйте Float (накапливает ошибки).
«Цена ingestion»
- Крупные батчи вставок → меньше parts, меньше merges.
- Kafka/MV: микробатчи (размер блока, частота флашей).
- Большие MV лучше вести по свежему окну, а не по всей истории.
Критерии «выносить в агрегаты»
- Отчёты считаются ≥ 1–2 раз/день и сканируют значимые объёмы.
- Метрики тяжёлые (uniq/quantile/%).
- Ожидаемый выигрыш по read_bytes ≥ 10×.
Риски: «ранняя оптимизация» — лишние таблицы и дубли логики.
Митигация: профилирование до/после, метрики read_bytes/query_duration из system.query_log.
Производительность (advanced): индексы, проекции, JOIN
Data-skipping индексы
- bloom_filter — для длинных IN/LIKE.
- set — маленькие домены.
ALTER TABLE mart_sales_wide ADD INDEX idx_sku_bloom sku_id TYPE bloom_filter GRANULARITY 4;
Риск: индекс без селективности — только место ест.
Митигация: замеры до/после.
Проекции (projections)
- Дают выигрыш на стабильных паттернах группировки/агрегации.
- Включайте после профилирования; это не замена хорошему ORDER BY.
JOIN-стратегии
- Малые справочники → Dictionary (dictGet*()), а не JOIN.
- SCD-атрибуты «на дату факта» → pre-join при записи.
- Избегайте «толстых» JOIN в BI; держите их в витринах/VIEW.
Много-региональность и DR
Гео-паттерны
- Active/Passive: основной регион + репликация/бэкап во вторичный.
- Active/Active: редкая необходимость для витрин (сложнее консистентность).
Бэкапы и восстановление
- Бэкап метаданных и «горячих» партиций ежедневно; полный — реже.
- Хранение бэкапов в другом failure-домене.
- Учебные восстановление раз в квартал (DR-день): поднять копию и прогнать smoke-тесты.
BACKUP TABLE db_marts.agg_sales_daily_state
TO Disk('backups','2025-08-01/agg_sales_daily_state');
RESTORE TABLE db_marts.agg_sales_daily_state
FROM Disk('backups','2025-08-01/agg_sales_daily_state');
Риски: «зелёные» бэкапы, но не восстанавливаются.
Митигация: регламент DR-тестов, чек-листы, автоматические smoke-тесты.
Инциденты и runbook’и
Свежесть просела
- Kafka lag / состояние MV.
- system.merges / system.parts → part explosion.
- Временно выключить «глубокий» ретро-пересчёт, OPTIMIZE проблемных партиций.
- Сообщить ETA бизнесу; записать пост-инцидент.
Расхождение с CORE
- Баланс-тесты на окне 7–14 дней.
- Новые статусы/валюты/календарь?
- Ретро-пересчёт окна; если «ломающее» — v2 и changelog.
BI «тяжелеет»
- Топ-запросы из system.query_log.
- Удалить FINAL/SELECT *; заменить uniq/quantile на чтение состояний.
- Перепроектировать ORDER BY; вынести агрегаты.
Кейс-шаблоны
SaaS B2B: 500+ тенантов, один кластер
- Выбор: row-level, tenant_id в ORDER BY, RLS по тенанту, профили/квоты на роль тенанта.
- Горячее окно 90 дней на NVMe, остальное — S3.
- Семантика: отдельные VIEW для «на дату операции» и «на дату отчёта».
- Риски: один «тяжёлый» тенант ограничивает других.
- Митигации: выделение shard для «тяжёлых», лимиты по профилям, расписание тяжёлых джобов ночью.
Маркетплейс: PII + промо-анализ
- PII маскирована, RLS по партнёрам.
- Агрегаты-состояния для per-tenant Top-K/перцентилей.
- Риски: каннибализация и спилл-овер в промо.
- Митигации: витрина agg_promo_effect, контрольные группы, halo-эффекты в окне ±N дней.
Финансы: соответствие «главной книге»
- Две вьюхи: на дату операции vs на дату отчёта.
- Nightly ретро 30 дней, сверка с GL, алерт при diff > 0.2%.
- Риски: чарджбеки и пересчёты курсов.
- Митигации: «окно правды» и версии метрик (v1→v2).
Анти-паттерны и профилактика
|
Анти-паттерн |
Чем опасен |
Что делать |
|---|---|---|
|
BI читает «сырые» таблицы |
утечки PII, разные формулы |
BI → только vw_*, маскирование/RLS |
|
Нет паспортов метрик |
«две правды» |
YAML-паспорт + автодоки в CI |
|
Разделение арендаторов через схемы без автоматизации |
операционный хаос |
темплейты DDL/CI, миграции ON CLUSTER |
|
FINAL в прод-VIEW |
провалы SLA |
дисциплина записи, Aggregating-state |
|
Summing на данных с ретро-правками |
«накрутка» сумм |
Aggregating или пересборка окна |
|
Нет DR-тестов |
бэкапы «бумажные» |
квартальные восстановительные тренировки |
Чек-листы (готовые)
Access & PII
- BI имеет доступ только к vw_*.
- Включён RLS по ключевым измерениям (регион/тенант).
- PII замаскирована/обрезана; запрещённые колонки не попадают во VIEW.
- Включён аудит чтения (query_log → дашборд доступа).
Multi-tenant
- Определена модель (row/schema/cluster), обоснованы риски/стоимость.
- tenant_id в ORDER BY и/или ключ шардинга.
- Квоты/профили на роли тенантов.
- Тяжёлые тенанты — план выделения шарда/схемы.
Cost & Capacity
- Политики хранения (hot/warm/cold), TTL MOVE на «холод».
- Крупные батчи вставок, контроль parts/merges.
- Агрегаты-состояния для тяжёлых метрик.
- Мониторинг read_bytes/query_duration по топ-запросам.
DR & Compliance
- Ежедневные/еженедельные бэкапы; другое хранилище.
- DR-день раз в квартал; smoke-тест после восстановления.
- Retention и «legal hold» задокументированы.
- Журнал изменений семантики (v1→v2) и согласования.
Итог
Говернанс и безопасность — это «нескоростная», но фундаментальная часть слоя витрин. Если у вас:
- метрики как код (паспорт+VIEW+CI),
- RBAC/RLS/PII-маскирование,
- понятная модель multi-tenant,
- экономика (tiering/TTL, агрегаты-состояния, батчи),
- DR и наблюдаемость,
то vitrine-слой переживёт рост нагрузки, аудит и «человеческие» ошибки без поражений SLA.
Arenadata QuickMarts (ADQM) — корпоративная платформа на базе ClickHouse для быстрого слоя витрин и near-real-time аналитики. Решает задачи «быстрых» дашбордов и API с низкой латентностью и высокой конкуррентностью, работает поверх вашего DWH/лейкхауса как serving-уровень. Даёт предсказуемую производительность на терабайтно-петабайтных объёмах за счёт колоночного хранения, компрессии и предагрегатов (Materialized Views, AggregatingMergeTree), подключается к Kafka/S3 и стандартным BI-инструментам по SQL/HTTP. Для корпоративных ИТ ADQM предлагает поддержку и SLA, отказоустойчивые кластеры (HA/DR), безопасность (RBAC, LDAP/OIDC, шифрование трафика и данных), мониторинг и резервное копирование. Платформа хорошо ложится на методологию курса: семантика vw_*, роллап-слои, NRT-ингест, SLO/наблюдаемость и «гвардейки» для BI/API. Итог — быстрый запуск витрин за недели, снижённые риски в проде и предсказуемая стоимость владения.



