1. 程式人生 > >docker的devicemapper儲存驅動

docker的devicemapper儲存驅動

1 誕生的背景

期初docker是執行在Debian和Ubuntu系統上的,使用的是AUFS方式的儲存。後來很多企業希望在Redhat系linux上執行docker,並決定基於現有的Device Mapper技術開發一個新的儲存方案,這就是devicemapper。

2 映象的分層和共享

Device Mapper技術不是按照檔案級別(file level),而是按塊級別(block level)工作的,所以devicemapper也屬於塊級儲存方案,有著thin provisioning和copy-on-write的特點。

  • thin provisioning
    這個不知道該怎麼翻譯,網上叫自動精簡配置的比較多(與此相對的傳統的儲存配置模型被稱為厚儲存配置FP),簡單的說就是在需要的時候分配所需的最小空間(與此相對,傳統的儲存空間的分配都是超過目前的需求的,從而導致的一個問題就是儲存利用率低下)。
  • copy-on-write
    簡單的理解就是,在內容發生變化的時候才進行內容複製。

devicemapper儲存方式下的映象

使用devicemapper儲存生成映象大致按照下面的流程:
首先,devicemapper驅動從塊裝置建立一個小的儲存池(a thin pool)
然後,建立一個帶有檔案系統,如extfs等,的基礎裝置(base device)
之後,每個新的映象(或映象層)都是base device的一個快照(snapshot)

devicemapper儲存方式下的容器

devicemapper儲存方式下,容器層都是從映象生成的快照,快照裡儲存著所有對容器的更新。當資料被寫入容器的時候,devicemapper按需從池中分配空間。

下面是官方文件中的一個說明圖:
這裡寫圖片描述
從上圖可以看出,每個映象層都是它下面一層的快照。每個映象的最下面一層的映象則是池中base device的快照。需要注意的是,base device屬於Device Mapper的一部分,並不是docker的映象層。

3 devicemapper下的讀寫

關於讀

官網上讀操作的說明圖如下:
這裡寫圖片描述
1)應用請求讀取容器中的0x44f塊區
因為容器是映象的一個簡單快照,並沒有資料只有一個指標,指向映象層儲存資料的地方。
2)儲存驅動根據指標,到映象快照的a005e映象層尋找0xf33塊區
3)devicemapper從映象快照拷貝0xf33的內容到容器的記憶體中
4)儲存驅動最後將資料返回給請求的應用

關於寫

當對容器中的大檔案做一個小的改動的時候,devicemapper不會複製這整個檔案,而是隻拷貝被修改的塊區。每個塊區的大小為64KB。

  • 寫新資料的情況
    例如,寫56KB大小的新資料到一個容器:
    1)應用發出一個要寫56KB的新資料到容器的請求
    2)根據按需分配,將分配一個新的64KB的塊區給容器的快照
    如果寫操作的資料大於64KB的話,將分配多個塊區
    3)之後,資料將被寫入到新分配的塊區中

  • 覆寫已有的資料
    每當容器第一次更新已有的資料時:
    1)應用發出一個修改容器中資料的請求
    2)copy-on-write操作將定位到需要更新的塊區
    3)然後分配新的空塊區給容器快照,並複製資料到新分配的塊區
    4)接著,在有複製資料的新塊區中進行資料修改
    容器中的應用對發生的allocate-on-demand操作和copy-on-write操作是無感的

4 關於devicemapper的配置

Redhat系的linux發行版都採用devicemapper作為docker的預設儲存驅動。目前,Debian,Ubuntu和Arch Linux也支援devicemapper。

devicemapper預設使用的是loop-lvm模式,這個模式使用sparse files來建立供映象和容器快照使用的thin pool。然而,生產環境不要使用loop-lvm模式,官方建議使用direct-lvm模式。direct-lvm模式使用塊裝置(block devices)來建立thin pool。

假設/dev/mapper/docker-thinpool是已建好的lvm的邏輯卷,可以配置docker daemon的執行選項如下:

--storage-driver=devicemapper --storage-opt=dm.thinpooldev=/dev/mapper/docker-thinpool --storage-opt=dm.use_deferred_removal=true --storage-opt=dm.use_deferred_deletion=true

官方說設定dm.use_deferred_removal=true和dm.use_deferred_deletion=true選項可以防止unintentionally leaking mount points(沒太明白什麼意思,總之配了比不配好吧)。

devicemapper在主機上的結構

使用lsblk命令可以檢視裝置檔案和devicemapper在裝置檔案上建立的pool:
這裡寫圖片描述
對應上面介面的層次圖如下:
這裡寫圖片描述
可以看出,名為Docker-202:1-1032-pool的pool橫跨在data和metadata裝置之上。pool的命名規則為:

Docker-主裝置號:二級裝置號-inode號-pool

docker 1.10和以後的版本,在/var/lib/docker目錄下不在採用映象層ID來關聯目錄名了,有另外兩個比較重要的目錄:
/var/lib/docker/devicemapper/mnt 包含映象和容器層的掛載目錄;
/var/lib/docker/devicemapper/metadata 目錄包含每個映象層和容器快照的json格式的檔案。

另外,當資料的邏輯卷要滿的時候,可以給pool進行擴容,具體操作看官網。

5 關於devicemapper的效能

allocate-on-demand的效能影響

每當應用有新資料要寫入容器時,都要從pool中去定位空的塊區並對映給容器。因為所有塊區都是64KB的,小於64KB的資料也會分配一個塊區;大於64B的資料則會分配多個塊區。所以,特別是當發生很多小的寫操作時,就會比較影響容器的效能。

copy-on-write的效能影響

每當容器第一次更新已有的資料時,devicemapper儲存驅動都要執行copy-on-write操作。這個操作是從映象快照複製資料到容器快照,這對容器效能還是有比較明顯的效能影響的。當容器發生很多小64KB的寫操作時,devicemapper的效能會比AUFS要差。

其它方面

1)所使用的mode
預設情況下,devicemapper使用的是loop-lvm模式,這種模式使用的是sparse files,效能比較低。生產環境建議使用direct-lvm模式,這種模式儲存驅動直接寫資料到塊裝置。
2)使用高速儲存
如果希望更好的效能,可以將Data file和Metadata file放到SSD這樣的高速儲存上。
3)記憶體使用
devicemapper並不是一個有效使用記憶體的儲存驅動。當一個容器執行n個時,它的檔案也會被拷貝n份到記憶體中,這對docker宿主機的記憶體使用會造成明顯影響。因此,devicemapper儲存驅動可能並不是PaaS和其它高密度使用型的最好選擇。

對於寫操作較大的,可以採用掛載data volumes。使用data volumes可以繞過儲存驅動,從而不受thin provisioning和copy-on-write產生的負責影響。