0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

揭秘Google和Facebook不用Docker的原因

Linux愛好者 ? 來源:51cto博客 ? 作者:51cto博客 ? 2021-06-26 15:37 ? 次閱讀

寫作本文的起因是我想讓修改后的分布式 PyTorch 程序能更快的在 Facebook 的集群上啟動(dòng)。探索過程很有趣,也展示了工業(yè)機(jī)器學(xué)習(xí)需要的知識(shí)體系。

2007 年我剛畢業(yè)后在 Google 工作過三年。當(dāng)時(shí)覺得分布式操作系統(tǒng) Borg 真好用。

從 2010 年離開 Google 之后就一直盼著它開源,直到 Kubernetes 的出現(xiàn)。

Kubernetes 調(diào)度的計(jì)算單元是 containers(準(zhǔn)確的翻譯是“集裝箱”,而不是意思泛泛的“容器”,看看 Docker 公司的 Logo 上畫的是啥就知道作者的心意了)。

而一個(gè) container 執(zhí)行一個(gè) image,就像一個(gè) process 執(zhí)行一個(gè) program。

無論 Googlers 還是 ex-Googlers,恐怕在用 Borg 的時(shí)候都未曾接觸過 container 和 image 這兩個(gè)概念。為啥 Borg 里沒有,而 Kubernetes 卻要引入了這樣兩個(gè)概念呢?

這個(gè)曾經(jīng)問題在我腦海中一閃而過就被忽略了。畢竟后來我負(fù)責(zé)開源項(xiàng)目比較多,比如百度 Paddle 以及螞蟻的 SQLFlow 和 ElasticDL,Docker 用起來很順手。于是也就沒有多想。

今年(2021 年)初,我加入 Facebook。恰逢 Facebook 發(fā)論文[1]介紹了其分布式集群管理系統(tǒng) Tupperware。

不過 Tupperware 是一個(gè)注冊(cè)于 1946 年的品牌 https://en.wikipedia.org/wiki/Tupperware_Brands,所以在論文里只好起了另一個(gè)名字 Twine。

因?yàn)樾袠I(yè)里知道 Tupperware 這個(gè)名字的朋友很多,本文就不說 Twine 了。

總之,這篇論文的發(fā)表又引發(fā)了我對(duì)于之前問題的回顧——Facebook 里也沒有 Docker!

和 Facebook Tuppware 團(tuán)隊(duì)以及 Google Borg 幾位新老同事仔細(xì)聊了聊之后,方才恍然。因?yàn)樾袠I(yè)里沒有看到相關(guān)梳理,本文是為記錄。

一言蔽之

簡(jiǎn)單的說,如果用 monolithic repository 來管理代碼,則不需要 Docker image(或者 ZIP、tarball、RPM、deb)之類的“包”。

所謂 monolithic repo 就是一家公司的所有項(xiàng)目的所有代碼都集中放在一個(gè)(或者極少數(shù))repo 里。

因?yàn)?monolithic repository 得有配套的統(tǒng)一構(gòu)建系統(tǒng)(build system)否則編譯不動(dòng)那么老大一坨代碼。

而既然有統(tǒng)一的 build system,一旦發(fā)現(xiàn)某個(gè)集群節(jié)點(diǎn)需要執(zhí)行的程序依賴的某個(gè)模塊變化了,同步這個(gè)模塊到此節(jié)點(diǎn)既可。完全不需要打包再同步。

反之,如果每個(gè)項(xiàng)目在一個(gè)獨(dú)立的 git/svn repo 里,各自用不同的 build system,比如各個(gè)開源項(xiàng)目在不同的 GitHub repo 里,則需要把每個(gè)項(xiàng)目 build 的結(jié)果打包。

而 Docker image 這樣支持分層的包格式讓我們只需要傳輸那些容納被修改的項(xiàng)目的最上面幾層,而盡量復(fù)用被節(jié)點(diǎn) cache 了的下面的幾層。

Google 和 Facebook 都使用 monolithic repository,也都有自己的 build systems(我這篇老文尋找 Google Blaze[2] 解釋過 Google 的 build system)所以不需要“包”,當(dāng)然也就不需要 Docker images。

不過 Borg 和 Tupperware 都是有 container 的(使用 Linux kernel 提供的一些 system calls,比如 Google Borg 團(tuán)隊(duì)十多年前貢獻(xiàn)給 Linux kernel 的 cgroup)來實(shí)現(xiàn) jobs 之間的隔離。

只是因?yàn)槿绻恍枰蠹?build Docker image 了,那么 container 的存在就不容易被關(guān)注到了。

