Superset 源碼分析

我最初接觸 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的方式去增加自己想要的圖表。


gallery.jpeg

代碼目錄介紹

Superset branch 1.5為例,根目錄下通常會(huì)存放一些代碼樣式規(guī)范,git相關(guān)的配置,docker文件,python setup等腳本。還有做開(kāi)源貢獻(xiàn)必須仔細(xì)閱讀的 code of conductcontributing。

這些文件中需要著重閱讀的是 contributing,里面有很詳細(xì)的步驟告訴你如何開(kāi)始貢獻(xiàn)代碼,如何把前端本地開(kāi)發(fā)環(huán)境搭建起來(lái),前后端如何協(xié)調(diào),怎么修改代碼的縮進(jìn)等等。

根目錄下還有如圖所示的各個(gè)文件夾


Screen Shot 2022-05-17 at 23.05.22.png

挑幾個(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

Screen Shot 2022-05-18 at 21.30.27.png

這段代碼可以發(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 的腳本。

Screen Shot 2022-05-18 at 21.36.37.png

啟動(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)意~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容