阿里數據中台核心產品揭秘

2021年10月14日12:33:03 科技 1803

編者按:作為阿里數據中台的核心產品,Quick BI 單一代碼倉庫源碼已經突破了 100萬行,正在向1000萬行邁進。本文重點分享了單一代碼倉庫Monorepo選用前的思考,以及具體應用中的開發體驗和經驗。內容轉載自「Alibaba F2E」。

近年來,阿里數據中台產品發展迅速。核心產品之 Quick BI 連續 2 年成為國內唯一入選 Gartner 魔力象限的國產 BI。Quick BI 單一代碼倉庫源碼突破了 100萬行。整個開發過程涉及到的人員和模塊都很多,因為下文講的一些原則,產品能一直保持在快速的開發狀態。

先分享幾個關鍵數據:

代碼:TypeScript 82萬行,樣式 Sass+Less+CSS 18萬行。(cloc 統計,去除自動生成代碼)

協同:Code Review 12,111 次,Commit 53,026 次。

阿里數據中台核心產品揭秘 - 天天要聞

很多人會問,這麼多代碼,為什麼不切分代碼庫?還不趕快引入微前端、Serverless 框架?你們就不擔心無法維護,啟動龜速嗎?

實際情況是,從第一天開始,就預估到會有這麼大的代碼量。啟動時間也從最初的幾秒鐘到後面越來越慢5~10分鐘,再優化到近期的5秒鐘。整個過程下來,團隊更感受到 Monorepo(單一代碼倉庫)的優勢。

這個實踐想說明:

大的 Codebase 可能是好事情,大道至簡。用極其「簡單」的架構更容易支持複雜靈活的業務

要做到簡單的架構,內部需要更明確的規範,更密切的協同,更高效的執行

能通過工程化解決的問題,就不要通過開發規範,能通過規範來解決的不要靠自由發揮

開工

2019年4月30號,晴朗的下午,剛好是喜迎五一的前一天,發揮集體智慧,投票選出滿意的倉庫名。同時借 Quick BI 和 FBI 底座融合的契機,項目開啟。後來底座代碼轉正,把上層業務代碼也吸納進來。

commit 769bf68c1740631b39dca6931a19a5e1692be48d
Date:   Tue Apr 30 17:48:52 2019 +0800

    A New Era of BI Begins

Why Monorepo?

阿里數據中台核心產品揭秘 - 天天要聞

在開工之前,對單一倉庫(Monorepo)和多倉庫(Polyrepo)團隊內做了很多的討論。

曾經我也很喜歡 Polyrepo,為每個組件建立獨立 repo 獨立 npm,比如2019年前,單是表單類的編輯器組件就有 43 個:

阿里數據中台核心產品揭秘 - 天天要聞

本以為這樣可以做到完美的解耦、極致的復用,但實際上:

每次 Babel、React 等依賴整體升級能讓人脫層皮,所以自研了腳手架。造輪子都是被逼出來的,事情做了一點點,但寫腳本能力直線上升。

每次 調試組件,npm link 一下。後來組件跨級,可以做 3 層 npm link,使用過的都知道這是多麼糟糕的體驗。

版本難對齊,每次主倉庫發布前,組件間版本對齊更是考驗眼力,稍有不慎觸發線上故障。

方便別人復用的優勢呢?最終支持自己業務都捉襟見肘,哪還敢讓別人復用……

最終我們把所有這些組件都合併到一個倉庫,其實像 Google/Facebook/Microsoft 這些公司內部都很推崇 Monorepo。

但我們不是原教旨主義的 Monorepo,沒必要把不相關的產品代碼硬放到一起。在實線團隊內部,單個產品可以使用 Monorepo,會極大降低協同成本。但開始的時候,團隊內還是有很多疑問。

關於 Monorepo 的幾個核心疑問

**單一倉庫,體積會很大吧?**

100 萬行代碼 的體積有多大?

先來猜一下:1GB?10GB?還是更多?

首先,按照公式計算一下:

代碼的體積 = 源碼的體積 + .Git 的體積 + 資源文件(音視頻、圖片、其他文件)

1. 我們一起來算一下源碼的體積:

一般建議每行小於 120 字元,我們取每行 100 個字元來算,100 萬行就是:

100 * 1000,000 = 100,000,000 B
轉換之後就是 100 MB!

那我們的倉庫實際多大呢?

只有 85 MB!也就是平均每行 85 個字元。

2. 再來算一下 .git的體積:

.git里記錄了所有代碼的提交歷史、branch 和 tag 信息。會很大體積吧?

實際上 Git 底層做了很多的優化:1. 所有 branch 和 tag 都是引用;2. 對變更是增量存儲;3. 變更對象存儲的時候會使用 zlib 壓縮。(對於重複出現的樣板代碼只會存儲一次,對於規範化的代碼壓縮比例極高)。

按照我們的經驗,.git記錄 10,000 次 commit 提交只需要額外的 1~3 個代碼體積即可。

3. 資源文件大小

Git 做了很多針對源碼的優化,但視頻和音頻這類資源文件除外。我們最近使用 BFG 把另一個產品的倉庫從 22GB 優化到 200MB,降低 99%!而且優化後代碼的提交歷史和分支都得到了保留(因為 BFG 會編輯 Git 提交記錄,部分 commit id 會變化)。

以前 22 GB 是因為倉庫里存放視頻、發布的 build 文件和 sourcemap 文件,這些都不應該放到源碼倉庫。

小結一下,百萬行代碼體積一般在 200MB ~ 400MB 之間。那來估算下 1000 萬行代碼佔用體積是多少?

乘以十也就是 2GB ~ 4GB 之間。這對比 node_modules隨隨便便幾個 G 來說,並不算什麼,很容易管理。補充個案例,Linux 內核有 2800 萬行,使用 Monorepo,數千人協同。據說當時 Linus 就是為了管理 Linux 的源碼而開發出 Git。

**啟動很慢吧?5分鐘還是10分鐘?**

聽到有些團隊講,代碼十幾萬行,啟動 10+分鐘,典型的「巨石」項目,已經很難維護了。趕緊拆包、或者改微前端。可能團隊才 3 個人卻拆了 5 個項目,協同起來非常麻煩。

我們做法有3個:

按照頁面來拆分多 Entry,每次只需啟動一個 Entry

梳理子包間的依賴關係,追求極致的 Lazy loading,Tree-Shaking

Webpack 切換到 Vite

尤其是 Webpack 切換到 Vite 以後,最終項目冷啟動時間由 2-5分鐘 優化到 5秒 內。熱編譯時間由原來 5秒 優化到 1秒 內,Apple M1 電腦基本都是 500ms 以內。

**代碼復用怎麼辦?Monorepo 復用的時候是否要引入全部?**

傳統的軟體工程思想追求 DRY,但並不是越 DRY 越好。

每寫一行代碼,都產生了相應代價:維護的成本。為了減少代碼,我們有了可復用的模塊。但是代碼復用有一個問題:當你以後想要修改的時候它就會成為一個障礙。

對於像 Quick BI 這樣長期迭代的產品,絕大部分需求都是對原有功能的擴展,所以寫出易維護的代碼最重要。因此,團隊不鼓勵使用 magic 的特技寫法;不單純追求代碼復用率,而是追求更易於修改;鼓勵在未來模塊下線的時候易於刪除的編碼方式。

對於確實存在復用的場景,我們做了拆包。Monorepo 內部我們拆了多個 package(後面有截圖),比如其他產品需要 BI 搭建,可以復用 @alife/bi-designer,並藉助於 Tree-Shaking 做到依賴引入的最小化。

目前的開發體驗

1. 冷啟動 5秒,熱編譯 1秒內。以前是 5~10分鐘。

2. 改一行代碼能解決的問題,真正改一行且發布一次。而不是改 10+ 個項目,按依賴發布 N 次。

3. 新人 10分鐘搭建好環境,上手開發。以前每個組件一個 Repo,包賦權都要搞很久。

4. 避免了版本不對齊的問題

對於 2C 產品,不需要多版本多主幹分支,但多個 npm 依賴對齊版本也不容易

對於 2B 產品,由於多環境、多版本,會更加複雜,複雜度極高。Monorepo 通過分支來統一內部依賴的版本

5. 工程化升級只需要一次。目前是基於 Lerna 開發的 Pri Monorepo 方案。

當然,這裡提及的體驗要保持並不容易,開發中還有很多問題要解決。

真正需要解決的問題

並不是把代碼放到一起就完了,背後複雜的問題是協同、技術方案、穩定性。比如,如何避免一個人提交代碼導致整個產品崩潰?

**包依賴管理**

內部拆分多個子包,每個子包是子文件,可以單獨發布 npm,見下圖:

阿里數據中台核心產品揭秘 - 天天要聞

內部包管理的核心原則是:

從左向右單向依賴,只能右邊引用左邊,避免循環依賴

規範還不夠,開發插件來自動檢測,如果左邊依賴右邊直接報錯

對於開源 npm 的引入,應該更慎重。大部分 npm 的維護時長不超過x年,即使像 Moment.js 這樣曾經標配的工具庫也會終止維護。可能有 20% 的 npm 是沒人維護。但未來如果你的線上用戶遇到問題,你就需要靠自己啃源碼,陷入被動。所以我們的原則是,引入開源 npm 要三人線下評審通過才行。

**Code Review 文化**

互相 Code Review 能幫助新人快速成長,同時也是打造團隊技術文化的方式。

過去幾年一直在團隊內推行 100% CR,但這還不夠。機械的執行很容易把 CR 流於形式,還要分場景來做。

Monorepo 有個風險是一旦有問題就可能是整體的問題。

目前我們的 Code Review 主要分為3個場景:

線上 MR Code Review【1對1】

主題式 Code Review【3-5個人】

大版本發布前集體 Code Review【All】

12,111 次 Code Review 的經驗很多,主要是:

及時 Review,鼓勵小顆粒度的 MR,不必等整個功能開發完成

代碼是寫給人看的,鼓勵白話文一樣的代碼,而不是文言文

建立最佳實踐(目錄樹結構、命名規範、數據流規範)。開發一個功能可以有 10 種方法,但團隊需要選 1 種並推廣

不鼓勵炫技,為了未來可維護性。能用簡單技術實現,不要用「高深」冷門的技術

強調開發潔癖,追求優雅代碼的文化(命名是否易於理解、注釋是否完整、是否有性能隱患等)

**工程化建設**

這個過程首先要感謝淘系前端 DEF 工程化團隊的支持,在這麼多代碼的情況下,不斷挑戰極限升級 DEF 支持我們。

除了制定文檔的規範之外,能夠自動化工具檢查的規範才是好規範。

檢查器:ESLint、TS 類型校驗、Prettier

語法檢查器是推動規範落地的重要方法,ESLint 可以做增量,優化後 git commit 的 pre-hooks 依舊很快。但 TS type check 因為不支持增量就比較慢了,需要搭配 CI/CD 來使用。

Webpack vs Vite

發布使用 Webpack,開發使用 Vite。

開發環境使用 Vite 快速調試,生產環境依舊使用 Webpack 打包。

風險是開發和生產編譯產物不一致,這一塊需要上線前回歸測試避免。

**性能優化**

對於數據產品而言,性能的挑戰除了來自於 Monorepo 後資源包的變大,還有大數據量對渲染計算帶來的挑戰。

性能優化可以分為3個環節:

資源載入:精細化 Tree Shaking,難在精細。Webpack 本身的 Tree-Shaking 做的並不好,不支持 Class method 做 Tree Shaking,所以有時候需要修改代碼。Lazy Loading 模塊做到按需載入,尤其是圖表、SQL 編輯器這類大組件。合理的介面預載入,不要讓網路閑下來。

視圖渲染:讓組件渲染次數降到最低,表格類組件虛擬滾動優化,閑時預載入預渲染。

取數請求:資源本地化緩衝方案,移動端使用 PWA 將 JS 等資源文件和數據緩存到本地。

另外還有性能檢測工具,定位性能卡點。計劃做代碼性能門閂,代碼提交前如果發現包體積增大發出提醒。

**數據化驅動架構優化**

身在數據中台,我對數據的業務價值深信不疑。但對於開發本身而言,很少深度使用過數據。

所以 S1 重點探索了開發體驗的數字化。通過採集大家的開發環境和啟動耗時數據來做分析【不統計其他數據避免內卷】。發現很多有意思的事情,比如有個同學熱編譯 3~5 分鐘,他以為別人也是這樣慢,嚴重影響了開發效率,當從報表發現數據異常後十分鐘幫他解決。

另外一個例子,為了保持線上打包產物的一致性,推動團隊做 Node.js 版本統一,以前都是靠釘,釘多少次都無法知道效果如何。有了報表以後就一目了然。

阿里數據中台核心產品揭秘 - 天天要聞

目前整個數據化的流程跑通,初步嘗到甜頭。未來還有很多好玩的分析可以做。

更深層的經驗

**效率最高的方式就是一次做好**

每行代碼都會留下成本。長遠考慮,效率最高的方法就是一次做好。

蘇世民說「做大事和做小事的難度是一樣的,兩者都會消耗你的時間和精力。」既然如此,不妨把代碼一次寫好。代碼中如果遺留 「TODO」 可能就永遠 TO DO。客觀來講,一次做好比較難,首先是每個人認為的「好」標準不同,背後是個人的技術能力、體驗的追求、業務的理解。

**組織文化技術,相輔相成**

技術架構和組織結構有很大關係,選擇適合組織的技術架構更重要。

如果一個組織是分散的,使用 Monorepo 會有很大的協同成本。但組織如果是內聚的,Monorepo 能極大提效。

工程化和架構底座是團隊的事情,靠個人很難去推動。

短期可以靠戰役靠照搬,長期要形成文化才能持續迭代。

組織溝通成本高應該通過組織來解,通過技術來解的力量是渺小的。技術可以做的是充分發揮工具的優勢,讓變化快速發生。

**簡單不先於複雜,而是在複雜之後**

對於一個簡單的架構,總有人會想辦法把它做複雜。踩了坑,下決心重構,成功則回歸簡單,失敗就會被新的簡單模式顛覆。踩坑本身也是有價值的,不然新人總是按捺不住還會再踩一次。做複雜很容易,但保持簡單需要遠見和剋制。沒有經歷過過程的磨練,別人的解藥對你可能是毒藥。

架構不可能一成不變的,我們的圖表最開始直接使用 D3、ECharts 很簡單,後來定製很多逐漸複雜到難以維護,於是基於 G2 自研 bi-charts 後架構又一次變簡單,前後的開發體驗可能是差不多的,但背後的技術完全變了。

總結與展望

百萬行代碼沒什麼可怕,是一個正常的節點,仍然可以像幾萬行代碼那樣敏捷。

現在 Quick BI 已經向千萬行邁進,向世界一流 BI 的目標邁進。以上內容更多是工程化相關,把工程化做好目的是想讓開發者更專註於業務,沒講的業務挑戰其實更多,因為數據分析天生就要與海量數據打交道,性能優化有長期的實踐;洞察豐富異樣的數據,有很多可視化及複雜表格方面的沉澱,可視化不僅是技術,也是業務本身;手機平板電視等多端展示,跨端適配的挑戰。

未來還希望能夠把數據分析打造成一個引擎,能夠快速集成到辦公和商業流程中。

目前的開發模式並不完美,在迭代的過程中,不可避免會產生技術債,架構的優化本質就是在保持可維護性和減少技術債。最近團隊在醞釀一次 Redux-Toolkit 的引入,會對取數和數據流有大的升級,有進展再分享。(完)

阿里數據中台核心產品揭秘

科技分類資訊推薦

App能「取現」能「代還」?小心非法套現危及個人信息安全 - 天天要聞

App能「取現」能「代還」?小心非法套現危及個人信息安全

如果有這樣一款App,簡單操作幾下就能讓你的信用卡額度提現到自己的儲蓄卡內,甚至動動手指就能讓信用卡的還款日推遲到下個周期,聽上去是不是非常有誘惑力?然而,其中卻暗藏著巨大的陷阱和風險。2023年7月,湖南汨羅警方破獲一起信用卡非法套現案,抓獲涉案人員19人,查明套現金額約40億元,非法獲利約1.2億元。目前,這...
珂芝 K98 機械鍵盤開售:Leaf-Spring Gasket 結構,279 元起 - 天天要聞

珂芝 K98 機械鍵盤開售:Leaf-Spring Gasket 結構,279 元起

IT之家 5 月 19 日消息,珂芝 K98 機械鍵盤目前已經在京東現貨開售,這款鍵盤主打「Leaf-Spring Gasket 結構」,可選極地雪 / 沙漠綠洲 / 星岩灰色(價格取決於軸體),IT之家整理價格信息如下:彩虹軸:279 元風雨軸:299 元波塞冬軸:369 元據介紹,這款機械鍵盤外殼採用厚膠位注塑工藝,鍵盤背部擁有 3D 冰晶紋裝飾,裸..
全球第一款!中國公司泄露Intel二代酷睿Ultra掌機 - 天天要聞

全球第一款!中國公司泄露Intel二代酷睿Ultra掌機

快科技5月19日消息,Intel預計會在馬上到來的台北電腦展上公開下一代酷睿Ultra處理器Arrow Lake、Lunar Lake的更多具體信息,而來自我國深圳的微步公司,第一家公布了基於Lunar Lake的掌機,將在本次展會上首次亮相。這款掌機名為「GP10」,採用10.95英寸大屏,解析度1920x1200,刷新率120Hz,支持觸摸。內存容量16
海信推出 Vidda NEW S100 Pro 電視:100 英寸 192 分區,8999 元 - 天天要聞

海信推出 Vidda NEW S100 Pro 電視:100 英寸 192 分區,8999 元

IT之家 5 月 19 日消息,海信今天在京東上架一款 Vidda NEW S100 Pro 電視,這款電視主打「100 英寸 144Hz」,不過僅有 192 分區,該電視將於 5 月 21 日凌晨 0 點開售,首發價 8999 元。據介紹,這款電視配備 3840 x 2160 解析度 144Hz 面板,擁有 192 分區,覆蓋 85% DCI-P3 色域,
中核集團:全國最大海上光伏電站開工建設,2025 年全容量併網 - 天天要聞

中核集團:全國最大海上光伏電站開工建設,2025 年全容量併網

IT之家 5 月 19 日消息,據中核集團消息,5 月 19 日,我國最大的海上光伏項目 —— 中核田灣 200 萬千瓦灘涂光伏示範項目在江蘇連雲港正式開工建設。▲ 圖源中核集團公眾號,下同據介紹,項目預計於 2024 年 9 月首次併網,2025 年全容量併網,在運行期 25 年內年平均上網電量 22.34 億千瓦時,能夠滿足中等發達國家約 23...
長治振興小鎮「研學熱」持續升溫 「教育+科技」是亮點 - 天天要聞

長治振興小鎮「研學熱」持續升溫 「教育+科技」是亮點

田小麗立夏之後,暑氣漸顯。長治振興小鎮「研學熱」持續升溫,研學團接踵而至。5月11日,來自長治市實驗小學的學生走進振興小鎮,開展「感觸科技魅力 體驗非遺傳承」趣味研學游活動。5月18日,長治市平順縣苗庄中心校、北社中心校研學團隊走進振興小鎮開展「紅色教育點亮心燈 勞動實踐助力成長」研學游活動。……科技創新、...