2010年5月5日 星期三

LVM2學習筆記

LVM2(Logical Volume Manager, version 2)的前身是LVM,他是由Heinz Mauelshagen於1998年在HP-UX上開發。他當初為了解決unix上分割區空間分配的問題而設計出這個管理程式。有了LVM,我們可以動態的調整空間的大小,大大縮短置換硬碟所需的downtime。這個鬼才現在任職於Redhat,目前正主持幾個跟software raid相關的計畫。目前我們所接觸到的教學文件大多是LVM2,但是因為已經全面取代了舊版的的LVM,因此還是以LVM稱之。

LVM的基本架構


上圖引用自鳥哥的私房菜,是一個相當有助理解的架構圖。本文僅適合非常熟悉LVM架構的讀者做為快速複習使用;如果談到PV/LV/VG等名詞您還得停頓一下,本文可能對您毫無幫助。下表則是我自己整理的指令列表,但僅列出一些常用的commands。

Function PV VG LV
新增 pvcreate vgcreate lvcreate
刪除 pvremove vgremove lvremove
擴大 vgextend lvextend lvresize
縮小 vgreduce lvreduce
變更屬性 pvchange vgchange lvchange
掃描 pvscan vgscan lvscan
詳列清單 pvdisplay vgdisplay lvdisplay
匯入/匯出 vgimport
vgexport
移動 pvmove
附註: 1. pvchangelvchange非常少用,本文也不會提及。
2. lvextend與lvreduce可以完全由lvresize來取代。
3. LVM不具備redundent的功能。如果想要有備援機制,請改用raid或是raid搭配LVM。
4. 目前的開機管理程式均無法辨識LVM,請獨立出/boot便於開機。

設計一個實驗

藉由實做是理解LVM最好的方式。本實驗的流程與目的如下:

  1. 利用虛擬機器產生一個2G大小的硬碟用來產生LVM類型分割區
  2. 練習建立與刪除PV
  3. 練習建立與刪除VG
  4. 練習建立與刪除LV
  5. 在LV上建立檔案系統,並且動態改變LV以及檔案系統大小
  6. 實做LVM的snapshot功能並還原
  7. 以新硬碟取代舊硬碟
  8. 系統重灌或是硬碟轉移,LVM的轉移方案


目標1:產生LVM類型分割區

我先前已經有一個2G的虛擬硬碟,我不想用fdisk慢慢組分割區,直接刪掉他的partiton table以利我們馬上就能使用:

dd if=/dev/zero of=/dev/hdb count=1
接著利用fdisk產生四個分割區,假設分別是hdb{1,2,5,6},各為200M, 300M, 300M以及1200M。

把partition ID改成8e(LVM format)。改完後,別忘記更新核心的partition資訊:

partprobe /dev/hdb
檢查一下核心是否已經更新partition table了:
cat /proc/partitions
major minor  #blocks  name

   3     0    8388608 hda
   3     1    8281476 hda1
   3     2     104422 hda2
   3    64    2097152 hdb
   3    65     196024 hdb1
   3    66     293328 hdb2
   3    67          1 hdb3
   3    69     293296 hdb5
   3    70    1314400 hdb6
如果能看到hdb的1,2,5,6號partition,那就表示可以進行下一步。

目標2:PV的建立與刪除

pv就是構成LVM最基本的元素,他可以是一整顆硬碟,也可以是一個partition。(實作上如果要把整顆硬碟加入LVM裡,還是建議至少做一個partition再加入)要把數個硬碟或是分割區加入PV裡,需要用pvcreate:

pvcreate /dev/hdb{1,5}
把某個分割區從pv裡移除,使用pvremove:
pvremove /dev/hdb5
查看現有的pv有哪些,可以用pvdisplay得知:
  "/dev/hdb1" is a new physical volume of "191.43 MB"
  --- NEW Physical volume ---
  PV Name               /dev/hdb1
  VG Name               
  PV Size               191.43 MB
  Allocatable           NO
  PE Size (KByte)       0
  Total PE              0
  Free PE               0
  Allocated PE          0
  PV UUID               OKTpgY-M2tF-KykI-xPB1-xJae-UMqI-XKvJ5U