如果不想被上述蔽之,而要細(xì)究這個(gè)問題,那就待我一層一層剝開 Google 和 Facebook 的研發(fā)技術(shù)體系和計(jì)算技術(shù)體系。

Packaging

當(dāng)我們提交一個(gè)分布式作業(yè)(job)到集群上去執(zhí)行,我們得把要執(zhí)行的程序(包括一個(gè)可執(zhí)行文件以及相關(guān)的文件,比如 *.so,*.py)傳送到調(diào)度系統(tǒng)分配給這個(gè) job 的一些機(jī)器(節(jié)點(diǎn)、nodes)上去。

這些待打包的文件是怎么來的呢?當(dāng)時(shí)是 build 出來的。在 Google 里有 Blaze,在 Facebook 里有 Buck。

感興趣的朋友們可以看看 Google Blaze 的“開源版本”Bazel[3],以及 Facebook Buck 的開源版本[4]。

不過提醒在先:Blaze 和 Facebook Buck 的內(nèi)部版都是用于 monolithic repo 的,而開源版本都是方便大家使用非 mono repos 的,所以理念和實(shí)現(xiàn)上有不同,不過基本使用方法還是可以感受一下的。

假設(shè)我們有如下模塊依賴(module dependencies),用 Buck 或者 Bazel 語(yǔ)法描述(兩者語(yǔ)法幾乎一樣):

python_binary(name=“A”, srcs=[“A.py”], deps=[“B”, “C”], 。。.)

python_library(name=“B”, srcs=[“B.py”], deps=[“D”], 。。.)

python_library(name=“C”, srcs=[“C.py”], deps=[“E”], 。。.)

cxx_library(name=“D”, srcs=[“D.cxx”, “D.hpp”], deps=“F”, 。。.)

cxx_library(name=“E”, srcs=[“E.cxx”, “E.hpp”], deps=“F”, 。。.)

那么模塊(build 結(jié)果)依賴關(guān)系如下:

A.py --》 B.py --》 D.so -

-》 C.py --》 E.so --》 F.so

如果是開源項(xiàng)目,請(qǐng)自行腦補(bǔ),把上述模塊(modules)替換成 GPT-3,PyTorch,cuDNN,libc++ 等項(xiàng)目(projects)。

當(dāng)然,每個(gè) projects 里包含多個(gè) modules 也依賴其他 projects,就像每個(gè) module 有多個(gè)子 modules 一樣。

Tarball

最簡(jiǎn)單的打包方式就是把上述文件 {A,B,C}.py, {D,E,F(xiàn)}.so 打包成一個(gè)文件 A.zip,或者 A.tar.gz。

更嚴(yán)謹(jǐn)?shù)恼f,文件名里應(yīng)該包括版本號(hào)。比如 A-953bc.zip,其中版本號(hào) 953bc 是 git/Mercurial commit ID。

引入版本號(hào),可以幫助在節(jié)點(diǎn)本地 cache,下次運(yùn)行同一個(gè) tarball 的時(shí)候,就不需要下載這個(gè)文件了。

請(qǐng)注意這里我引入了 package caching 的概念。為下文解釋 Docker 預(yù)備。

XAR

ZIP 或者 tarball 文件拷貝到集群節(jié)點(diǎn)上之后,需要解壓縮到本地文件系統(tǒng)的某個(gè)地方,比如:/var/packages/A-953bc/{A,B,C}.py,{D,E,F(xiàn)}.so。

一個(gè)稍顯酷炫的方式是不用 Tarball,而是把上述文件放在一個(gè) overlay filesystem 的 loopback device image 里。這樣“解壓”就變成了“mount”。

請(qǐng)注意這里我引入了 loopback device image 的概念。為下文解釋 Docker 預(yù)備。

什么叫 loopback device image 呢?在 Unix 里,一個(gè)目錄樹的文件們被稱為一個(gè)文件系統(tǒng)(filesystem)。

通常一個(gè) filesystem 存儲(chǔ)在一個(gè) block device 上。什么是 block device 呢?

簡(jiǎn)單的說,但凡一個(gè)存儲(chǔ)空間可以被看作一個(gè) byte array 的,就是一個(gè) block device。

比如一塊硬盤就是一個(gè) block device。在一個(gè)新買的硬盤里創(chuàng)建一個(gè)空的目錄樹結(jié)構(gòu)的過程,就叫做格式化(format)。

既然 block device 只是一個(gè) byte array,那么一個(gè)文件不也是一個(gè) byte array 嗎?

