使用 BTRFS 儲存驅動程式

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

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

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

注意

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

先決條件

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

  • 僅建議在 Ubuntu 或 Debian 系統上的 Docker CE 中使用 btrfs

  • 更改儲存驅動程式會使您已經在本地系統上建立的任何容器都無法訪問。使用 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) 比旋轉磁碟提供更快的讀寫速度。

對寫入量大的工作負載使用卷

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