可以得知我們現在只有一個分割區加入到pv裡。我們把hdb{2,5}也加到pv裡,讓實驗繼續進行。
pvcreate /dev/hdb{2,5}

目標3:VG的建立與刪除

對於作業系統來說,vg相當於傳統硬碟的地位;把許多個傳統分割區加入pv裡,然後建立一個vg組成一個大的虛擬硬碟。現在我們建立一個名為myVG的vg,由hdb1及hdb2組成:

vgcreate myVG /dev/hdb{1,2}
此時可以用vgdisplay以及vgscan觀察之:
  --- Volume group ---
  VG Name               myVG
  System ID             
  Format                lvm2
  Metadata Areas        2
  Metadata Sequence No  1
  VG Access             read/write
  VG Status             resizable
  MAX LV                0
  Cur LV                0
  Open LV               0
  Max PV                0
  Cur PV                2
  Act PV                2
  VG Size               472.00 MB
  PE Size               4.00 MB
  Total PE              118
  Alloc PE / Size       0 / 0   
  Free  PE / Size       118 / 472.00 MB
  VG UUID               VyMTQc-1Cuy-z2UG-jXyF-LFvx-vRY2-oQaJLd
由上面資訊可以得知,我們只有一個vg叫做myVG,大小為472MB,為118個PE的大小,目前完全沒有PE被使用。
再把hdb5加入到這個vg裡:
vgextend myVG /dev/hdb5
然後再使用vgdisplay/vgscan觀察變化。要把某個傳統分割區從vg裡開除,則使用vgreduce:
vgreduce myVG /dev/hdb1
要把整個vg砍掉重練,就使用vgremove:
vgremove myVG
為了後續的實驗,趕快恢復原狀吧:
vgcreate myVG /dev/hdb{1,2,5}

目標4:LV的建立與刪除

從一個vg裡建立一個lv,就好比從一顆硬碟建立分割區,你需要清楚的知道分割區從哪顆硬碟建立,以及分割區的大小。利用lvcreate建立lv:

lvcreate -L 500M -n myLV myVG
也可以特別指定vg裡的某個pv:
lvcreate -l 125 -n myLV myVG /dev/hdb1
上例表示使用myVG的其中一個pv的空間來建立lv,以-L指定大小,-l指定PE數量;預設1PE=4MB。需特別注意的是,lv一旦建立,想要使用lv則必須像是寫一個分割區一樣寫完整的路徑。以myLV而言,他的完整路徑將會是/dev/myVG/myLV或是/dev/mapper/myVG-myLV
現在擴大lv成為600M:
lvextend -l +25 /dev/myVG/myLV
上例會再從vg裡剩餘的空間去分配。同樣的,要縮減lv也很容易:
lvreduce -l -5 /dev/myVG/myLV
如果-l後面沒有接正負號,則表示改變大小成指定值。由於lvextend只能接正值,lvreduce後面只能接負值,這兩個指令可以完全被lvresize取代,例如上面兩個例子完全等於:
lvresize -l +25 /dev/myVG/myLV
lvresize -l -5 /dev/myVG/myLV
因此,往後的實作將只使用lvresize。為了使實驗繼續進行,我們把myLV的大小設定成600M吧:
lvresize -L 600M /dev/mapper/myVG-myLV

目標5:動態改變LV以及檔案系統大小

建立好lv(想像成建立好傳統的分割區)之後,就必須在上面搭載檔案系統以供使用。請把lv當成一個分割區一樣的來進行格式化吧!