是的!在 Unix 的世界里,我們完全可以創(chuàng)建一個(gè)固定大小的空文件(用 truncate 命令),然后“格式化”這個(gè)文件,在里面創(chuàng)建一個(gè)空的文件系統(tǒng)。然后把上述文件 {A,B,C}.py,{D,E,F(xiàn)}.so 放進(jìn)去。

比如 Facebook 開源的 XAR 文件[5]格式。這是和 Buck 一起使用的。

如果我們運(yùn)行 buck build A 就會(huì)得到 A.xar 。 這個(gè)文件包括一個(gè) header,以及一個(gè) squashfs loopback device image,簡(jiǎn)稱 squanshfs image。

這里 squashfs 是一個(gè)開源文件系統(tǒng)。感興趣的朋友們可以參考這個(gè)教程[6],創(chuàng)建一個(gè)空文件,把它格式化成 squashfs,然后 mount 到本地文件系統(tǒng)的某個(gè)目錄(mount point)里。

待到我們 umount 的時(shí)候,曾經(jīng)加入到 mount point 里的文件,就留在這個(gè)“空文件”里了。

我們可以把它拷貝分發(fā)給其他人,大家都可以 mount 之,看到我們加入其中的文件。

因?yàn)?XAR 是在 squashfs image 前面加上了一個(gè) header,所以沒法用 mount -t squashf 命令來 mount,得用 mount -t xar 或者 xarexec -m 命令。

比如,一個(gè)節(jié)點(diǎn)上如果有了 /packages/A-953bc.xar,我們可以用如下命令看到它的內(nèi)容,而不需要耗費(fèi) CPU 資源來解壓縮:

xarexec -m A-953bc.xar

這個(gè)命令會(huì)打印出一個(gè)臨時(shí)目錄,是 XAR 文件的 mount point。

分層

如果我們現(xiàn)在修改了 A.py,那么不管是 build 成 tarball 還是 XAR,整個(gè)包都需要重新更新。

當(dāng)然,只要 build system 支持 cache,我們是不需要重新生成各個(gè) *.so 文件的。

但是這個(gè)不解決我們需要重新分發(fā) .tar.gz 和 .xar 文件到集群的各個(gè)節(jié)點(diǎn)的麻煩。

之前節(jié)點(diǎn)上可能有老版本的 A-953bc87fe.{tar.gz,xar} 了,但是不能復(fù)用。為了復(fù)用 ,需要分層。

對(duì)于上面情況,我們可以根據(jù)模塊依賴關(guān)系圖,構(gòu)造多個(gè) XAR 文件。

A-953bc.xar --》 B-953bc.xar --》 D-953bc.xar -

-》 C-953bc.xar --》 E-953bc.xar --》 F-953bc.xar

其中每個(gè) XAR 文件里只有對(duì)應(yīng)的 build rule 產(chǎn)生的文件。比如,F(xiàn)-953bc.xar 里只有 F.so。

這樣,如果我們只修改了 A.py,則只有 A.xar 需要重新 build 和傳送到集群節(jié)點(diǎn)上。這個(gè)節(jié)點(diǎn)可以復(fù)用之前已經(jīng) cache 了的 {B,C,D,E,F(xiàn)}-953bc.xar 文件。

假設(shè)一個(gè)節(jié)點(diǎn)上已經(jīng)有 /packages/{A,B,C,D,E,F(xiàn)}-953bc.xar,我們是不是可以按照模塊依賴順序,運(yùn)行 xarexec -m 命令,依次 mount 這些 XAR 文件到同一個(gè) mount point 目錄,既可得到其中所有的內(nèi)容了呢?

很遺憾,不行。因?yàn)楹笠粋€(gè) xarexec/mount 命令會(huì)報(bào)錯(cuò) —— 因?yàn)檫@個(gè) mount point 已經(jīng)被前一個(gè) xarexec/mount 命令占據(jù)了。

下面解釋為什么文件系統(tǒng) image 優(yōu)于 tarball。

那退一步,不用 XAR 了,用 ZIP 或者 tar.gz 不行嗎?可以,但是慢。我們可以把所有 .tar.gz 都解壓縮到同一個(gè)目錄里。

但是如果 A.py 更新了,我們沒法識(shí)別老的 A.py 并且替換為新的,而是得重新解壓所有 .tar.gz 文件,得到一個(gè)新的文件夾。而重新解壓所有的 {B,C,D,E,F(xiàn)}.tar.gz 很慢。

Overlay Filesystem

有一個(gè)申請(qǐng)的開源工具 fuse-overlayfs。它可以把幾個(gè)目錄“疊加”(overlay)起來。

比如下面命令把 /tmp/{A,B,C,D,E,F(xiàn)}-953bc 這幾個(gè)目錄里的內(nèi)容都“疊加”到 /pacakges/A-953bc 這個(gè)目錄里。

fuse-overlayfs -o

lowerdir=“/tmp/A-953bc:/tmp/B-953bc:。。.”

/packages/A-953bc

而 /tmp/{A,B,C,D,E,F(xiàn)}-953bc 這幾個(gè)目錄來自 xarcexec -m /packages/{A,B,C,D,E,F(xiàn)}-953bc.xar。

請(qǐng)注意這里我引入了 overlay filesystem 的概念。為下文解釋 Docker 預(yù)備。fuse-overlayfs 是怎么做到這一點(diǎn)的呢?

當(dāng)我們?cè)L問任何一個(gè)文件系統(tǒng)目錄,比如 /packages/A 的時(shí)候,我們使用的命令行工具(比如 ls )調(diào)用 system calls(比如 open/close/read/write) 來訪問其中的文件。

這些 system calls 和文件系統(tǒng)的 driver 打交道 —— 它們會(huì)問 driver:/packages/A 這個(gè)目錄里有沒有一個(gè)叫 A.py 的文件呀?

如果我們使用 Linux,一般來說,硬盤上的文件系統(tǒng)是 ext4 或者 btrfs。也就是說,Linux universal filesystem driver 會(huì)看看每個(gè)分區(qū)的文件系統(tǒng)是啥,然后把 system call 轉(zhuǎn)發(fā)給對(duì)應(yīng)的 ext4/btrfs driver 去處理。

一般的 filesystem drivers 和其他設(shè)備的 drivers 一樣運(yùn)行在 kernel mode 里。

這是為什么一般我們運(yùn)行 mount 和 umount 這類操作 filesystems 的命令的時(shí)候,都需要 sudo。而 FUSE 是一個(gè)在 userland 開發(fā) filesystem driver 的庫(kù)。

fuse-overlayfs 這命令利用 FUSE 這個(gè)庫(kù),開發(fā)了一個(gè)運(yùn)行在 userland 的 fuse-overlayfs driver。

當(dāng) ls 命令詢問這個(gè) overlayfs driver /packages/A-953bc 目錄里有啥的時(shí)候,這個(gè) fuse-overlayfs driver 記得之前用戶運(yùn)行過 fuse-overlayfs 命令把 /tmp/{A,B,C,D,E}-953bc 這幾個(gè)目錄給疊加上去過,所以它返回這幾個(gè)目錄里的文件。

此時(shí),因?yàn)?/tmp/{A,B,C,D,E}-953bc 這幾個(gè)目錄其實(shí)是 /packages/{A,B,C,D,E,F(xiàn)}-953bc.xar 的 mount points,所以每個(gè) XAR 就相當(dāng)于一個(gè) layer。

像 fuse-overlayfs driver 這樣實(shí)現(xiàn)把多個(gè)目錄“疊加”起來的 filesystem driver 被稱為 overlay filesystem driver,有時(shí)簡(jiǎn)稱為 overlay filesystems。

Docker Image and Layer

上面說到用 overlay filesystem 實(shí)現(xiàn)分層。用過 Docker 的人都會(huì)熟悉一個(gè) Docker image 由多層構(gòu)成。

當(dāng)我們運(yùn)行 docker pull 《image-name》 命令的時(shí)候,如果本機(jī)已經(jīng) cache 了這個(gè) image 的一部分 layers,則省略下載這些 layers。這其實(shí)就是用 overlay filesystem 實(shí)現(xiàn)的。

Docker 團(tuán)隊(duì)開發(fā)了一個(gè) filesystem(driver)叫做 overlayfs —— 這是一個(gè)特定的 filesystem 的名字。

顧名思義,Docker overlayfs 也實(shí)現(xiàn)了“疊加”(overlay)的能力,這就是我們看到每個(gè) Docker image 可以有多個(gè) layers 的原因。

Docker 的 overlayfs 以及它的后續(xù)版本 overlayfs2 都是運(yùn)行在 kernel mode 里的。

這也是 Docker 需要機(jī)器的 root 權(quán)限的原因之一,而這又是 Docker 被詬病容易導(dǎo)致安全漏斗的原因。

有一個(gè)叫 btrfs 的 filesystem,是 Linux 世界里最近幾年發(fā)展很迅速的,用于管理硬盤效果很好。

這個(gè) filesystem 的 driver 也支持 overlay。所以 Docker 也可以被配置為使用這個(gè) filesystem 而不是 overlayfs。

不過只有 Docker 用戶的電腦的 local filesystem 是 btrfs 的時(shí)候,Docker 才能用 btrfs 在上面疊加 layers。

所以說,如果你用的是 macOS 或者 Windows,那肯定沒法讓 Docker 使用 btrfs 了。

不過如果你用的是 fuse-overlayfs,那就是用了一副萬靈藥了。只是通過 FUSE 在 userland 運(yùn)行的 filesystem 的性能很一般,不過本文討論的情形對(duì)性能也沒啥需求。

其實(shí) Docker 也可以被配置使用 fuse-overlayfs。Docker 支持的分層 filesystem 列表在這里 Docker storage drivers[7]。

為什么需要 Docker Image

總結(jié)上文所述,從編程到可以在集群上跑起來,我們要做幾個(gè)步驟:

編譯:把源碼編譯成可執(zhí)行的形式。

打包:把編譯結(jié)果納入一個(gè)“包”里,以便部署和分發(fā)

傳輸:通常是集群管理系統(tǒng)(Borg、Kubernetes、Tupperware 來做)。如果要在某個(gè)集群節(jié)點(diǎn)上啟動(dòng) container,則需要把“包”傳輸?shù)酱斯?jié)點(diǎn)上,除非這個(gè)節(jié)點(diǎn)曾經(jīng)運(yùn)行過這個(gè)程序,已經(jīng)有包的 cache。

解包:如果“包”是 tarball 或者 zip,到了集群節(jié)點(diǎn)上之后需要解壓縮;如果“包”是一個(gè) filesystem image,則需要 mount。

把源碼分成模塊,可以讓編譯這步充分利用每次修改只改動(dòng)一小部分代碼的特點(diǎn),只重新編譯被修改的模塊,從而節(jié)省時(shí)間。

為了節(jié)省 2,3 和 4 的時(shí)間,我們希望“包”是分層的。每一層最好只包含一個(gè)或者幾個(gè)代碼模塊。這樣,可以利用模塊之間的依賴關(guān)系,盡量復(fù)用容納底層模塊的“層”。

在開源的世界里,我們用 Docker image 支持分層的特點(diǎn),一個(gè)基礎(chǔ)層可能只包括某個(gè) Linux distribution(比如 CentOS)的 userland programs,如 ls、cat、grep 等。

在其上,可以有一個(gè)層包括 CUDA。再其上安裝 Python 和 PyTorch。再再之上的一層里是 GPT-3 模型的訓(xùn)練程序。

這樣,如果我們只是修改了 GPT-3 訓(xùn)練程序,則不需要重新打包和傳輸下面三層。

這里的邏輯核心是:存在“項(xiàng)目”(project)的概念。每個(gè)項(xiàng)目可以有自己的 repo,自己的 building system(GNU make、CMake、Buck、Bazel 等),自己的發(fā)行版本(release)。

所以每個(gè)項(xiàng)目的 release 裝進(jìn) Docker image 的一層 layer。與其前置多層合稱為一個(gè) image。

為什么 Google 和 Facebook 不需要 Docker

經(jīng)過上述這么多知識(shí)準(zhǔn)備,請(qǐng)我們終于可以點(diǎn)題了。

因?yàn)?Google 和 Facebook 使用 monolithic repository,使用統(tǒng)一的 build system(Google Blaze 或者 Facebook Buck)。

雖然也可以利用“項(xiàng)目”的概念,把每個(gè)項(xiàng)目的 build result 裝入 Docker image 的一層。但是實(shí)際上并不需要。

利用 Blaze 和 Buck 的 build rules 定義的模塊,以及模塊之間依賴關(guān)系,我們可以完全去打包和解包的概念。

沒有了包,當(dāng)然就不需要 zip、tarball、以及 Docker image 和 layers 了。

直接把每個(gè)模塊當(dāng)做一個(gè) layer 既可。如果 D.so 因?yàn)槲覀冃薷牧?D.cpp 被重新編譯,那么只重新傳輸 D.so 既可,而不需要去傳輸一個(gè) layer 其中包括 D.so。

于是,在 Google 和 Facebook 里,受益于 monolithic repository 和統(tǒng)一的 build 工具。

我們把上述四個(gè)步驟省略成了兩個(gè):

編譯:把源碼編譯成可執(zhí)行的形式。

傳輸:如果某個(gè)模塊被重新編譯,則傳輸這個(gè)模塊。

Google 和 Facebook 沒在用 Docker

