Superset配置Report & Alert实践及二次开发实践
项目背景与概述
Apache Superset 是一个现代化的数据探索和可视化平台,提供了强大的自动报警和报表功能。通过这些功能,用户可以将仪表板或图表自动发送到指定的电子邮件收件人或Slack频道,主要包括两种类型:
- 警报(Alert):当SQL查询满足特定条件时触发发送
- 报表(Report):按照预设的时间计划定期发送
然而,在实际使用过程中,我发现其截屏功能存在一些限制 - 只能以固定窗口大小进行截屏,这可能导致报表中的图表内容被截断或产生多余的空白区域。为了解决这个问题,我进行了相关的二次开发。本文将详细介绍Report & Alert功能的配置方法,以及如何通过二次开发优化截屏功能。
Report & Alert配置指南
前置要求
1. 基础配置
在superset_config.py
或superset_config_docker.py
中需要:
- 启用功能标志:
python
FEATURE_FLAGS = {
"ALERT_REPORTS": True
}
- 配置Celery调度:
python
from celery.schedules import crontab
class CeleryConfig:
# ... 其他Celery配置 ...
beat_schedule = {
"reports.scheduler": {
"task": "reports.scheduler",
"schedule": crontab(minute="*", hour="*"),
},
"reports.prune_log": {
"task": "reports.prune_log",
"schedule": crontab(minute=0, hour=0),
},
}
- 配置通知方式(至少选择一种):
- 邮件通知:配置
SMTP_*
相关设置 - Slack通知:配置
SLACK_API_TOKEN
- 邮件通知:配置
2. 环境要求
- 必须安装无头浏览器(Firefox或Chrome)用于截图
- 如果使用Chrome,需要在配置中设置:
python
WEBDRIVER_TYPE = "chrome"
WEBDRIVER_OPTION_ARGS = [
"--force-device-scale-factor=2.0",
"--high-dpi-support=2.0",
"--headless",
"--disable-gpu",
"--disable-dev-shm-usage",
"--no-sandbox",
"--disable-setuid-sandbox",
"--disable-extensions",
]
详细配置示例
python
# Redis配置
REDIS_HOST = "superset_cache"
REDIS_PORT = "6379"
# 截图等待时间配置
SCREENSHOT_LOCATE_WAIT = 100
SCREENSHOT_LOAD_WAIT = 600
# Slack配置
SLACK_API_TOKEN = "xoxb-your-token"
# 邮件配置
SMTP_HOST = "smtp.sendgrid.net"
SMTP_PORT = 2525
SMTP_STARTTLS = True
SMTP_SSL_SERVER_AUTH = True
SMTP_SSL = False
SMTP_USER = "your_user"
SMTP_PASSWORD = "your_password"
SMTP_MAIL_FROM = "noreply@youremail.com"
EMAIL_REPORTS_SUBJECT_PREFIX = "[Superset] "
# WebDriver配置
WEBDRIVER_BASEURL = "http://superset:8088"
WEBDRIVER_BASEURL_USER_FRIENDLY = "https://your-domain.com:8088"
# 执行用户配置
from superset.tasks.types import ExecutorType
THUMBNAIL_SELENIUM_USER = 'admin'
ALERT_REPORTS_EXECUTE_AS = [ExecutorType.SELENIUM]
# 最小执行间隔配置
from datetime import timedelta
ALERT_MINIMUM_INTERVAL = int(timedelta(minutes=10).total_seconds())
REPORT_MINIMUM_INTERVAL = int(timedelta(minutes=5).total_seconds())
重要说明
-
关于Celery并发:
- 建议使用
-c 4
限制并发数,因为Selenium/webdriver会消耗大量资源 - 如果发现geckodriver进程泄露,尝试使用:
celery worker --pool=prefork --max-tasks-per-child=128
- 建议使用
-
Worker配置:
- 建议为sql_lab和email_reports任务运行独立的worker
- 可以通过task_annotations中的queue字段配置
-
故障排查:
- 检查Celery worker日志
- 验证浏览器和webdriver安装
- 测试邮件发送功能
- 确认worker可以访问报表URL
功能改进:自适应截屏
问题描述
原版Superset(3.1.*)在进行截屏时使用了预设的固定窗口大小:
python
driver.set_window_size(*self._window)
这种方式无法根据实际内容自动调整窗口大小,可能导致以下问题:
- 内容过长时被截断
- 内容较短时产生多余空白
- 无法完整捕获仪表板的所有内容
改进方案
我对get_screenshot()
函数进行了优化,主要改动如下(完整代码可见GitHub提交记录):
python
# 屏蔽预设的窗口配置
# driver.set_window_size(*self._window)
driver.get(url)
img: bytes | None = None
selenium_headstart = current_app.config["SCREENSHOT_SELENIUM_HEADSTART"]
logger.debug("Sleeping for %i seconds", selenium_headstart)
sleep(selenium_headstart)
# 使用JavaScript获取页面实际高度并设置窗口大小
height = driver.execute_script("return document.documentElement.scrollHeight")
driver.set_window_size(self._window[0], height)
改进后的代码可以:
- 通过JavaScript获取页面的实际高度
- 动态调整窗口大小以适应内容
- 确保截图包含所有内容,无多余空白
项目结构导读
在开始开发之前,了解Superset的项目结构很重要。以下是主要目录结构:
superset/
├── superset/ # 后端Python代码
│ ├── views/ # 视图层,处理HTTP请求
│ ├── models/ # 数据模型
│ ├── utils/ # 工具类,我们的截屏功能就在这里
│ ├── extensions/ # Flask扩展
│ └── ...
├── superset-frontend/ # 前端代码
│ ├── src/ # 源代码
│ ├── packages/ # 可重用的包
│ └── ...
├── docker/ # Docker相关配置
├── tests/ # 测试用例
└── ...
关键模块说明
-
后端核心模块:
superset/views/
: 包含所有视图函数,处理HTTP请求superset/models/
: 定义数据库模型superset/utils/
: 包含各种工具函数,如我们修改的截屏功能superset/config.py
: 配置文件
-
前端核心模块:
superset-frontend/src/views/
: 页面组件superset-frontend/src/components/
: 可重用组件superset-frontend/src/visualizations/
: 可视化组件
-
Docker相关:
docker/
: 包含Docker相关配置Dockerfile
: 主Dockerfile文件
开发环境搭建指南
1. 使用Docker Compose搭建开发环境
因为项目依赖较多,推荐使用Docker Compose来搭建开发环境。首先需要创建一个适合开发的docker-compose配置文件。
- 克隆项目代码:
bash
git clone git@github.com:apache/superset.git
cd superset
- 创建开发环境配置文件:
bash
cp docker-compose.yml docker-compose-local.yml
- 修改
docker-compose-local.yml
,主要改动如下:
yaml
// ... existing code ...
x-superset-image: &superset-image apache/superset:latest-dev
// ... existing code ...
superset:
env_file: docker/.env
build:
context: .
dockerfile: Dockerfile
target: dev
image: *superset-image
// ... existing code ...
- 启动开发环境:
bash
docker compose -f docker-compose-local.yml up
主要改动说明:
- 将远程镜像地址 apachesuperset.docker.scarf.sh/apache/superset:${TAG:-latest-dev} 改为本地镜像名称 apache/superset:latest-dev
- 在 superset 服务中添加了 build 配置,指定使用本地的 Dockerfile 进行构建
- 使用 target: dev 指定构建开发环境镜像
这样修改后,当您运行 docker-compose up 时,系统会先使用本地的 Dockerfile 构建镜像,而不是从远程仓库拉取。其他依赖这个镜像的服务(如 superset-worker、superset-init 等)会自动使用这个本地构建的镜像。
记得在运行前执行:
bash
docker-compose -f docker-compose-local.yml build
来构建本地镜像。
2. 本地开发流程
- 创建并切换到新的开发分支:
bash
git checkout -b feature/screenshot-improvement
- 修改代码后,需要重新构建Docker镜像:
bash
docker compose -f docker-compose-local.yml down
docker compose -f docker-compose-local.yml build
docker compose -f docker-compose-local.yml up
3. 开发调试技巧
-
实时代码修改:
- 由于配置了代码目录挂载,修改Python代码后会自动重载
- 修改前端代码需要在superset-frontend目录下运行
npm run dev
-
查看日志:
bash
# 查看所有容器日志
docker compose -f docker-compose-local.yml logs -f
# 只查看superset容器日志
docker compose -f docker-compose-local.yml logs -f superset
- 数据库操作:
bash
# 进入容器
docker exec -it superset_app bash
# 执行数据库迁移
superset db upgrade
# 创建管理员用户
superset fab create-admin
4. 生产环境部署
根据不同的部署环境和需求,这里提供几种部署方案:
方案一:直接修改Python包源码(最简单)
适用场景:单机部署,快速验证
- 找到Superset安装目录:
bash
# 查看superset包安装位置
pip show apache-superset | grep Location
- 直接修改目标文件:
bash
# 例如修改截屏功能
cd <superset安装路径>/superset/utils/
vim webdriver.py
# 修改完成后重启Superset服务
sudo systemctl restart superset
# 或者
supervisorctl restart superset
优点:
- 操作简单直接
- 无需构建镜像
- 适合快速验证修改
缺点:
- 不适合多机部署
- 版本管理困难
- 系统升级时修改会被覆盖
方案二:使用Docker镜像(推荐)
适用场景:正式生产环境,多机部署
- 确保代码经过充分测试
- 创建发布分支
- 构建生产环境镜像:
bash
docker build -t your-registry/superset:your-tag .
- 推送镜像到镜像仓库:
bash
docker push your-registry/superset:your-tag
- 在生产环境更新镜像版本并重启服务:
bash
# 拉取新镜像
docker pull your-registry/superset:your-tag
# 更新服务
docker compose -f docker-compose-prod.yml up -d
优点:
- 环境一致性好
- 便于版本管理
- 适合多机部署
- 回滚方便
缺点:
- 需要维护Docker镜像仓库
- 部署流程相对复杂
方案三:使用pip安装自定义包
适用场景:需要在多个项目中复用修改,或需要维护自己的版本
- 创建自定义包:
bash
# 克隆原始代码
git clone https://github.com/apache/superset.git
cd superset
# 修改版本号(避免冲突)
vim setup.py # 修改version为自定义版本,如"3.1.0-custom"
- 构建并上传到私有PyPI仓库:
bash
# 构建包
python setup.py sdist bdist_wheel
# 上传到私有PyPI仓库
twine upload --repository-url https://your-pypi-repo/simple/ dist/*
- 在生产环境安装:
bash
pip install -i https://your-pypi-repo/simple/ apache-superset==3.1.0-custom
优点:
- 便于在多个项目中复用
- 可以维护自己的版本
- 支持通过pip管理依赖
缺点:
- 需要维护私有PyPI仓库
- 版本号管理需要注意
方案四:使用Helm在Kubernetes中部署
适用场景:Kubernetes环境
- 修改Helm配置:
yaml
# values.yaml
image:
repository: your-registry/superset
tag: your-tag
- 部署/更新:
bash
# 首次部署
helm install superset ./helm/superset -f values.yaml
# 更新部署
helm upgrade superset ./helm/superset -f values.yaml
优点:
- 适合云原生环境
- 便于扩展和管理
- 配置灵活
缺点:
- 需要Kubernetes环境
- 学习成本较高
开发建议
-
环境隔离:始终使用Docker进行开发,确保环境一致性
-
代码规范:
- 遵循项目的代码风格指南
- 添加适当的注释
- 编写测试用例
-
版本控制:
- 创建功能分支进行开发
- 提交信息要清晰明了
- 定期与主分支同步
-
测试验证:
- 本地充分测试
- 在开发环境验证
- 考虑边界情况
结论
通过这次二次开发实践,不仅解决了Superset截屏功能的限制,也积累了宝贵的开发经验。对于想要进行Superset二次开发的开发者,建议:
- 充分阅读项目文档
- 使用Docker管理开发环境
- 遵循项目的开发规范
- 循序渐进,从小改动开始
希望这篇文章能帮助到想要进行Superset二次开发的同学们!