mkfs.ext3 -L "myLV" /dev/mapper/myVG-myLV
mount -t ext3 LABEL=myLV /mnt
截至目前,這個lv已經正式上線使用了。不過我們可以藉由vgdisplay以及df得知,其實myLV並沒有用到全部的可用空間。LVM最強大的功能之一,就是允許線上擴大容量。由於lv是底層,檔案系統在上層,因此要擴大檔案系統必須lv先擴大,filesystem再擴大。
想要擴張lv到最大容量,你可以查看vg剩餘多少PE然後擴大,或是直接擴大到全部可用範圍:
lvresize -l +100%FREE /dev/myVG/myLV
或是指定完全使用某幾個pv:
lvresize -l +100%PVS /dev/myVG/myLV /dev/hdb{2,5}
由此可見,LVM的運用非常強大,且自訂性極高。
擴充lv的容量之後,接著就可以擴充檔案系統:
resize2fs /dev/myVG/myLV [700M]
如果不指定擴充大小,則resize2fs會自動擴充到全部可用範圍。

要縮減lv大小則與擴充相反--必須先縮小上層的filesystem,再縮小底層的lv。如果你不照此順序進行,lv上面的資料會全部付之一炬。縮減lv不支援線上進行,而且縮減到有寫入資料的部份也會造成檔案lost,必須小心為之:

umount /mnt
fsck.ext3 -f /dev/myVG/myLV
resize2fs /dev/myVG/myLV 500M
lvresize -l -25 /dev/myVG/myLV
mount LABEL=myLV /mnt
依序縮減filesystem以及lv大小後,就可以掛載後正式上線工作。

目標6:實做LVM的snapshot功能

Solaris的ZFS檔案系統擁有非常卓越的snapshot功能,雖然LVM的snapshot沒有Solaris那麼powerful,但是也是一樣功能強大且便於使用。snapshot目前僅支援lv,vg的snapshot功能還尚未實做出來。
快照檔其實就是一個lv,他會與檔案系統共用『未變更』的PE,因此snapshot必須與原本的lv在同一個vg裡面。

上圖引用自鳥哥的私房菜,說明了snapshot可以很小的原因就是與原本的lv共用未變更的PE。 他的大小約為想執行snapshot的lv的15%~20%的大小。檢查我們的lv大小:

lvdisplay | grep Size
以我們的例子而言,我們的lv約750MB,製作一個snapshot約需要150MB,恰好目標5的末段我們縮減了檔案系統,vg也還有約156M的空間可以用。我們讓snapshot就坐在這156MB上:
lvcreate -L 156M -s -n `date +"%Y-%m%d".snap` /dev/myVG/myLV
產生了具有日期為檔名的快照檔之後,可以以此作為系統還原備份之用。例如半年後想要回到snapshot的狀態,只要把該snapshot掛載上去就好。
umount /mnt
mkdir /mnt/{myLV,date}
mount /dev/myVG/2010-0505.snap /mnt/date
mount LABEL=myLV /mnt/myLV
雖然snapshot只佔有156MB的空間,但是對於核心而言,他就是一個lv的clone,因此你從df看到的大小是一樣的:
/dev/mapper/myVG-myLV
                      591M   17M  545M   3% /mnt/myLV
/dev/mapper/myVG-2010--0505.snap
                      591M   17M  545M   3% /mnt/date
把snapshot給umount之後,再來進行一些測試!
umount /mnt/date
for words in $(seq 1 1000000); do
      echo 'I love peace world!!' >> abc.txt
done
cp -r /etc/httpd /mnt/myLV
以上,我們做的所有更動都會紀錄在snapshot檔裡,可以用lvdisplay /dev/myVG/2010-0505.snap來觀察:
  --- Logical volume ---
  LV Name                /dev/myVG/2010-0505.snap
  VG Name                myVG
  LV UUID                JDGmIg-m0qW-M0VK-Gem1-4bqA-DEyS-83FtbL
  LV Write Access        read/write
  LV snapshot status     active destination for /dev/myVG/myLV
  LV Status              available
  # open                 0
  LV Size                600.00 MB
  Current LE             150
  COW-table size         156.00 MB
  COW-table LE           39
  Allocated to snapshot  13.32% 
  Snapshot chunk size    4.00 KB
  Segments               1
  Allocation             inherit
  Read ahead sectors     auto
  - currently set to     256
  Block device           253:1
請特別留意"Allocated to snapshot"已經佔了13.32%,由此可知LV的snapshot有個關鍵的要素:所容許的異動大小必須小於snapshot的大小。往後將此snapshot掛載,便可以取出製作快照前的檔案作為備援使用。snapshot被掛載的時候會停止紀錄變動,請非常留意。

