我最初接觸 Superset 是在2018年的時候,那時候 Superset 的版本才0.26,當時在公司內(nèi)部積累了一些best practice,遇到了bug還順便貢獻了代碼,算是對這個項目有比較深入的了解。
這些年看著 Superset 社區(qū)越來越成功,國內(nèi)也有很多公司和開發(fā)者需要圍繞著 Superset 做一些公司生態(tài)內(nèi)的二次開發(fā),而我現(xiàn)在回過頭來看這個項目,對整個項目有了更深刻的理解,接下來,我會輸出一系列的文章,講解如何玩轉(zhuǎn) Superset 的二次開發(fā)。
剛開始接手一個新的項目,大致了解每個目錄下的代碼大概是做什么的非常重要,你會知道代碼去哪里修改,做到心中有數(shù)才能更加游刃有余。
Superset 介紹
Superset 是一個款非常優(yōu)秀的開源項目,作為BI工具,它的開發(fā)語言大眾化,云原生的架構(gòu)能夠滿足企業(yè)各種各樣的定制化需求,從 web server,后端數(shù)據(jù)庫,消息隊列,緩存層都可以根據(jù)業(yè)務(wù)需要進行配置更改。支持各種各樣的大數(shù)據(jù)組件作為查詢引擎,如 Presto,Hive,Spark,Clickhouse,Amazon Athena,Redshift 等等。
而豐富的數(shù)據(jù)可視化解決方案才是 Superset 最大的亮點,它還支持自定義plugin的方式去增加自己想要的圖表。

代碼目錄介紹
以 Superset branch 1.5為例,根目錄下通常會存放一些代碼樣式規(guī)范,git相關(guān)的配置,docker文件,python setup等腳本。還有做開源貢獻必須仔細閱讀的 code of conduct 和 contributing。
這些文件中需要著重閱讀的是 contributing,里面有很詳細的步驟告訴你如何開始貢獻代碼,如何把前端本地開發(fā)環(huán)境搭建起來,前后端如何協(xié)調(diào),怎么修改代碼的縮進等等。
根目錄下還有如圖所示的各個文件夾

挑幾個比較重要的來說說,
- superset:后端代碼主要放在這個文件夾中
- superset-frontend: 前端代碼的入口
- superset-websocket:Nodejs websocket相關(guān)
- docker:docker文件,docker的啟動腳本等等
- helm/superset:helm charts 的配置文件,不太了解 helm 的可以看看官方介紹
- requirements:python環(huán)境下,需要安裝的一些第三方包及其版本
- .github:存放github CI/CD 相關(guān)的 workflow 配置,可略過
- RELEASING:存放版本release note
我個人多年來閱讀項目源碼的習慣是先抓住重點,細枝末節(jié)的東西可以以后慢慢一點點補充。一上來不要一下子輸入太多,細節(jié)有時候會把人帶跑。
以上就是比較重要的一些模塊,作為后端開發(fā)(前端我無能為力 ?? ),首先可以看看 superset 文件夾下的代碼。
看源碼的過程建議結(jié)合前端的UI交互、功能來看對應的后端代碼。首先應該自己去上手用一用這款產(chǎn)品,連接一些數(shù)據(jù)庫,建幾張表,最后建幾個dashboard玩一玩,數(shù)據(jù)可視化方面的一些基本知識也需要順便補一補,只有真正成為一個產(chǎn)品的用戶,才會變成一個有心人,發(fā)現(xiàn)很多別人看不到的細節(jié),才有可能做到深入。
后端代碼入口
后端是如何啟動起來的,通過看 Dockerfile 的 entrypoint 或者 CMD

這段代碼可以發(fā)現(xiàn),啟動后端服務(wù)應該是在 ./docker/docker-ci.sh 這個文件里執(zhí)行的,順著這個文件找下去,會發(fā)現(xiàn)最終執(zhí)行的是一個叫 ./docker/run-server.sh 的腳本。

啟動 Superset 后端server的一個命令就是 gunicorn 這一句。gunicorn 要啟動的這個 ${FLASK_APP} 變量通過代碼搜索可以發(fā)現(xiàn)就是 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
這段創(chuàng)建應用的代碼做了幾件事:
- 加載 superset/config.py,也就是說將配置文件加載進來,看過官網(wǎng)的介紹應該也知道默認的配置文件就是這個。
- 調(diào)用 app_initializer 進行一系列的初始化,配置文件里沒有的話,默認就調(diào)用 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 的理解都需要在了解這兩個框架的基礎(chǔ)上。
- 熟悉一些常見的 python package,如 SQLAlchemy,marshmallow,pandas,celery等。
最后
如果你對Superset的代碼或者二次開發(fā)有問題,可以找我咨詢,我組建了免費的社區(qū),大家都很樂于分享。如有需要,看我個人簡介來聯(lián)系我,注明來意~