上一節(jié)說了 monolithic repo 可以讓 Google 和 Facebook 不需要 Docker image。

現(xiàn)實(shí)是 Google 和 Facebook 沒有在使用 Docker。這兩個(gè)概念有區(qū)別。

我們先說“沒在用”。歷史上,Google 和 Facebook 使用超大規(guī)模集群先于 Docker 和 Kubernetes 的出現(xiàn)。當(dāng)時(shí)為了打包方便,連 tarball 都沒有。

對(duì)于 C/C++ 程序,直接全靜態(tài)鏈接,根本沒有 *.so。于是一個(gè) executable binary file 就是“包”了。

直到今天,大家用開源的 Bazel 和 Buck 的時(shí)候,仍然可以看到默認(rèn)鏈接方式就是全靜態(tài)鏈接。

Java 語(yǔ)言雖然是一種“全動(dòng)態(tài)鏈接”的語(yǔ)言,不過其誕生和演進(jìn)扣準(zhǔn)了互聯(lián)網(wǎng)歷史機(jī)遇,其開發(fā)者發(fā)明 jar 文件格式,從而支持了全靜態(tài)鏈接。

Python 語(yǔ)言本身沒有 jar 包,所以 Blaze 和 Bazel 發(fā)明了 PAR 文件格式(英語(yǔ)叫 subpar),相當(dāng)于為 Python 設(shè)計(jì)了一個(gè) jar。開源實(shí)現(xiàn)在這里[8]。

類似的,Buck 發(fā)明了 XAR 格式,也就是我上文所說的 squashfs image 前面加了一個(gè) header。其開源實(shí)現(xiàn)在這里[9]。

Go 語(yǔ)言默認(rèn)就是全靜態(tài)鏈接的。在 Rob Pike 早期的一些總結(jié)里提到,Go 的設(shè)計(jì),包括全靜態(tài)鏈接,基本就是繞坑而行,繞開 Google C/C++ 實(shí)踐中遇到過的各種坑。

熟悉 Google C++ style guide 的朋友們應(yīng)該感覺到了 Go 語(yǔ)法覆蓋了 guide 說的“應(yīng)該用的 C++ 語(yǔ)法”,而不支持 guide 說的 “不應(yīng)該用的 C++ 的部分”。

簡(jiǎn)單的說,歷史上 Google 和 Facebook 沒有在用 Docker image,很重要的一個(gè)原因是,其 build system 對(duì)各種常見語(yǔ)言的程序都可以全靜態(tài)鏈接,所以可執(zhí)行文件就是“包”。

但這并不是最好的解法,畢竟這樣就沒有分層了。哪怕我只是修改了 main 函數(shù)里的一行代碼,重新編譯和發(fā)布,都需要很長(zhǎng)時(shí)間,十分鐘甚至數(shù)十分鐘,要知道全靜態(tài)鏈接得到的可執(zhí)行文件往往大小以 GB 計(jì)。

所以全靜態(tài)鏈接雖然是 Google 和 Facebook 沒有在用 Docker 的原因之一,但是并不是一個(gè)好選擇。

所以也沒被其他公司效仿。大家還是更愿意用支持分層 cache 的 Docker image。

完美解法的技術(shù)挑戰(zhàn)

完美的解法應(yīng)該支持分層 cache(或者更精確的說是分塊 cache)。所以還是應(yīng)該用上文介紹的 monolithic repo 和統(tǒng)一 build system 的特點(diǎn)。

但是這里有一個(gè)技術(shù)挑戰(zhàn),build system 描述的模塊,而模塊通常比“項(xiàng)目”細(xì)粒度太多了。

以 C/C++ 語(yǔ)言為例,如果每個(gè)模塊生成一個(gè) .so 文件,當(dāng)做一個(gè)“層”或者“塊”以便作為 cache 的單元,那么一個(gè)應(yīng)用程序可能需要的 .so 數(shù)量就太多了。

啟動(dòng)應(yīng)用的時(shí)候,恐怕要花幾十分鐘來 resolve symbols 并且完成鏈接。

所以呢,雖然 monolithic repo 有很多好處,它也有一個(gè)缺點(diǎn),不像開源世界里,大家人力的把代碼分解成“項(xiàng)目”。

每個(gè)項(xiàng)目通常是一個(gè) GitHub repo,其中可以有很多模塊,但是每個(gè)項(xiàng)目里所有模塊 build 成一個(gè) *.so 作為一個(gè) cache 的單元。

因?yàn)橐粋€(gè)應(yīng)用程序依賴的項(xiàng)目數(shù)量總不會(huì)太多,從而控制了 layer 的總數(shù)。