刪除一個snapshot就是刪除一個lv:

lvremove /dev/myVG/2010-0505.snap

目標7:以新硬碟汰換舊硬碟

以上已經展示過LVM線上擴大檔案系統及lv的卓越能力,也展示過製作snapshot的功能,現在則是模擬淘汰一個快要壞掉的舊硬碟,換上一個又大又新的硬碟上去。我們假設舊硬碟是hdb1(200M),新硬碟是hdb6(1200M),首先必須把新硬碟加入:

pvcreate /dev/hdb6
vgextend myVG /dev/hdb6
pvmove -v -i 2 /dev/hdb1 /dev/hdb6
上述的指令顯示線上加入一個新硬碟到vg裡,然後把hdb1裡的PE都移動到hdb6裡,並且每隔2秒顯示詳細訊息:
    Finding volume group "myVG"
    Archiving volume group "myVG" metadata (seqno 4).
    Creating logical volume pvmove0
    Moving 47 extents of logical volume myVG/myLV
    Found volume group "myVG"
    Updating volume group metadata
    Suspending myVG-myLV (253:0) with device flush
    Creating myVG-pvmove0
    Loading myVG-pvmove0 table (253:1)
    Resuming myVG-pvmove0 (253:1)
    Creating volume group backup "/etc/lvm/backup/myVG" (seqno 5).
    Checking progress every 2 seconds
  /dev/hdb1: Moved: 14.9%
  /dev/hdb1: Moved: 34.0%
  /dev/hdb1: Moved: 46.8%
  /dev/hdb1: Moved: 57.4%
  /dev/hdb1: Moved: 66.0%
  /dev/hdb1: Moved: 76.6%
  /dev/hdb1: Moved: 89.4%
  /dev/hdb1: Moved: 100.0%
    Found volume group "myVG"
    Loading myVG-myLV table (253:0)
    Suspending myVG-myLV (253:0) with device flush
    Suspending myVG-pvmove0 (253:1) with device flush
    Resuming myVG-pvmove0 (253:1)
    Removing temporary pvmove LV
    Writing out final volume group after pvmove
    Creating volume group backup "/etc/lvm/backup/myVG" (seqno 7).
由於是每隔兩秒顯示一次訊息,因此訊息很長。
vgreduce myVG /dev/hdb1
pvremove /dev/hdb1
lvresize -l +100%FREE /dev/myVG/myLV
resize2fs /dev/myVG/myLV
最後的兩行指令,就是把hdb1完整的從LVM裡面拿掉,接著就是找個可以允許短暫downtime的時間,把舊硬碟抽走。別忘了新硬碟容量大多了,別忘了先把lv變大,在擴大filesystem!

目標8:LVM的轉移方案

假設今天想要換新的機器或是重灌系統,但是lvm裡面的資料還是要保留下來,我們該怎麼處理呢?大致的流程如下:

umount->vgchange(deactivate)->vgexport->系統重灌->vgimport->vgchange(activate)->mount

承續剛才的狀況:

umount /mnt/myLV
vgchange -a n myVG
vgexport myVG #可以藉由vgdisplay觀察是否有exported!

上述的指令便是停止vg的運作,因此所有在vg上的lv也都會全部終止運作,因此假設你在vg上切不只一個lv,則需要把所有掛載點都umount之後,vgchange才有可能終止活動。我終止這個vg並且匯出vg之後,關閉虛擬的os並開啟一個新的os,假設是SLES11好了;我們可以在SLES11上面利用vgdisplay找到這個vg:

vgimport myVG
vgchange -a y myVG
mkdir /export
mount /dev/myVG/myLV /export
如此一來便可以順利完成轉移。


參考文獻:

1. Redhat Enterprise Linux系統管理寶典 進階篇(陳永昇),第八章
2. Logical Volume Manager(一)(二)(林彥明)
3. RHEL3/4 之Logical Volume Manager(林彥明)
4. 鳥哥的私房菜:Logical Volume Manager

沒有留言: