Apache Superset на сервере: частые ошибки и решения
Apache Superset ставится за 15 минут по любому туториалу, но через неделю эксплуатации начинаются сюрпризы: дашборды виснут на «Loading», SQL Lab падает по таймауту, письма с отчётами не уходят, а после рестарта контейнера пропадают все сохранённые чарты. Большинство этих проблем — не баги Superset, а последствия дефолтной конфигурации, которая рассчитана на демо, а не на прод. Ниже — конкретные причины и рабочие решения для каждой из типовых ситуаций.
Содержание
- Дашборд бесконечно грузится или падает по таймауту
- Async-очередь для запросов не работает: Celery, Redis и результаты, которые не приходят
- CSRF-ошибки и «Bad Request» при логине через reverse-proxy
- После рестарта контейнера пропали дашборды и подключения к базам
- SQL Lab обрывает длинные запросы раньше, чем нужно
- Отчёты по расписанию (Alerts & Reports) не приходят на почту
- Дашборды с большими датасетами тормозят даже с async-очередью
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →Дашборд бесконечно грузится или падает по таймауту
Самая частая жалоба: тяжёлый дашборд с 8-10 чартами открывается минуту-две, а иногда вместо данных вылезает Query timeout или белый экран. Причина почти всегда в том, что Superset по умолчанию считает все запросы синхронно — веб-воркер Gunicorn ждёт ответа от базы, держит соединение открытым, и если у вас всего 2-4 воркера, они быстро упираются в потолок при параллельной загрузке чартов.
Проверьте, сколько воркеров реально поднято:
ps aux | grep gunicorn | grep -v grep | wc -l
Если Superset запущен как в дефолтном Docker-образе (docker/docker-init.sh), там обычно 4 sync-воркера — этого хватает для одного пользователя, но не для команды. Решение — включить gevent worker class и поднять число воркеров, отредактировав docker/pythonpath_dev/gunicorn_config.py или флаги запуска:
gunicorn \
--bind 0.0.0.0:8088 \
--workers 8 \
--worker-class gevent \
--worker-connections 1000 \
--timeout 120 \
--limit-request-line 0 \
--limit-request-field_size 0 \
"superset.app:create_app()"
Формула для количества воркеров на VPS — (2 x CPU) + 1, но не берите значение с потолка: на 4 vCPU / 8 ГБ RAM 8-9 воркеров уже съедят большую часть памяти, если каждый держит по 300-400 МБ на запросах с большими датасетами. Второй обязательный шаг — включить асинхронные запросы через Celery (см. следующий раздел), иначе даже с gevent тяжёлые SQL-запросы будут блокировать интерфейс.
Async-очередь для запросов не работает: Celery, Redis и результаты, которые не приходят
Superset умеет отправлять тяжёлые запросы в фоновую очередь вместо того, чтобы держать HTTP-соединение открытым, но из коробки это не настроено. Если в интерфейсе вы включили «Run async» в настройках базы, а чарт просто зависает с крутящимся индикатором — почти наверняка не запущен Celery worker или он не видит брокер.
Минимальный рабочий конфиг в superset_config.py:
from celery.schedules import crontab
class CeleryConfig:
broker_url = "redis://redis:6379/0"
imports = ("superset.sql_lab",)
result_backend = "redis://redis:6379/1"
worker_prefetch_multiplier = 1
task_acks_late = True
task_annotations = {
"sql_lab.get_sql_results": {
"rate_limit": "100/s",
},
}
beat_schedule = {
"reports.scheduler": {
"task": "reports.scheduler",
"schedule": crontab(minute="*", hour="*"),
},
"reports.prune_log": {
"task": "reports.prune_log",
"schedule": crontab(minute=0, hour=0),
},
}
CELERY_CONFIG = CeleryConfig
RESULTS_BACKEND = None # используем через SQLALCHEMY, см. ниже
После этого нужно реально поднять воркер и beat отдельными процессами — просто прописать конфиг недостаточно:
celery --app=superset.tasks.celery_app:app worker \
--pool=prefork --concurrency=4 -Ofair -l INFO
celery --app=superset.tasks.celery_app:app beat -l INFO
Типичная ошибка — Celery worker стартует в отдельном контейнере, у которого нет доступа к тем же переменным окружения (SUPERSET_CONFIG_PATH, строка подключения к БД), что и у веб-контейнера. Проверяйте логи воркера отдельно:
docker compose logs -f celery_worker | grep -i error
Если видите kombu.exceptions.OperationalError: Error connecting to redis, значит контейнер Redis либо не в той же docker-сети, либо название хоста в broker_url не совпадает с именем сервиса в docker-compose.yml.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверCSRF-ошибки и «Bad Request» при логине через reverse-proxy
Если Superset стоит за Nginx с SSL-терминацией, частая ошибка — 400 Bad Request: The CSRF session token is missing при попытке войти, хотя напрямую по HTTP на порт 8088 всё работает. Причина в том, что Superset не знает, что запрос пришёл по HTTPS, потому что Nginx не передаёт нужные заголовки.
Конфиг Nginx должен явно пробрасывать протокол:
server {
listen 443 ssl;
server_name bi.example.com;
location / {
proxy_pass http://127.0.0.1:8088;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}
}
А в superset_config.py — обязательно включить ENABLE_PROXY_FIX, иначе Flask-приложение продолжит считать, что все запросы приходят по HTTP:
ENABLE_PROXY_FIX = True
WTF_CSRF_ENABLED = True
WTF_CSRF_TIME_LIMIT = None
WTF_CSRF_TIME_LIMIT = None снимает ограничение по времени жизни CSRF-токена — полезно, если пользователи держат вкладку логина открытой дольше часа, но это небольшое ослабление защиты; в средах с высокими требованиями к безопасности лучше просто увеличить лимит (например, до 3600 x 4), а не снимать его совсем.
После рестарта контейнера пропали дашборды и подключения к базам
Это не баг Superset, а классическая ошибка эксплуатации Docker: метаданные Superset (дашборды, чарты, сохранённые запросы, пользователи) хранятся в его собственной БД — по умолчанию SQLite внутри контейнера, если вы явно не подключили внешний PostgreSQL. При пересоздании контейнера (docker compose down без -v, обновление образа, миграция на новый сервер) файл SQLite остаётся в слое контейнера и теряется.
Проверьте, куда сейчас смотрит Superset:
docker exec -it superset_app env | grep SQLALCHEMY_DATABASE_URI
Если там sqlite:////app/superset_home/superset.db — переносите метаданные на отдельный PostgreSQL как можно скорее. Правильная схема — два независимых экземпляра БД: одна для метаданных Superset, вторая (или несколько) как источники данных, на которые смотрят дашборды:
SQLALCHEMY_DATABASE_URI = "postgresql+psycopg2://superset:PASSWORD@postgres:5432/superset_meta"
Инициализация после переезда на PostgreSQL:
superset db upgrade
superset fab create-admin \
--username admin --firstname Admin --lastname Admin \
--email admin@example.com --password 'STRONG_PASSWORD'
superset init
Полезно почитать про установку и тюнинг самого PostgreSQL под нагрузку, если это первая база, которую вы администрируете самостоятельно — там разобраны ошибки, актуальные и для метаданных Superset, и для источников данных.
SQL Lab обрывает длинные запросы раньше, чем нужно
По умолчанию у Superset несколько слоёв таймаутов, и они не синхронизированы между собой: таймаут Gunicorn, таймаут самого запроса в SQL Lab, таймаут соединения к базе-источнику и таймаут Nginx как reverse-proxy. Если вы увеличили один, а запрос всё равно рвётся на той же секунде — значит уперлись в другой слой.
Проверьте и выровняйте все четыре:
# superset_config.py
SUPERSET_WEBSERVER_TIMEOUT = 300
SQLLAB_TIMEOUT = 300
SQLLAB_ASYNC_TIME_LIMIT_SEC = 21600 # 6 часов для фоновых запросов
SUPERSET_WEBSERVER_PROTOCOL = "https"
# в блоке location
proxy_read_timeout 300s;
proxy_connect_timeout 300s;
Для запросов, которые объективно выполняются дольше 5 минут (аналитика по большим таблицам без индексов), правильный путь — не бесконечно поднимать таймауты, а перевести такие запросы в асинхронный режим через Celery (см. раздел выше) и агрегировать данные заранее, например через материализованные представления или отдельные ETL-джобы, которые кладут уже посчитанный результат в отдельную таблицу для дашборда.
Отчёты по расписанию (Alerts & Reports) не приходят на почту
Функция «Alerts & Reports» зависит сразу от нескольких компонентов, и если хотя бы один не настроен — письма молча не отправляются, без явной ошибки в интерфейсе. Чек-лист по порядку:
- Celery beat действительно запущен как отдельный процесс (см. раздел про async) — без него планировщик просто не срабатывает.
- В
superset_config.pyвключена сама фича:
FEATURE_FLAGS = {
"ALERT_REPORTS": True,
}
EMAIL_NOTIFICATIONS = True
SMTP_HOST = "smtp.yourmailprovider.com"
SMTP_STARTTLS = True
SMTP_SSL = False
SMTP_USER = "reports@example.com"
SMTP_PORT = 587
SMTP_PASSWORD = "APP_PASSWORD"
SMTP_MAIL_FROM = "reports@example.com"
- Для скриншотов дашбордов в письме нужен headless-браузер — Superset использует Selenium с Chromium, и если в контейнере его нет, отчёты падают с ошибкой в логах Celery worker, а не показываются пользователю вообще. В официальном Docker-образе (профиль
superset-worker) это обычно уже есть, но при сборке своего образа легко забыть пакетыchromiumиchromedriver.
Проверка логов по отчётам:
docker compose logs celery_worker | grep -i "report\|alert"
Если видите WebDriverException: unknown error: cannot find Chrome binary, значит нужно доставить браузер в образ воркера — это отдельный контейнер от веб-воркера, и наличие Chromium в одном не гарантирует его в другом.
Дашборды с большими датасетами тормозят даже с async-очередью
Когда очередь настроена, а дашборд всё равно медленный — проблема обычно уже не в Superset, а в источнике данных. Superset — это визуализация поверх чужой СУБД, и он не ускоряет сами запросы. Частые причины на стороне PostgreSQL: отсутствие индексов на колонках, по которым идёт GROUP BY в чартах, и отсутствие кеша результатов на уровне Superset.
Включите кеш через Redis для результатов чартов — это снимает нагрузку с базы при повторных открытиях одного и того же дашборда несколькими пользователями:
from datetime import timedelta
CACHE_CONFIG = {
"CACHE_TYPE": "RedisCache",
"CACHE_DEFAULT_TIMEOUT": 300,
"CACHE_KEY_PREFIX": "superset_results_",
"CACHE_REDIS_URL": "redis://redis:6379/2",
}
DATA_CACHE_CONFIG = CACHE_CONFIG
Если чарты строятся поверх ClickHouse, а не PostgreSQL — это часто оправдано именно для BI-нагрузки с большими объёмами и агрегациями: почитайте сравнение ClickHouse и PostgreSQL для аналитики, прежде чем переносить источник данных. Отдельно стоит настроить Redis правильно с точки зрения памяти и персистентности — если Redis используется и для Celery-брокера, и для кеша чартов, при нехватке памяти он начнёт вытеснять ключи по политике maxmemory-policy, и это может незаметно ломать очередь задач.
Нужен сервер под эту задачу?
Разверните VPS MAATRIX за пару минут: NVMe, AMD EPYC, root-доступ, локации UK, США, Франция и РФ. Оплата картой РФ и по СБП.
Арендовать серверНужны сами нейросети для контента?
Генерируйте изображения, видео и озвучку нейросетями на falapi.io — десятки моделей в одном окне. Оплата картой РФ и по СБП.
Частые вопросы
Сколько ресурсов сервера нужно для Superset в проде?
Для команды до 10-15 активных пользователей и умеренного числа дашбордов хватает 4 vCPU / 8 ГБ RAM под сам Superset плюс отдельно ресурсы под источники данных и Redis. Если источник данных (PostgreSQL/ClickHouse) стоит на том же сервере — закладывайте минимум 8-16 ГБ RAM суммарно и следите за потреблением памяти по факту, цифры сильно зависят от объёма данных и сложности запросов.
Обязательно ли выносить метаданные в PostgreSQL, если Superset используют 2-3 человека?
Технически нет, но SQLite не переживёт пересоздание контейнера без явного volume, а конкурентная запись при нескольких пользователях у SQLite ограничена. Даже для маленькой команды перенос на PostgreSQL занимает 20 минут и снимает риск потери всех дашбордов.
Можно ли использовать Superset без Docker, напрямую на VPS?
Да, через pip install apache-superset в виртуальном окружении, но тогда все компоненты (веб, Celery worker, Celery beat, Redis, PostgreSQL) нужно поднимать и держать в системе как отдельные systemd-юниты вручную — Docker Compose избавляет от этой рутины и упрощает обновления.
Почему после обновления Superset дашборды визуально сломались?
Между мажорными версиями иногда меняется формат хранения конфигурации чартов (viz_type, схема JSON в slice.params). Перед обновлением делайте бэкап метаданных (pg_dump базы метаданных) и проверяйте changelog конкретной версии — миграция superset db upgrade обычно решает схему БД, но кастомные плагины визуализации иногда требуют ручной правки.
Нужен ли отдельный сервер под Superset или можно на одном VPS с другими сервисами?
Можно совмещать при небольшой нагрузке, но Celery worker и headless Chromium для скриншотов потребляют заметно больше памяти в моменты формирования отчётов — если на том же сервере крутится что-то ещё чувствительное к задержкам (например, продакшн-БД приложения), лучше вынести Superset на отдельный VPS.
Обсудить статью, задать вопрос или начать новую тему
Есть вопрос по этой статье, идея для обсуждения или просто хотите поделиться опытом? Сообщество MAATRIX ждёт. Для общения, пожалуйста, зарегистрируйтесь в нашем личном кабинете.
Перейти в сообщество →