![]()
作者 | Sergio De Simone
譯者 | 平川
在 5 年時間里,Datadog Agent 從 428 MiB 增長到了 1.22 GiB。Datadog 工程師們開始著手縮減其二進制文件的大小。他們 發現,對于大多數 Go 二進制文件,膨脹的主要原因是隱藏的依賴項、禁用的鏈接器優化以及 Go 編譯器和鏈接器中的微妙行為。
不管是對于我們自己,還是對于我們的用戶,這種增長都產生了不利的影響:網絡成本和資源使用增加,Agent 感知變差,并且在資源受限的平臺上使用 Agent 變得更加困難。
Datadog 軟件工程師 Pierre Gimalac 寫道,為了解決這個問題,他們采取了一些措施,以便盡可能地縮小二進制文件的大小,其中包括:審計導入項、隔離可選代碼以及消除反射 / 插件陷阱。
實際上,在分析了 Agent 的增長情況后,Datadog 工程師發現,這主要是由新功能、額外的集成和大型第三方依賴項(如 Kubernetes SDK)引起的。特別是,Go 的依賴模型包括傳遞性導入,使得即使是一個小的變化也可能引入數百個包。
Datadog 工程師設計了兩種實用的方法來移除不必要的依賴項:使用構建標簽(//go:build feature_x)來排除可選代碼,并將代碼移到單獨的包中,從而使非可選包盡可能保持小巧。這兩種技術都需要系統地審計導入項,以便確定哪些文件或包可以從給定的構建中排除。例如,僅僅將一個函數移動到它自己的包中,就從一個不使用它的二進制文件中移除了約 570 個包和約 36 MB 的生成代碼。
審計依賴項并不是一項簡單的任務,但 Go 生態系統提供了三個有用的工具:go list,可以列出構建中使用的所有包;goda,可以可視化依賴圖和導入鏈,幫助開發人員理解為什么需要某個特定的依賴項;go-size-analyzer,可以顯示每個依賴項使二進制文件的空間占用增加了多少。
除了優化依賴項外,通過最小化反射機制的使用,Datadog 工程師額外獲得了 20% 的大小縮減。反射會悄悄地禁用一些鏈接器優化,包括死代碼消除:
如果你使用非恒定方法名,那么鏈接器在構建時就無法知道哪些方法將在運行時被使用。因此,它需要保留每個可達類型的每個導出方法,以及它們所依賴的所有符號,這可能會大幅增加最終二進制文件的大小。
為了解決這個問題,他們盡可能地消除了動態反射,無論是在他們的代碼庫中還是在依賴項中。后一步驟需要向 kubernetes/kubernetes、uber-go/dig、google/go-cmp 等項目提交多個 PR。
另一個禁用死代碼消除的功能是 Go 插件(一種允許 Go 程序在運行時動態加載 Go 代碼的機制)。實際上,僅僅導入 plugin 包就導致鏈接器將二進制文件視為動態鏈接的,“這會禁用方法死代碼消除,甚至迫使鏈接器保留所有未導出的方法”。在部分構建中,這一變化額外帶來了約 20% 的縮減。
最后,Gimalac 強調,這些改進是在六個月的時間里實現的。最重要的是,沒有移除任何功能。他的文章里提供了更多的細節,如果想了解整個事情的來龍去脈,請閱讀原博文。
https://www.infoq.com/news/2026/03/datadog-go-binary-optimization/
聲明:本文為 InfoQ 翻譯,未經許可禁止轉載。
特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.