BTRFS 儲存驅動程式

重要

在大多數情況下,您應該使用 overlay2 儲存驅動程式——僅僅因為您的系統使用 Btrfs 作為其根檔案系統,並不需要使用 btrfs 儲存驅動程式。

Btrfs 驅動程式存在已知問題。有關更多資訊,請參閱 Moby 問題 #27653

Btrfs 是一種寫時複製檔案系統,支援許多先進的儲存技術,使其非常適合 Docker。Btrfs 已包含在主線 Linux 核心中。

Docker 的 btrfs 儲存驅動程式利用了許多 Btrfs 的功能來管理映象和容器。這些功能包括塊級操作、精簡配置、寫時複製快照以及易於管理。您可以將多個物理塊裝置組合成一個 Btrfs 檔案系統。

此頁面將 Docker 的 Btrfs 儲存驅動程式稱為 btrfs,將整個 Btrfs 檔案系統稱為 Btrfs。

注意

btrfs 儲存驅動程式僅在 SLES、Ubuntu 和 Debian 系統上的 Docker Engine CE 中受支援。

先決條件

如果您滿足以下先決條件,則支援 btrfs

  • btrfs 僅建議在 Ubuntu 或 Debian 系統上與 Docker CE 一起使用。

  • 更改儲存驅動程式會使您已建立的任何容器在本地系統上無法訪問。使用 docker save 來儲存容器,並將現有映象推送到 Docker Hub 或私有倉庫,這樣您以後就不需要重新建立它們。

  • btrfs 需要一個專用的塊儲存裝置,例如物理磁碟。此塊裝置必須格式化為 Btrfs 並掛載到 /var/lib/docker/。下面的配置說明將引導您完成此過程。預設情況下,SLES 的 / 檔案系統使用 Btrfs 格式化,因此對於 SLES,您不需要使用單獨的塊裝置,但為了效能考慮,您可以選擇這樣做。

  • 您的核心必須支援 btrfs。要檢查這一點,請執行以下命令

    $ grep btrfs /proc/filesystems
    
    btrfs
    
  • 要在作業系統級別管理 Btrfs 檔案系統,您需要 btrfs 命令。如果您沒有此命令,請安裝 btrfsprogs 包 (SLES) 或 btrfs-tools 包 (Ubuntu)。

配置 Docker 使用 btrfs 儲存驅動

