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"
    }

    daemon 參考文件中查看每個儲存驅動程式的完整儲存選項。

  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) 提供比旋轉式硬碟更快的讀寫速度。

針對寫入密集型工作負載使用磁碟區

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