Модуль 8. BI-приложения в k8s (шаблоны)
BI-приложения (Superset, Metabase и т. п.) стейтлес на уровне веб-слоя, но опираются на стейтфул-компоненты: метаданные в БД, кэш/очереди, файловые/объектные экспорты. Надёжность и производительность определяются не только самим BI, а всей обвязкой: сетевой публикацией (Ingress), пулом соединений к источникам данных, кэшем, асинхронными воркерами и правильными лимитами.
Эталонные паттерны: Superset
Референс-архитектура (логика)
- Web: Superset web (Gunicorn) — 2–N реплик, stateless.
- Метаданные: Postgres (отдельный StatefulSet/оператор), RWO-блок, PITR (см. Модуль 2).
- Брокер/кэш: Redis (broker для Celery + кэш результатов/сессий).
- Воркеры: Celery workers под SQL Lab/ Alerts & Reports/фоновые задания.
- Object storage: S3/MinIO для экспортов/артефактов (рекомендация).
- Ingress: TLS, лимиты тела/таймауты, IP-allowlist/SSO (см. Модуль 3/4).
Практические настройки (ключевые, без «простынь»)
- Gunicorn: воркеры gevent/async, 2–4 на CPU, таймауты ≥ 120–300 c для тяжёлых запросов (под ваш профиль).
- RESULTS_BACKEND/CACHE: вынос в Redis → уменьшает повторные запросы, разгружает БД/Trino.
- ASYNC/Alerts & Reports: только через Celery; без воркеров письма/экспорты «залипают».
- Метаданные: SQLAlchemy pool (pool_size, max_overflow) согласовать с лимитами Postgres/pgBouncer.
- Экспорт: большие выгрузки — в S3 с pre-signed ссылкой (не через BI-web). Почта — SMTP с rate-limit.
- SSO: OIDC/SAML нативно или через oauth2-proxy; группы → роли проекта (role mapping).
- Наблюдаемость: метрики Gunicorn, Redis (длина очередей), Celery (tasks in progress/failed), Ingress p95, ошибки отчётов.
Риски (Superset) и смягчение
-
Всё синхронно через web → таймауты/мёртвые соединения.
→ Переносить тяжёлые операции в Celery, на web — только запрос/статус. -
Очередь забита / долгие экспорты → рост latency.
→ Автоскейл воркеров по длине очередей (KEDA по Redis), cap на размер файлов. -
Сессии/логин на несколько реплик → «скачки» авторизации.
→ Sticky-cookie в Ingress + единый Redis-бэкенд для сессий. -
Метаданные БД — узкое место.
→ pgBouncer, индексы на таблицах событий/словарях, контроль автовакаума, лимит подключения из web/worker.
Эталонные паттерны: Metabase
Референс-архитектура (логика)
- Web: Metabase (JVM) — 2–N реплик, stateless.
- Приложенческая БД: Postgres/MySQL для метаданных/учётных записей.
- Очереди/кэш: по-возможности внешний Redis (если версия/плагины поддерживают), иначе опора на кэш источника и «умные» таймауты.
- Subscriptions/Alerts: использовать встроенные механизмы BI (письма/мессенджеры) ИЛИ внешние job’ы через API — важно исключить дубли.
- Ingress: TLS/лимиты, SSO (OIDC чаще всего), sticky-cookie при необходимости.
Практические настройки
- JVM: Xms/Xmx под размер набора; -XX:+UseG1GC; следите за GC-паузы p95.
- Таймауты и лимиты: ограничить длительность запросов/экспортов; на Ingress поднять proxy-read/send-timeout до разумного уровня.
- Пулы соединений к источникам: ограничить конкурентность Metabase и/или ставить PgBouncer перед Postgres-витринами; к Trino — лимиты сессий/запросов.
- Метаданные: SQL-пул под контролем; регулярный бэкап/вакуум.
Риски (Metabase) и смягчение
-
Дубли рассылок при нескольких репликах.
→ Использовать рекомендованный режим работы встроенного планировщика (по документации вашей версии): единый «scheduler-pod» или внешний Cron + API; при сомнениях — выделить одну реплику под «scheduler». -
Утечки памяти/рост heap при тяжёлых дашбордах.
→ Настройка JVM, профилирование, ограничение строк/колонок на виджет, кэш на стороне движка (Trino/ClickHouse query result cache). -
Исчерпание коннектов в источнике.
→ PgBouncer, per-user/per-app лимиты, connection-pool на BI «короче», чем на БД.
Кэш и пулы соединений
Где кэшировать
- Слой BI: кэш результатов запросов/фильтров (Redis). Хорошо экономит «повторные» дашборды.
- Слой движка: Trino/ClickHouse — собственные механизмы кэширования (metadata, query-result), настройте TTL и лимиты.
- Уровень HTTP: редко применимо (контент часто персонализирован).
Пулы и лимиты
- У BI → источнику: стойте за PgBouncer (Postgres), ограничьте max_conns на БД и pool_size на BI; не допускайте «N реплик × M воркеров × K потоков» без потолка.
- К Trino: ограничить query.max-concurrent-queries, max-clients, очередь запросов; BI — не выше лимита Trino, иначе получите 503/timeout.
- К ClickHouse: max_concurrent_queries, max_threads на пользователя BI, max_execution_time/max_result_rows для защиты.
Отчётные кроны и экспорт в файлы/почту
Где крутить «расписания»
- Superset: Alerts & Reports (через Celery). Вынесите воркеры в отдельный Deployment, масштабируйте по очереди.
- Metabase: встроенные «Subscriptions/Alerts» ИЛИ внешний оркестратор (Airflow) с вызовом API. Старайтесь обеспечить одиночность триггера (distributed-lock или single-scheduler pod).
Экспорт
- Большие файлы → S3: BI/воркер генерирует CSV/Parquet → загружает в S3 → пользователю приходит ссылка (pre-signed URL). Это снимает нагрузку с Ingress/подов.
- Почта: лимит размера вложений, дефолтная компрессия (zip), политические лимиты SMTP. Учитывайте ретраи/блокировки на стороне почты.
Анти-паттерны
- Скачивание 100+ МБ через BI-web синхронно.
- Сотни параллельных экспортов без очереди.
- Отчёт-монолит, который часами держит соединение к БД.
SSO/разграничение
- SSO на краю (oauth2-proxy/Ingress) или нативно в приложении. Группы из IdP маппятся на роли BI (RBAC).
- Row-level security (если нужно) — реализуйте на уровне движка (Postgres RLS, представления в Trino/ClickHouse) плюс параметризация BI.
- Сегментация источников: разные креды/роуты на Dev/Stage/Prod; запретить BI-Prod ходить в Dev-данные (NetworkPolicy + секреты).
Стратегия масштабирования
Что масштабируем
- Web-слой: по CPU/latency/requests-per-second. Sticky-sessions при необходимости (но лучше без них).
- Воркеры (Superset Celery): по длине очередей/времени ожидания задач (KEDA по Redis/Prometheus).
- Движок: Trino workers — по очереди запросов/CPU; ClickHouse — сложнее (шардирование и ресурсы), масштабирование вдумчиво.
Ограничители (guardrails)
- Connection budget: «верхняя планка» коннектов к каждой БД/Trino; HPA не должен переваливать за бюджет.
- Time budget: дефолтные таймауты запросов BI меньше таймаутов Ingress/прокси и БД.
- Memory budget: пулы BI/JVM/worker с запасом против OOM.
Типовые метрики для HPA/KEDA
- CPU web-слоя, p95 latency Ingress (через Prometheus Adapter), RPS.
- Длина очереди Celery/Redis, среднее время «в очереди».
- Очередь Trino (queued queries), активные воркеры.
Наблюдаемость (минимум, который нужен BI)
- SLI BI: доступность (2xx/3xx), p95 latency по ключевым URI, ошибки (4xx/5xx) — см. Модуль 5.
- Очереди: Redis/Celery queue length, задачи в обработке/ошибки.
- Экспорт: длительность и размер файлов, процент неуспешных отправок.
- Кэш: hit-ratio в Redis (по ключам BI), объём ключей, TTL.
- Пулы: занятость пулов SQLAlchemy/Hikari/pgBouncer; «исчерпано N%» → предупреждение.
- Движок: Trino/ClickHouse success-rate и p95.
Риски и анти-паттерны
|
Риск |
Проявление |
Что сделать |
|---|---|---|
|
Нет Redis/воркеров у Superset |
«Всё через web», ошибки/таймауты |
Включить Celery+Redis, все тяжёлые операции — асинхронно |
|
Sticky-sessions без причины |
«Липкость» ломает скейл/отказы |
Убрать зависимость от sticky, хранить сессии в Redis |
|
BI штурмует БД |
100+ коннектов, блокировки |
PgBouncer, connection budget, throttle на BI, очереди |
|
Гигантские экспорты через Ingress |
502/timeout, web-поды «зависают» |
Генерация в фоновых, загрузка в S3, pre-signed ссылки |
|
HPA «размножает» поды без лимитов |
исчерпаны коннекты/память |
Ограничители в конфиге, KEDA по очередям, не только CPU |
|
Смешение ролей Dev/Stage/Prod |
случайные доступы к не тем данным |
Отдельные секреты/NetworkPolicy/SSO-группы, валидация в CI |
ПРАКТИКА: k6-нагрузка BI + настройка HPA
Цель: проверить масштабируемость веб-слоя BI и включить HPA так, чтобы рост нагрузки не «ронял» SLO и не выедал бюджет коннектов.
A. Нагрузочное тестирование через k6
-
Подготовка
- Создайте тестовый пользователь SSO или временно включите basic-auth токен/сессионную куку.
- Выберите 2–3 целевых дашборда/эндпоинта (UI и API).
- Простой скрипт k6 (минимум необходимого)
// save as bi-test.js
import http from 'k6/http';
import { check, sleep } from 'k6';
export let options = {
stages: [
{ duration: '2m', target: 50 }, // разгон
{ duration: '5m', target: 50 }, // плато
{ duration: '2m', target: 0 }, // спад
],
thresholds: {
http_req_duration: ['p(95)<2500'], // p95 < 2.5s
http_req_failed: ['rate<0.01'], // ошибок < 1%
},
};
const BASE = __ENV.BASE_URL; // https://superset.company.local
const HDRS = { headers: { 'Authorization': `Bearer ${__ENV.TOKEN}` } };
export default function () {
let res = http.get(`${BASE}/api/v1/health`, HDRS);
check(res, { '200': (r) => r.status === 200 });
// пример обращения к дашборду/чартам
// http.get(`${BASE}/superset/dashboard/3/`, HDRS);
sleep(1);
}
Запуск:
BASE_URL=https://superset.company.local TOKEN=... k6 run bi-test.js
-
На что смотрим
- p95 latency, доля ошибок, CPU/память веб-подов, длина очередей Celery (если включены), RPS на Ingress.
- Побочные эффекты: рост коннектов к метаданных-БД/Trino, throttle по CPU.
B. Включаем HPA для веб-слоя
Метрика по умолчанию — CPU. Лучше — кастомная метрика (RPS/latency) через Prometheus Adapter или KEDA. Но начнём с CPU, зафиксировав «верхний лимит» по коннектам.
- Мини-пример HPA (CPU)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: superset-web-hpa
namespace: bi
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: superset
minReplicas: 2
maxReplicas: 8
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
-
Ограничители
- В values/env выставьте пределы: SQLALCHEMY_POOL_SIZE, MAX_OVERFLOW, PGBOUNCER max_client_conn, лимиты Trino (max concurrent).
- Убедитесь, что maxReplicas × (соединения на под) ≤ допустимого кворума источников.
- Продвинутый вариант
- KEDA по длине Celery-очереди (скалирует воркеры отдельно от web).
- Prometheus Adapter: метрика nginx_ingress_controller_requests → HPA по RPS/latency.
- Убедитесь, что при росте нагрузки HPA «поднимает» реплики без просадки SLO и без «красных» алертов по коннектам.
- Повторный прогон k6
Чек-лист «готово к продакшну»
- Superset: Redis + Celery workers, кэш результатов, таймауты и лимиты; Metabase: планы рассылок без дублей, JVM-настройки.
- Метаданные BI в Postgres с PITR; PgBouncer перед Postgres-витринами; лимиты коннектов и пулов согласованы.
- Экспорты больших файлов — через S3 (pre-signed), почтовые лимиты/ретраи настроены.
- SSO и RBAC: группы → роли; row-level security на уровне движка (если нужно).
- Ingress: TLS/лимиты/таймауты, sticky-cookie только при необходимости, WAF (внешние витрины).
- HPA/KEDA: web-слой по CPU/latency/RPS; воркеры — по очередям; верхние пределы по коннектам.
- Наблюдаемость: SLO BI (availability/latency), Celery/Redis, пулы коннектов, экспорты, Trino/ClickHouse p95.
- Runbooks: «затоптали БД коннектами», «очередь Celery растёт», «экспорт завис», «таймауты Ingress», «OOM у web/worker».
Надёжный BI в k8s — это web-слой, который ничего тяжёлого не делает, быстрые асинхронные воркеры, разумные пулы к источникам и экспорты через S3, а также SSO/разграничение «как код». Масштабируйте web по спросу, воркеров — по очередям, но всегда держите в голове бюджет соединений/времени/памяти. Тогда Superset/Metabase выдержат пики и не «утянут» за собой вашу DWH-платформу.



