Docker存儲驅動之Btrfs簡介

簡介

Btrfs是下一代的copy-on-write文件系統,它支持很多高級特性,使其更加適合Docker。Btrfs合併在內核主線中,並且它的on-disk-format也逐漸穩定了。不過,它的很多特性還仍然處於開發中。
Docker的btrfs存儲驅動利用了很多Btrfs特性來管理鏡像和容器。這些特性中最重要的就是thin provisioning(超配)、copy-on-write和快照。

Btrfs特性

  Btrfs一直被認爲是Linux文件系統的未來。在Linux內核主線的全力支持下,穩定的on-disk-format,關注於穩定性的積極開發,使得Btrfs逐漸成爲現實。
  只要Docker還在Linux平臺上運行,人們就會認爲btrfs存儲驅動會替代devicemapper存儲驅動,成爲潛在的長期的存儲驅動。然而,在寫耗時上,devicemapper被認爲更安全,更穩定,更適合商品化。只有當你很瞭解Btrfs,並且有豐富的經驗時,纔可以考慮btrfs驅動商品化。

鏡像分層和共享Btrfs

  Docker利用Btrfs的子卷(subvolumes)和快照來管理鏡像和容器層的on-disk組件。Btrfs子卷像是一個普通的Unix文件系統。同樣,當掛靠到Unix文件系統時,它們可以有自己的內部目錄結構。
  子卷是原生的copy-on-write,還有着按需分配的足夠的空間,這些空間來自於下層的存儲池。它們也可以擁有子卷,也可以使用快照。下圖顯示了4個子卷,子卷2和子卷3掛靠在其他子卷之上,子卷4顯示了自己內部的目錄樹。
  image
  快照是某個時間點整個子卷的讀寫拷貝。它們直接位於其父-子卷之下。示例如下:
  image
  Btrfs從下層的存儲池中,按需地爲子卷和快照分配空間。分配的單位是chunk(大塊),大塊的大小通常是1GB左右。
  快照是Btrfs文件系統的“一等公民”,它操作時就像普通的子卷。由於Btrfs原生的copy-on-write設計,創建快照可以直接在Btrfs文件系統中構建。這意味着Btrfs快照空間利用率很高,很少或是沒有性能消耗。下圖顯示了子卷和它快照如何分享相同數據的。
  image
  Docker的btrfs存儲驅動把每個鏡像層和容器都保存在它們自己的Btrfs子卷或者快照中。底部鏡像保存爲子卷,而他的子鏡像層和容器都保存爲快照。下圖展示了該特性。
  image
  Docker是如下使用btrfs驅動的:
  1) 鏡像的底層保存爲Btrfs子卷,位於/var/lib/docker/btrfs/subvolumes目錄下。
  2) 隨後的鏡像層都保存爲父層(子卷或快照)的Btrfs快照。

鏡像和容器on-disk構建

  鏡像層和容器可在Docker host的文件系統下直接看到,目錄爲/var/lib/docker/btrfs/subvolumes/。即使容器停止了,但其目錄依然存在。這是因爲btrfs存儲驅動映射了一個默認的,最高等級的子卷在/var/lib/docker/btrfs/subvolumes/下。所有其他的子卷都作爲Btrfs文件系統給的對象而存在於該卷之下,而不是各自獨立的映射。
  因爲Btrfs工作在文件系統級別,而不是塊級別,可以通過普通的Unix命令直接瀏覽鏡像和容器層的內容。可以通過ls -l等簡單命令來顯示鏡像層的內容,以下爲一個刪減的輸出:

$ ls -l /var/lib/docker/btrfs/subvolumes/0a17decee4139b0de68478f149cc16346f5e711c5ae3bb969895f22dd6723751/

total 0
drwxr-xr-x 1 root root 1372 Oct  9 08:39 bin
drwxr-xr-x 1 root root    0 Apr 10  2014 boot
drwxr-xr-x 1 root root  882 Oct  9 08:38 dev
drwxr-xr-x 1 root root 2040 Oct 12 17:27 etc
drwxr-xr-x 1 root root    0 Apr 10  2014 home
...output truncated...

容器使用Btrfs讀寫

  容器是鏡像的一個高效利用空間的快照,快照中的元數據指向存儲池中的實際數據塊,這個和子卷是一致的。因此,從快照中讀和從子卷中讀本質上是一樣的。所以,Btrfs驅動沒有額外的性能損耗。
  寫一個新的文件,是一個按需分配的操作,會分配新的數據塊給容器快照。文件也會寫到這塊新的空間。按需分配操作和所有Btrfs寫操作一樣,和寫新數據到子卷也是一樣的。因此,向容器快照寫文件操作和原生的Btrfs操作速度一致。
  在容器中更新一個已經存在的文件會引起copy-on-write操作(實際上是redirect-on-write),驅動不操作源數據,新分配一塊空間給快照。更新的數據寫在這塊新空間上,然後,驅動更新快照中的文件系統系統元數據,指向這塊新數據。該行爲只有極小的損耗。
  使用Btfs,寫和更新大量小文件時,會使得性能緩慢。

在Docker中配置Btrfs

  btrfs存儲驅動只有在/var/lib/docker被映射在一個Btrfs文件系統時才能被使用。以下步驟展示如何在Ubuntu 14.04 LTS上配置Brtfs。

準備知識

  如果你已經在你的Docker host上使用了Docker daemon,還有些鏡像想保存,那麼在嘗試Btrfs之前,你需要先把鏡像推送到Docker Hub或者你的私有倉庫。
  停止Docker daemon。然後,確保你在/dev/xvdb下有空閒的塊設備。
  另外,還需要確定你的OS上是否已經加載了Btrfs模塊。輸入以下命令確認:

$ cat /proc/filesystems | grep btrfs

        btrfs

在Ubuntu 14.04 LTS上配置Btrfs

  如果你的OS滿足前面的要求,那麼如下操作:
  1) 安裝btrfs-tools包。

$ sudo apt-get install btrfs-tools

 Reading package lists... Done
 Building dependency tree
 <output truncated>

  2) 創建Btrfs存儲池。
  通過mkfs.btrfs命令創建Btrfs存儲池。給mkfs.btrfs命令傳遞多個設備則可以創建一個使用多個設備的存儲池。這裏我們演示一下創建單個設備(/dev/xvdb)的池。

 $ sudo mkfs.btrfs -f /dev/xvdb

 WARNING! - Btrfs v3.12 IS EXPERIMENTAL
 WARNING! - see http://btrfs.wiki.kernel.org before using

 Turning ON incompat feature 'extref': increased hardlink limit per file to 65536
 fs created label (null) on /dev/xvdb
     nodesize 16384 leafsize 16384 sectorsize 4096 size 4.00GiB
 Btrfs v3.12

  記得把/dev/xvdb替換爲你係統中的實際設備名稱。
  再次提醒:如前面提到的,Btrfs暫時來看,不建議作爲產品來使用,除非你有着豐富的經驗。
  3) 在本地存儲創建 /var/lib/docker。

$ sudo mkdir /var/lib/docker

  4) 使Btrfs文件系統在系統重啓時會自映射。
    a. 獲取Btrfs文件系統的UUID。

$ sudo blkid /dev/xvdb

/dev/xvdb: UUID="a0ed851e-158b-4120-8416-c9b072c8cf47"
UUID_SUB="c3927a64-4454-4eef-95c2-a7d44ac0cf27" TYPE="btrfs"

    b. 在/etc/fstab中增加一行條目,使得系統啓動時可以自動映射/var/lib/docker。下面兩行每一行都可以生效,當然,在你實際操作中,記得替換爲自己的UUID。

 /dev/xvdb /var/lib/docker btrfs defaults 0 0
 UUID="a0ed851e-158b-4120-8416-c9b072c8cf47" /var/lib/docker btrfs defaults 0 0

  5.映射新的文件系統,並確認操作是否成功。

$ sudo mount -a

$ mount

/dev/xvda1 on / type ext4 (rw,discard)
<output truncated>
/dev/xvdb on /var/lib/docker type btrfs (rw)

  6.然後,重啓docker服務。

$ sudo service docker start

