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

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

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

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

啟動(dòng) Superset 后端server的一個(gè)命令就是 gunicorn 這一句。gunicorn 要啟動(dòng)的這個(gè) ${FLASK_APP} 變量通過(guò)代碼搜索可以發(fā)現(xiàn)就是 FLASK_APP="superset.app:create_app()"
它所對(duì)應(yīng)的方法就是 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)建應(yīng)用的代碼做了幾件事:
- 加載 superset/config.py,也就是說(shuō)將配置文件加載進(jìn)來(lái),看過(guò)官網(wǎng)的介紹應(yīng)該也知道默認(rèn)的配置文件就是這個(gè)。
- 調(diào)用 app_initializer 進(jìn)行一系列的初始化,配置文件里沒(méi)有的話(huà),默認(rèn)就調(diào)用 SupersetAppInitializer.init_app() 方法
- 這個(gè) init_app() 里面又處理了很多初始化的工作,比如 setup database, configure celery, config cache 等等
- 最重要的還有一個(gè) 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()
這個(gè)方法很重要,因?yàn)?Superset 后端是用 Flask + FlaskAppBuilder 這兩個(gè)框架去寫(xiě)的,因此需要初始化一些 FlaskAppBuilder 的 views,API,links 等等。
到此為止,整個(gè)后端代碼的入口介紹就差不多了,后端核心的代碼放在 superset 文件夾中,通過(guò)文件夾的命名,也能夠看到大致的端倪。
這個(gè)看代碼入口的方法套到其他的開(kāi)源項(xiàng)目也是適用的哦,這是一個(gè)屢試不爽的好方法。
如何上手代碼
想要更好地理解 Superset 的代碼,你還需要做一些額外的準(zhǔn)備:
- 熟悉 Python 語(yǔ)言,了解一些常見(jiàn)的語(yǔ)法糖,語(yǔ)言的特性。這樣看到報(bào)錯(cuò)信息可以幫助更好地定位問(wèn)題,而不是一頭霧水。
- 熟悉 Flask 和 FlaskAppBuilder 框架,因?yàn)?Superset 的后端 API,views,models 的理解都需要在了解這兩個(gè)框架的基礎(chǔ)上。
- 熟悉一些常見(jiàn)的 python package,如 SQLAlchemy,marshmallow,pandas,celery等。
最后
如果你對(duì)Superset的代碼或者二次開(kāi)發(fā)有問(wèn)題,可以找我咨詢(xún),我組建了免費(fèi)的社區(qū),大家都很樂(lè)于分享。如有需要,看我個(gè)人簡(jiǎn)介來(lái)聯(lián)系我,注明來(lái)意~