我最初接触 Superset 是在2018年的时候,那时候 Superset 的版本才0.26,当时在公司内部积累了一些best practice,遇到了bug还顺便贡献了代码,算是对这个项目有比较深入的了解。
这些年看着 Superset 社区越来越成功,国内也有很多公司和开发者需要围绕着 Superset 做一些公司生态内的二次开发,而我现在回过头来看这个项目,对整个项目有了更深刻的理解,接下来,我会输出一系列的文章,讲解如何玩转 Superset 的二次开发。
刚开始接手一个新的项目,大致了解每个目录下的代码大概是做什么的非常重要,你会知道代码去哪里修改,做到心中有数才能更加游刃有余。
Superset 介绍
Superset 是一个款非常优秀的开源项目,作为BI工具,它的开发语言大众化,云原生的架构能够满足企业各种各样的定制化需求,从 web server,后端数据库,消息队列,缓存层都可以根据业务需要进行配置更改。支持各种各样的大数据组件作为查询引擎,如 Presto,Hive,Spark,Clickhouse,Amazon Athena,Redshift 等等。
而丰富的数据可视化解决方案才是 Superset 最大的亮点,它还支持自定义plugin的方式去增加自己想要的图表。
代码目录介绍
以 Superset branch 1.5为例,根目录下通常会存放一些代码样式规范,git相关的配置,docker文件,python setup等脚本。还有做开源贡献必须仔细阅读的 code of conduct 和 contributing。
这些文件中需要着重阅读的是 contributing,里面有很详细的步骤告诉你如何开始贡献代码,如何把前端本地开发环境搭建起来,前后端如何协调,怎么修改代码的缩进等等。
根目录下还有如图所示的各个文件夹
挑几个比较重要的来说说,
- superset:后端代码主要放在这个文件夹中
- superset-frontend: 前端代码的入口
- superset-websocket:Nodejs websocket相关
- docker:docker文件,docker的启动脚本等等
- helm/superset:helm charts 的配置文件,不太了解 helm 的可以看看官方介绍
- requirements:python环境下,需要安装的一些第三方包及其版本
- .github:存放github CI/CD 相关的 workflow 配置,可略过
- RELEASING:存放版本release note
我个人多年来阅读项目源码的习惯是先抓住重点,细枝末节的东西可以以后慢慢一点点补充。一上来不要一下子输入太多,细节有时候会把人带跑。
以上就是比较重要的一些模块,作为后端开发(前端我无能为力 🙂 ),首先可以看看 superset
文件夹下的代码。
看源码的过程建议结合前端的UI交互、功能来看对应的后端代码。首先应该自己去上手用一用这款产品,连接一些数据库,建几张表,最后建几个dashboard玩一玩,数据可视化方面的一些基本知识也需要顺便补一补,只有真正成为一个产品的用户,才会变成一个有心人,发现很多别人看不到的细节,才有可能做到深入。
后端代码入口
后端是如何启动起来的,通过看 Dockerfile 的 entrypoint 或者 CMD
这段代码可以发现,启动后端服务应该是在 ./docker/docker-ci.sh 这个文件里执行的,顺着这个文件找下去,会发现最终执行的是一个叫 ./docker/run-server.sh 的脚本。
启动 Superset 后端server的一个命令就是 gunicorn 这一句。gunicorn 要启动的这个 ${FLASK_APP} 变量通过代码搜索可以发现就是 FLASK_APP="superset.app:create_app()"
它所对应的方法就是 superset/app.py 文件中的 create_app()
方法。
def create_app() -> Flask:
app = SupersetApp(__name__)
try:
# Allow user to override our config completely
config_module = os.environ.get("SUPERSET_CONFIG", "superset.config")
app.config.from_object(config_module)
app_initializer = app.config.get("APP_INITIALIZER", SupersetAppInitializer)(app)
app_initializer.init_app()
return app
# Make sure that bootstrap errors ALWAYS get logged
except Exception as ex:
logger.exception("Failed to create app")
raise ex
class SupersetApp(Flask):
pass
这段创建应用的代码做了几件事:
- 加载 superset/config.py,也就是说将配置文件加载进来,看过官网的介绍应该也知道默认的配置文件就是这个。
- 调用 app_initializer 进行一系列的初始化,配置文件里没有的话,默认就调用 SupersetAppInitializer.init_app() 方法
- 这个 init_app() 里面又处理了很多初始化的工作,比如 setup database, configure celery, config cache 等等
- 最重要的还有一个 init_views() 方法。
代码:https://github.com/apache/superset/blob/1.5/superset/initialization/init.py
def init_app(self) -> None:
"""
Main entry point which will delegate to other methods in order to fully init the app """ self.pre_init()
self.check_secret_key()
# Configuration of logging must be done first to apply the formatter properly
self.configure_logging()
# Configuration of feature_flags must be done first to allow init features
# conditionally self.configure_feature_flags()
self.configure_db_encrypt()
self.setup_db()
self.configure_celery()
self.enable_profiling()
self.setup_event_logger()
self.setup_bundle_manifest()
self.register_blueprints()
self.configure_wtf()
self.configure_middlewares()
self.configure_cache()
with self.superset_app.app_context():
self.init_app_in_ctx()
self.post_init()
init_views()
这个方法很重要,因为 Superset 后端是用 Flask + FlaskAppBuilder 这两个框架去写的,因此需要初始化一些 FlaskAppBuilder 的 views,API,links 等等。
到此为止,整个后端代码的入口介绍就差不多了,后端核心的代码放在 superset 文件夹中,通过文件夹的命名,也能够看到大致的端倪。
这个看代码入口的方法套到其他的开源项目也是适用的哦,这是一个屡试不爽的好方法。
如何上手代码
想要更好地理解 Superset 的代码,你还需要做一些额外的准备:
- 熟悉 Python 语言,了解一些常见的语法糖,语言的特性。这样看到报错信息可以帮助更好地定位问题,而不是一头雾水。
- 熟悉 Flask 和 FlaskAppBuilder 框架,因为 Superset 的后端 API,views,models 的理解都需要在了解这两个框架的基础上。
- 熟悉一些常见的 python package,如 SQLAlchemy,marshmallow,pandas,celery等。
最后
如果你对Superset的代码或者二次开发有问题,可以找我咨询,我组建了免费的社区,大家都很乐于分享。如有需要,看我个人简介来联系我,注明来意~