docker start/running, process 2315

  當然,由於你使用的Linux發行版可能不同,啓動Docker Daemon的方法可能也不同。
  這裏,在啓動Docker Daemon之前,你可以強行指定Daemon的存儲驅動爲btrfs存儲驅動。可以在daemon啓動命令行時傳遞–storage-driver=btrfs 參數,也可以在Docker配置文件中修改DOCKER_OPTS參數。
  7.通過docker info命令驗證。

$ sudo docker info

Containers: 0
Images: 0
Storage Driver: btrfs
[...]

btrfs和Docker性能

  在btrfs存儲驅動下,有以下一些原因可以影響Docker的性能。
-   Page caching,頁緩存。Btrfs不支持頁緩存共享,也就是說n個容器訪問同一個文件會請求n份緩存拷貝。因此,btrfs驅動可能不是PaaS或者高密集容器的最優選項。
-   Small writes,小的寫請求。容器執行大量寫的寫請求(包括Docker host啓動和停止很多容器)會導致Btrfs大塊只使用了很小一部分,最終會導致Docker host空間不足,停止服務。這是當前使用Btrfs的一個最重大的缺點。
  如果使用btrfs存儲驅動,需要密切監視Btrfs文件系統的可用空間,可用使用btrfs filesys show來觀察。不要相信常規的Unix命令(如df)的輸出。
-   Sequential writes,順序寫。Btrfs通過日誌技術寫數據到磁盤,這會導致順序寫的性能減半。
-   Fragmentation。存儲殘片是像Btrfs這種copy-on-write文件系統的天然副產品,很多小的隨機寫會產生這個問題。它可以表現爲使用SSD介質的Docker主機上的CPU峯值和使用旋轉介質的Docker主機上的抖動(It can manifest as CPU spikes on Docker hosts using SSD media and head thrashing on Docker hosts using spinning media.不是很理解這句)。這兩個都會導致性能很差。
  Btrfs的最近版本允許你制定autodefrag作爲一個映射點。這種模式下,會探測到隨機寫並進行碎片整理。在確定使用Btrfs之前,你應該在你的Docker host上進行測試。一些測試顯示,在執行大量的samll writes操作時(包括啓停很多容器),這個選項會有一些負面的性能問題。
-   Solid State Devices(SSD)。Btrfs有原生的SSD優化,可以通過映射時加上-o ssd映射選項來使能它。這些優化包括在SSD介質上避免seek之類的操作來增強SSD寫性能,因爲這類操作在SSD上沒有任何作用。
  Btrfs也支持TRIM/Discard元操作。然而,映射時加上 -o discard 的選項會導致性能問題。因此,還是建議在使用之前做些測試。
-   Use Data Volumes。數據卷提供最優和最可預測的性能。因爲它們可以繞過存儲驅動,不會引起任何超配和copy-on-write可能會導致的潛在的負載。
-   Balance BTRFS。開啓一個cron任務來均衡你的BTRFS設備,比如均衡地傳輸子卷的塊給raid設備,回收未使用的塊。如果不這樣做,docker刪除了快照和子卷,但仍會殘留那些已經分配了的塊,而這些塊安裝了BTRFS根卷。一旦你沒有執行再均衡操作,在不添加額外的存儲設備情況下,會導致潛在的不可恢復的狀態。如果你不願意使用crond來自動執行,另一種方法是在非峯值時手動執行再均衡命令,因爲這種操作是磁盤I/O密集型操作。此命令按要求所有的大塊使用了1%或者更少:

$ sudo btrfs filesystem balance start -dusage=1 /var/lib/docker
Dumping filters: flags 0x1, state 0x0, force is off DATA (flags 0x2): balancing, usage=1 Done, had to relocate 673 out of 842 chunks

小結

  Btrfs存儲驅動的主要特性就是超配,copy-on-write和快照。與AuFS或者devmapper不同,要在Docker上使用Btrfs,要求整個/var/lib/docker所處的文件系統就是Btrfs。此外,btrfs存儲驅動由於現在還在重度開發中,現在最多的就是各種性能問題。所以,官方也不建議直接在Docker生產環境中使用,除非,你在Btrfs上有着豐富的經驗。

發佈了122 篇原創文章 · 獲贊 55 · 訪問量 54萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章