好在這個(gè)問題并非無解。既然一個(gè)應(yīng)用程序?qū)Ω鱾€(gè)模塊的依賴關(guān)系是一個(gè) DAG,那么我們總可以想辦法做一個(gè) graph partitioning,把這個(gè) DAG 分解成不那么多的幾個(gè)子圖。

仍然以 C/C++ 程序?yàn)槔?,我們可以把每個(gè)子圖里的每個(gè)模塊編譯成一個(gè) .a,而每個(gè)子圖里的所有 .a 鏈接成一個(gè) *.so,作為一個(gè) cache 的單元。

于是,如何設(shè)計(jì)這個(gè) graph partitioning 算法就成了眼前最重要的問題了。

編輯:jq

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • Google
    +關(guān)注

    關(guān)注

    5

    文章

    1752

    瀏覽量

    57334
  • 操作系統(tǒng)
    +關(guān)注

    關(guān)注

    37

    文章

    6620

    瀏覽量

    123046
  • 分布式
    +關(guān)注

    關(guān)注

    1

    文章

    843

    瀏覽量

    74426
  • 代碼
    +關(guān)注

    關(guān)注

    30

    文章

    4700

    瀏覽量

    68115
  • pytorch
    +關(guān)注

    關(guān)注

    2

    文章

    795

    瀏覽量

    13088

原文標(biāo)題:Google 和 Facebook 為什么不用 Docker?

文章出處:【微信號(hào):LinuxHub,微信公眾號(hào):Linux愛好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    手動(dòng)構(gòu)建Docker鏡像的方法

    不推薦使用docker commit命令,而應(yīng)該使用更靈活、更強(qiáng)大的dockerfile來構(gòu)建docker鏡像。
    的頭像 發(fā)表于 08-05 15:30 ?370次閱讀
    手動(dòng)構(gòu)建<b class='flag-5'>Docker</b>鏡像的方法

    ARM平臺(tái)實(shí)現(xiàn)Docker容器技術(shù)

    平臺(tái)上,而不用擔(dān)心運(yùn)行環(huán)境的變化導(dǎo)致應(yīng)用無法正常運(yùn)行的情況。 更輕松的維護(hù)和拓展:Docker使用的分層存儲(chǔ)以及鏡像的技術(shù),使得應(yīng)用重復(fù)部分的復(fù)用更為容易,也使得應(yīng)用的維護(hù)更新更加簡(jiǎn)單,基于基礎(chǔ)鏡像
    發(fā)表于 07-25 14:36

    ARM平臺(tái)實(shí)現(xiàn)Docker容器技術(shù)

    不用擔(dān)心運(yùn)行環(huán)境的變化導(dǎo)致應(yīng)用無法正常運(yùn)行的情況。更輕松的維護(hù)和拓展:Docker使用的分層存儲(chǔ)以及鏡像的技術(shù),使得應(yīng)用重復(fù)部分的復(fù)用更為容易,也使得應(yīng)用的維護(hù)更新更加簡(jiǎn)單,基于基礎(chǔ)鏡像進(jìn)一步擴(kuò)展鏡像
    發(fā)表于 07-17 11:05

    Jtti:Docker會(huì)替代調(diào)虛機(jī)嗎

    嗎? 答案:不會(huì)。 原因:是有些遺留應(yīng)用是運(yùn)行在windows系統(tǒng)上的。有些應(yīng)用可以直接遷移到虛擬上,但是不能直接在容器中運(yùn)行。現(xiàn)在得趨勢(shì)是虛擬機(jī)和容器同時(shí)發(fā)展。容器的優(yōu)點(diǎn)是敏捷性和高性能。而虛擬機(jī)的優(yōu)點(diǎn)是更強(qiáng)的隔離性和運(yùn)維的簡(jiǎn)單性。 Docker不但不會(huì)替代虛擬機(jī),
    的頭像 發(fā)表于 07-12 14:38 ?220次閱讀
    Jtti:<b class='flag-5'>Docker</b>會(huì)替代調(diào)虛機(jī)嗎

    關(guān)于Docker 的清理命令集錦

    這篇文章主要介紹了Docker 清理命令集錦,需要的朋友可以參考下 復(fù)制代碼代碼如下: docker kill $(docker ps -a -q) ?刪除所有已經(jīng)停止的容器 復(fù)制代碼代碼如下
    的頭像 發(fā)表于 06-13 15:56 ?275次閱讀

    貼片繞線電感使用中溫度高的原因揭秘

    貼片繞線電感使用中溫度高的原因揭秘 編輯:谷景電子 貼片繞線電感作為電子電路中一種特別重要的電感元件,大部分人在使用的時(shí)候可能都碰到過這種溫度過高的狀況。所以,到底是什么原因引起的這種情況發(fā)生呢
    的頭像 發(fā)表于 03-13 19:46 ?361次閱讀

    ARM平臺(tái)實(shí)現(xiàn)Docker容器技術(shù)

    什么是Docker? (1)Docker的架構(gòu) Docker是一個(gè)開源的應(yīng)用容器引擎,讓開發(fā)者可打包他們的應(yīng)用以及依賴包到一個(gè)可移植的鏡像中,然后發(fā)布到任何流行的Linux或Windows機(jī)器上
    的頭像 發(fā)表于 03-07 13:48 ?685次閱讀
    ARM平臺(tái)實(shí)現(xiàn)<b class='flag-5'>Docker</b>容器技術(shù)

    如何利用樹莓派安裝DockerDocker-compose呢?

    本文主要演示了樹莓派如何安裝DockerDocker-compose的過程。
    的頭像 發(fā)表于 12-14 16:19 ?2579次閱讀
    如何利用樹莓派安裝<b class='flag-5'>Docker</b>和<b class='flag-5'>Docker</b>-compose呢?

    docker核心組件有哪些

    Docker 是一種開源的容器化平臺(tái),它能夠?qū)崿F(xiàn)將應(yīng)用程序及其依賴項(xiàng)打包到一個(gè)可移植的容器中,從而實(shí)現(xiàn)快速、可重復(fù)、可擴(kuò)展的部署和管理。Docker 的核心組件包括 Docker Engine
    的頭像 發(fā)表于 11-23 09:47 ?1716次閱讀

    docker進(jìn)入容器的方法有哪些

    Docker是一種流行的容器化平臺(tái),它能夠快速構(gòu)建、交付和運(yùn)行應(yīng)用程序。在使用Docker時(shí),我們經(jīng)常需要進(jìn)入容器進(jìn)行調(diào)試、管理和運(yùn)行命令等操作。本文將詳細(xì)介紹Docker進(jìn)入容器的各種方法,包括
    的頭像 發(fā)表于 11-23 09:45 ?1w次閱讀

    如何啟動(dòng)本機(jī)docker服務(wù)

    Docker是一個(gè)開源項(xiàng)目,可以幫助開發(fā)者打包應(yīng)用程序及其依賴,并且能夠?qū)⑵渥鳛楠?dú)立的容器來運(yùn)行。本文將詳細(xì)介紹如何在本機(jī)上啟動(dòng)Docker服務(wù)。 第一步:安裝Docker 在開始之前,首先需要
    的頭像 發(fā)表于 11-23 09:43 ?1830次閱讀

    linux關(guān)閉docker的命令

    在 Linux 系統(tǒng)中,關(guān)閉 Docker 的操作可以通過以下多種方式進(jìn)行。本文將詳細(xì)講解每一種方式,并提供示例代碼和命令,以幫助讀者更好地理解和實(shí)踐。 使用 docker 命令 最常用的方法
    的頭像 發(fā)表于 11-23 09:39 ?2641次閱讀

    docker exec命令的使用方法

    Docker是一種開源的容器化平臺(tái),可以讓開發(fā)人員在容器中打包和運(yùn)行應(yīng)用程序。它提供了一種快速、可靠和一致的方式來構(gòu)建、部署和運(yùn)行應(yīng)用程序。Docker exec命令是Docker提供的一個(gè)非常
    的頭像 發(fā)表于 11-23 09:33 ?1480次閱讀

    docker部署對(duì)性能的影響

    Docker 是一個(gè)流行的容器化平臺(tái),它提供了一種輕量級(jí)的虛擬化技術(shù),使得應(yīng)用程序可以在獨(dú)立的容器中運(yùn)行。然而,部署應(yīng)用程序到 Docker 容器中可能會(huì)對(duì)性能產(chǎn)生一些影響。在本文中,我們將探討
    的頭像 發(fā)表于 11-23 09:31 ?1410次閱讀

    docker部署mysql的壞處

    Docker 是一種虛擬化技術(shù),它允許開發(fā)人員在容器內(nèi)打包應(yīng)用程序及其所有依賴項(xiàng),從而實(shí)現(xiàn)在不同環(huán)境中運(yùn)行相同的應(yīng)用程序的能力。然而,在使用 Docker 部署 MySQL 時(shí),也存在一些潛在
    的頭像 發(fā)表于 11-23 09:29 ?1297次閱讀