此過程在 SLES 和 Ubuntu 上基本相同。

  1. 停止 Docker。

  2. /var/lib/docker/ 的內容複製到備份位置,然後清空 /var/lib/docker/ 的內容

    $ sudo cp -au /var/lib/docker /var/lib/docker.bk
    $ sudo rm -rf /var/lib/docker/*
    
  3. 將您的專用塊裝置格式化為 Btrfs 檔案系統。此示例假設您正在使用兩個名為 /dev/xvdf/dev/xvdg 的塊裝置。請仔細檢查塊裝置名稱,因為這是一個破壞性操作。

    $ sudo mkfs.btrfs -f /dev/xvdf /dev/xvdg
    

    Btrfs 還有許多其他選項,包括條帶化和 RAID。請參閱 Btrfs 文件

  4. 將新的 Btrfs 檔案系統掛載到 /var/lib/docker/ 掛載點。您可以指定用於建立 Btrfs 檔案系統的任何塊裝置。

    $ sudo mount -t btrfs /dev/xvdf /var/lib/docker
    
    注意

    透過在 /etc/fstab 中新增一個條目,使更改在重啟後永久生效。

  5. /var/lib/docker.bk 的內容複製到 /var/lib/docker/

    $ sudo cp -au /var/lib/docker.bk/* /var/lib/docker/
    
  6. 配置 Docker 使用 btrfs 儲存驅動程式。即使 /var/lib/docker/ 現在正在使用 Btrfs 檔案系統,這也是必需的。編輯或建立檔案 /etc/docker/daemon.json。如果它是一個新檔案,請新增以下內容。如果它是一個現有檔案,請僅新增鍵和值,並注意如果它不是右花括號(})前的最後一行,則以逗號結束該行。

    {
      "storage-driver": "btrfs"
    }

    有關每個儲存驅動程式的所有儲存選項,請參閱守護程序參考文件

  7. 啟動 Docker。當它執行時,請驗證 btrfs 是否被用作儲存驅動程式。

    $ docker info
    
    Containers: 0
     Running: 0
     Paused: 0
     Stopped: 0
    Images: 0
    Server Version: 17.03.1-ce
    Storage Driver: btrfs
     Build Version: Btrfs v4.4
     Library Version: 101
    <...>
    
  8. 準備好後,刪除 /var/lib/docker.bk 目錄。

管理 Btrfs 卷

Btrfs 的好處之一是易於管理 Btrfs 檔案系統,而無需解除安裝檔案系統或重新啟動 Docker。

當空間不足時,Btrfs 會自動以大約 1 GB 的塊擴展卷。

要向 Btrfs 卷新增塊裝置,請使用 btrfs device addbtrfs filesystem balance 命令。

$ sudo btrfs device add /dev/svdh /var/lib/docker

$ sudo btrfs filesystem balance /var/lib/docker
注意

雖然您可以在 Docker 執行時執行這些操作,但效能會受到影響。最好計劃一個停機視窗來平衡 Btrfs 檔案系統。

btrfs 儲存驅動如何工作

btrfs 儲存驅動程式的工作方式與其他儲存驅動程式不同,您的整個 /var/lib/docker/ 目錄都儲存在 Btrfs 捲上。

磁碟上的映象和容器層

關於映象層和可寫容器層的資訊儲存在 /var/lib/docker/btrfs/subvolumes/ 中。這個子目錄為每個映象或容器層包含一個目錄,其統一檔案系統由一個層及其所有父層構建而成。子卷是原生的寫時複製,並按需從底層儲存池中分配空間。它們也可以巢狀和快照。下圖顯示了 4 個子卷。“子卷 2”和“子卷 3”是巢狀的,而“子卷 4”則顯示了其自己的內部目錄樹。

Subvolume example

只有映象的基礎層作為真正的子卷儲存。所有其他層都作為快照儲存,這些快照只包含在該層中引入的差異。您可以建立快照的快照,如下圖所示。

Snapshots diagram

在磁碟上,快照看起來和感覺上都像子卷,但實際上它們要小得多,空間效率也更高。寫時複製用於最大化儲存效率並最小化層的大小,容器可寫層中的寫入在塊級別進行管理。下圖顯示了一個子卷及其快照共享資料。

Snapshot and subvolume sharing data

為了獲得最高效率,當容器需要更多空間時,會以大約 1 GB 大小的塊進行分配。

Docker 的 btrfs 儲存驅動程式將每個映象層和容器儲存在自己的 Btrfs 子卷或快照中。映象的基礎層儲存為子卷,而子映象層和容器則儲存為快照。如下圖所示。

Btrfs container layers

在執行 btrfs 驅動程式的 Docker 主機上建立映象和容器的高階流程如下

  1. 映象的基礎層儲存在 /var/lib/docker/btrfs/subvolumes 下的 Btrfs *子卷* 中。

  2. 後續映象層作為父層子卷或快照的 Btrfs *快照* 儲存,但包含該層引入的更改。這些差異以塊級別儲存。

  3. 容器的可寫層是最終映象層的 Btrfs 快照,其中包含執行中容器引入的差異。這些差異以塊級別儲存。

容器讀寫如何與 btrfs 協同工作

讀取檔案

容器是映象的空間高效快照。快照中的元資料指向儲存池中的實際資料塊。這與子卷相同。因此,對快照執行的讀取與對子卷執行的讀取基本相同。

寫入檔案

作為一般警告,使用 Btrfs 寫入和更新大量小檔案可能會導致效能緩慢。

考慮三種容器使用 Btrfs 開啟檔案進行寫訪問的場景。

寫入新檔案

向容器中寫入新檔案會呼叫按需分配操作,為容器的快照分配新的資料塊。然後檔案被寫入這個新空間。按需分配操作是 Btrfs 所有寫入操作的原生特性,與向子卷寫入新資料相同。因此,向容器快照中寫入新檔案的操作以原生 Btrfs 速度執行。

修改現有檔案

更新容器中的現有檔案是一個寫時複製操作(Btrfs 術語為寫時重定向)。原始資料從檔案當前所在的層讀取,只有修改過的塊被寫入容器的可寫層。接下來,Btrfs 驅動程式更新快照中的檔案系統元資料以指向這個新資料。這種行為會產生輕微的開銷。

刪除檔案或目錄

如果容器刪除存在於較低層的檔案或目錄,Btrfs 會在較低層中遮蔽該檔案或目錄的存在。如果容器建立檔案然後刪除它,此操作在 Btrfs 檔案系統本身中執行,並且空間被回收。

Btrfs 和 Docker 效能

有幾個因素會影響 Docker 在 btrfs 儲存驅動程式下的效能。

注意

透過為寫密集型工作負載使用 Docker 卷,可以減輕許多這些因素的影響,而不是依賴於將資料儲存在容器的可寫層中。然而,在 Btrfs 的情況下,除非 /var/lib/docker/volumes/ 不由 Btrfs 支援,否則 Docker 卷仍然會受到這些缺點的影響。

頁面快取

Btrfs 不支援頁面快取共享。這意味著訪問同一檔案的每個程序都會將該檔案複製到 Docker 主機的記憶體中。因此,btrfs 驅動程式可能不是高密度用例(如 PaaS)的最佳選擇。

小檔案寫入

執行大量小檔案寫入的容器(這種使用模式與在短時間內啟動和停止許多容器時發生的情況相匹配)可能導致 Btrfs 塊的利用率不佳。這可能會過早地填滿 Btrfs 檔案系統,並導致您的 Docker 主機出現空間不足的情況。使用 btrfs filesys show 來密切監控 Btrfs 裝置上的可用空間量。

順序寫入

Btrfs 在寫入磁碟時使用日誌技術。這可能會影響順序寫入的效能,最多可降低 50% 的效能。

碎片化

碎片化是像 Btrfs 這樣的寫時複製檔案系統的自然副產品。許多小的隨機寫入會加劇這個問題。當使用 SSD 時,碎片化可能表現為 CPU 峰值,或者在使用旋轉磁碟時表現為磁頭抖動。這些問題中的任何一個都可能損害效能。

如果您的 Linux 核心版本是 3.9 或更高,您可以在掛載 Btrfs 卷時啟用 autodefrag 功能。在將此功能部署到生產環境之前,請在您自己的工作負載上進行測試,因為一些測試顯示它對效能有負面影響。

SSD 效能

Btrfs 包含對 SSD 介質的原生最佳化。要啟用這些功能,請使用 -o ssd 掛載選項掛載 Btrfs 檔案系統。這些最佳化包括透過避免不適用於固態介質的尋道最佳化等方式來增強 SSD 的寫入效能。

經常平衡 Btrfs 檔案系統

使用作業系統實用程式(例如 cron 作業)在非高峰時段定期平衡 Btrfs 檔案系統。這會回收未分配的塊,並有助於防止檔案系統不必要地被填滿。除非您向檔案系統新增額外的物理塊裝置,否則無法重新平衡一個完全滿的 Btrfs 檔案系統。

請參閱 Btrfs Wiki

使用快速儲存

固態硬碟(SSD)比旋轉磁碟提供更快的讀寫速度。

對寫入密集型工作負載使用卷

對於寫入密集型工作負載,卷提供了最佳且最可預測的效能。這是因為它們繞過了儲存驅動程式,並且不會產生由精簡配置和寫時複製引入的任何潛在開銷。卷還有其他好處,例如允許您在容器之間共享資料,並且即使沒有正在執行的容器使用它們,它們也會持久存在。