
在實際運維里Debian系統(tǒng)上做“raid5lvm”組合幾乎是中小型Linux服務器最常碰到的存儲方案之一。我剛接手某公司那臺文件服務器時前一位運維留下的就是這套東西4塊數(shù)據(jù)盤做了RAID 5然后在上面疊加了一層LVM整個存儲池被切成了好幾個邏輯卷分別掛給項目目錄。RAID 5解決的是“多塊盤里壞一塊數(shù)據(jù)不丟”的問題LVM解決的是“容量不夠想在線擴”的問題兩個軟件包mdadm和lvm2就能把幾塊普通硬盤變成一塊既冗余又靈活的存儲空間。這篇內(nèi)容適合自己折騰家用NAS的也適合剛接手生產(chǎn)服務器的運維新人我會從設計思路講到具體命令再到故障處理盡量把每一步為什么這么做講清楚。1. 為什么偏偏是RAID 5LVM1.1 RAID級別的取舍我見過不少人一上來就問“RAID 5到底選幾塊盤”但事實上最重要的不是幾塊盤而是先想清楚你的場景到底吃哪一套冗余策略。RAID 0速度快但沒有冗余壞一塊盤全部數(shù)據(jù)清零適合純緩存類場景。RAID 1把數(shù)據(jù)完整復制兩份安全但有效容量直接打五折適合系統(tǒng)盤或者一兩塊盤的場景。RAID 10是鏡像加條帶性能和冗余平衡得很好但是最少4塊盤有效容量也只有一半。RAID 5則是把數(shù)據(jù)和校驗信息分散寫在所有盤上允許壞一塊盤而不丟數(shù)據(jù)3塊盤就能用有效容量是n-1塊盤的容量。RAID級別最少盤數(shù)有效容量冗余能力典型場景RAID 02100%無緩存、臨時數(shù)據(jù)RAID 1250%1塊盤系統(tǒng)盤、小容量數(shù)據(jù)RAID 53(n-1)/n1塊盤文件服務、備份數(shù)據(jù)RAID 10450%每組1塊盤數(shù)據(jù)庫、高IO應用我直接把RAID 5的容量公式放出來n塊盤做RAID 5有效容量 (n-1)/n × 總?cè)萘克?塊4T盤實際可用8T。這個公式在mdadm創(chuàng)建時也是這么計算的底層會把其中一塊盤的容量空間用作分布式校驗。很多人第一次看到RAID 5的校驗機制會疑惑“為什么壞一塊還能繼續(xù)讀寫”其實就是因為校驗塊分散在每一塊盤上任何一塊盤的數(shù)據(jù)都能通過其它n-1塊盤恢復出來。RAID 5的寫性能要額外算校驗所以隨機小塊寫入比RAID 10慢這是它天生的特點但順序讀寫和大多數(shù)文件服務器場景完全夠用。1.2 LVM為什么值得疊直接說RAID陣列本身有一個問題一旦創(chuàng)建容量基本是固定的。雖然mdadm支持在線擴容但總歸要先加盤、再調(diào)整陣列操作粒度比較粗。而LVM是另一層抽象它把底層RAID陣列看成一個物理卷PV再把空間切割成一個個PE多個PE組成卷組VG最后從VG里劃分邏輯卷LV。關鍵就是LV可以在VG還有空閑的情況下隨時在線擴大甚至縮小雖然縮小一般不建議在生產(chǎn)上隨便做。比如我做過的某單機項目中文件服務器起初LVM卷組里RAID 5陣列只有8T可用后來數(shù)據(jù)量漲到接近滿就加了盤把RAID擴成更大的陣列VG的空間隨之變大然后lvextend把LV撐大文件系統(tǒng)在線resize幾乎沒停服務。這就是RAID 5LVM組合最值錢的點也是為什么它在Debian系服務器上這么流行。2. Debian部署前的基礎準備2.1 硬件與軟件要求要在Debian下創(chuàng)建RAID 5LVM最少需要3塊獨立的硬盤注意是獨立硬盤而不是三塊邏輯分區(qū)。數(shù)據(jù)盤和系統(tǒng)盤最好分開不要把系統(tǒng)所在盤也加進RAID否則系統(tǒng)盤掛了整個系統(tǒng)都起不來RAID冗余形同虛設。如果是家用NAS或者小型服務器建議4塊盤起步多出來的一塊用來做熱備盤spare平時不參與寫入一旦某塊盤故障會自動頂替上去開始重建這個后面細講。系統(tǒng)層面需要安裝兩個軟件包mdadm負責管理軟件RAID陣列l(wèi)vm2負責LVM層的邏輯卷管理。Debian下安裝很簡單一條命令就能裝好。裝完建議順手確認一下兩個命令能正常執(zhí)行。apt update apt install -y mdadm lvm2 mdadm --version lvm version2.2 磁盤識別與盤符漂移做RAID之前最關鍵的準備工作不是敲命令而是認清楚哪塊盤是哪個物理設備。這個環(huán)節(jié)出錯的代價極高把系統(tǒng)盤和數(shù)據(jù)盤搞混了做進陣列系統(tǒng)分分鐘起不來。用lsblk看塊設備布局用fdisk -l看磁盤大小還可以用smartctl看序列號。更穩(wěn)妥的做法是用ls -l /dev/disk/by-id/查看所有磁盤的WWID或者廠商序列號不同廠商盤的命名格式不同但都能追溯到物理設備。生產(chǎn)環(huán)境里我習慣把每塊盤的盤位標簽和/dev/disk/by-id/的鏈接對應起來寫在一個小本子上避免開機盤符變化時憑感覺猜。經(jīng)驗更豐富一點的話也要注意Debian的udev規(guī)則重啟后/dev/sdX這種盤符順序可能因為內(nèi)核識別順序變化而徹底打亂。以前SATA盤少的時候還好現(xiàn)在NVMe和SATA混裝加上USB外接存儲盤符漂移幾乎是必然的。所以真正寫進mdadm和fstab的時候絕對不要依賴/dev/sdX而是用UUID后面的配置會專門處理這個。還有一個細節(jié)數(shù)據(jù)盤建議直接用整塊盤設備不需要先分區(qū)。mdadm可以直接在整塊盤上創(chuàng)建陣列很多老教程會讓人先分區(qū)再mdadm多一層分區(qū)表反而增加復雜度而且分區(qū)表出錯也會影響陣列識別。普通場景推薦整塊盤走到底。3. 創(chuàng)建RAID 5陣列3.1 mdadm的創(chuàng)建命令和參數(shù)確認磁盤無誤后就可以創(chuàng)建RAID 5陣列。典型命令是這樣的假設我有四塊數(shù)據(jù)盤/dev/sdb、/dev/sdc、/dev/sdd、/dev/sde我準備用前三塊做RAID 5第四塊做熱備盤。mdadm --create /dev/md0 --levelraid5 --raid-devices3 --spare-devices1 /dev/sdb /dev/sdc /dev/sdd /dev/sde命令說明--create是創(chuàng)建/dev/md0是陣列的設備名--levelraid5指定RAID級別--raid-devices3表示陣列由3塊組成--spare-devices1表示后面4個設備里第4個作為熱備盤。創(chuàng)建的時候還有一個重要參數(shù)叫做chunk size條帶大小它決定數(shù)據(jù)條帶化寫入時每個條帶塊的大小。mdadm默認是512K但這個默認值并不適合所有場景。如果存儲的是大量小文件比如代碼、配置目錄、數(shù)據(jù)庫日志建議把chunk size調(diào)小到64K或者128K小文件能更快地落盤。反過來如果主要存視頻、鏡像、備份數(shù)據(jù)這類大文件可以保持512K甚至用1M順序讀寫的吞吐更爽。在創(chuàng)建命令里加上chunk size參數(shù)mdadm --create /dev/md0 --levelraid5 --raid-devices3 --spare-devices1 --chunk128 /dev/sdb /dev/sdc /dev/sdd /dev/sde這里的128就是128K的意思。注意chunk參數(shù)不帶單位默認就是K不需要寫成128K。3.2 等待同步和狀態(tài)檢查創(chuàng)建完RAID 5陣列后系統(tǒng)會立即開始后臺同步rebuild目的就是讓整個陣列進入一致的冗余狀態(tài)。這個階段陣列還沒完全可用讀寫性能也會明顯下降不能急著格式化或者寫入數(shù)據(jù)。查看進度用cat /proc/mdstat輸出里會看到類似這樣的內(nèi)容Personalities : [raid6] [raid5] md0 : active raid5 sde[4](S) sdd[3] sdc[1] sdb[0] 109572224 blocks super 1.2 level 5, 128k chunk, algorithm 2 [3/3] [UUU] [....................] resync 2.5% (2745856/109572224) finish18.7min speed19473K/sec它包含的關鍵信息有好幾處陣列狀態(tài)是active raid5三塊工作盤為[3/3] [UUU]熱備盤是sde 4 同步百分比resync以及預計完成時間finish和實時速度speed。同步速度默認會限制避免把整機IO打滿等同步完成前不要做其它重IO操作。同步完成后可以再用詳細命令確認mdadm --detail /dev/md0這條命令會列出陣列的成員盤狀態(tài)、chunk大小、同步進度、壞塊數(shù)等完整信息。我習慣把它作為每次巡檢的第一條命令。3.3 陣列參數(shù)與完整性再補充一個容易踩坑的細節(jié)。創(chuàng)建時默認的metadata版本是1.2這個沒問題但如果你在很老的Debian版本或者某些特殊引導環(huán)境下可能需要考慮metadata版本兼容性。99%的現(xiàn)代系統(tǒng)直接用1.2即可不用刻意改。寫操作時也可以考慮給陣列加bitmap也就是位圖文件mdadm --grow /dev/md0 --bitmapinternal內(nèi)部位圖的好處是系統(tǒng)異常斷電重啟后不需要對整個陣列做全量同步只需要對位圖標記的“臟”區(qū)域做增量重建。這在生產(chǎn)環(huán)境里能省掉大把重建時間。我個人的建議是創(chuàng)建完成后順手加上。陣列層面的狀態(tài)顯示clean只表示元數(shù)據(jù)一致真正的數(shù)據(jù)一致性需要靠文件系統(tǒng)層面的檢查來兜底。Debian下可以定期對已掛載的ext4文件系統(tǒng)做只讀檢查e2fsck -fn /dev/vg_data/lv_projects-f是強制檢查-n表示只讀模式不會對文件系統(tǒng)做任何修改適合在線檢測。真正需要修復的時候才去掉-n但那時候最好先卸載或者維護窗口再操作。4. LVM疊加與容量管理4.1 PV、VG、LV三層邏輯LVM把存儲空間分成三層物理卷PV對應整個底層塊設備這里是/dev/md0卷組VG是多個PV拼起來的大容量池邏輯卷LV是最終格式化和掛載使用的“虛擬分區(qū)”。創(chuàng)建PV很簡單pvcreate /dev/md0創(chuàng)建完可以用pvs或者pvdisplay看狀態(tài)。在這里我要特別提醒PV一旦直接建在/dev/md0上以后整個陣列就被LVM接管如果臨時想把陣列直接當成普通塊設備就會多一步剝離操作但這不復雜后面如果想反悔可以用pvremove把PV信息清掉只要底層數(shù)據(jù)沒有格式化破壞就可以。然后創(chuàng)建VG并指定PE大小vgcreate vg_data /dev/md0PE物理擴展塊是VG的分配單位默認是4MiB。這個默認值不需要動除非你有特別大量的小邏輯卷需求一般保持默認即可。創(chuàng)建后再用vgs、vgdisplay確認卷組容量vgdisplay能看到VG的可用空間。接下來創(chuàng)建LVlvcreate -L 4T -n lv_projects vg_data這里的-L 4T表示直接分配4T空間給這個邏輯卷。如果你想用VG的全部剩余空間可以寫成-l 100%FREE。我一般會留出10%左右的VG空間不分配作為未來的快照空間或者應急擴容儲備因為一旦LV把VG占滿再想創(chuàng)建快照就沒有空間了。4.2 格式化與掛載LV建好后可以像普通分區(qū)一樣格式化。常見的文件系統(tǒng)是ext4如果新部署且數(shù)據(jù)不是特別敏感用xfs其實也推進得很廣泛但Debian默認工具鏈里ext4最順手下面的例子就用ext4。mkfs.ext4 /dev/vg_data/lv_projects格式化前再檢查一下確認這個設備名字沒有拼錯。格式化是不可逆的操作路徑寫錯了真的會出事。掛載測試mkdir -p /data/projects mount /dev/vg_data/lv_projects /data/projects df -h能正??吹饺萘亢蛼燧d點說明這個LV工作正常。df -h會顯示容量約等于創(chuàng)建時指定的4T減去文件系統(tǒng)自身開銷。4.3 在線擴展與快照擴展容量是LVM相對傳統(tǒng)分區(qū)最爽的地方。假設存儲空間滿了我先給RAID陣列加盤把新盤加入陣列如果當初留了熱備盤直接拔掉故障盤和加入新盤的重建流程都比較順暢。陣列擴容完成后原來創(chuàng)建的PV大小會自動跟隨變化但VG不會自動把新增空間納入可用還要執(zhí)行pvresize /dev/md0 vgspvresize的作用就是刷新PV大小讓VG知道陣列容量變了。然后就可以擴展LV和文件系統(tǒng)lvextend -L 2T /dev/vg_data/lv_projects resize2fs /dev/vg_data/lv_projects注意resize2fs只對ext4有效如果你當初選擇xfs就改xfs_growfs這倆命令的參數(shù)形式完全不同。很多新手擴容時文件系統(tǒng)忘了同步擴展邏輯卷已經(jīng)變大但df看到的容量沒變就是這一步漏了。再額外講一下LVM快照??煺赵趥浞輬鼍袄锓浅S杏帽热缫谶\行中的存儲上打一個一致的備份點就可以對LV做快照lvcreate -L 200G -s -n snap_projects /dev/vg_data/lv_projects快照創(chuàng)建時幾乎是瞬間完成的原理是寫時復制CoW原始數(shù)據(jù)塊發(fā)生變化前先把舊數(shù)據(jù)移到快照區(qū)所以快照只記錄增量變化不能用于長期備份只適合做短期一致性備份點??煺湛臻g用完了快照會自動失效所以給快照分配的大小要比備份期間預計寫入的數(shù)據(jù)量稍大。5. 開機自動裝配與文件系統(tǒng)掛載5.1 生成mdadm配置并更新initramfs如果希望系統(tǒng)重啟后RAID陣列自動被識別必須保存陣列配置?,F(xiàn)在Debian里的mdadm配置通常寫在/etc/mdadm/mdadm.conf用如下命令把當前陣列的信息追加進去mdadm --detail --scan /etc/mdadm/mdadm.conf查看生成的內(nèi)容里面會有一行類似ARRAY /dev/md0 metadata1.2 namehostname:0 UUIDxxxx:xxxx:xxxx:xxxx這里的UUID是陣列的唯一標識mdadm啟動時靠這個UUID而不是/dev/sdX去識別陣列所以盤符漂移不影響陣列裝配。配好之后還要更新initramfs因為mdadm的配置要打進初始內(nèi)存盤里系統(tǒng)引導階段才能識別update-initramfs -u這一步不能漏否則重啟時系統(tǒng)可能因為無法識別RAID而進入initramfs提示符或者直接找不到根文件系統(tǒng)。5.2 fstab自動掛載文件系統(tǒng)掛載同樣不能依賴盤符要用UUID。先用blkid查到LV的UUIDblkid /dev/vg_data/lv_projects輸出會包含UUID然后編輯/etc/fstab加一行類似UUIDxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx /data/projects ext4 defaults,noatime 0 2這里的noatime是個很實用的掛載參數(shù)它可以關閉atime更新減少不必要的磁盤寫入。對SSD和機械盤都有好處。至于最后的兩個數(shù)字0表示不進行dump備份2表示開機時按順序執(zhí)行fsck檢查。根分區(qū)一般是1其它數(shù)據(jù)分區(qū)可以用2。配置好fstab后建議先手動卸載再掛載驗證一次umount /data/projects mount -a df -hmount -a會把fstab里所有未掛載條目都掛一遍如果這一條配置有錯會立刻報出來不會拖到重啟才發(fā)現(xiàn)。這一步是驗證fstab正確性的最佳實踐比直接重啟要安全得多。6. 故障場景與排查經(jīng)驗6.1 RAID降級與壞盤處理做運維的人最怕半夜收到監(jiān)控告警說RAID降級。RAID 5允許壞一塊盤但只要壞盤沒處理陣列就處于降級狀態(tài)性能會受影響而且萬一第二塊盤再出問題就是全盤皆輸。當發(fā)現(xiàn)陣列降級第一步是確認是哪塊盤出了問題mdadm --detail /dev/md0輸出里壞盤會標記為removed或者faulty同時狀態(tài)變成[2/3] [UU_]。在確認物理盤已替換或故障盤被標記移除后把故障盤從陣列中移除mdadm /dev/md0 --fail /dev/sdd mdadm /dev/md0 --remove /dev/sdd然后插入新盤mdadm /dev/md0 --add /dev/sdf如果新盤被識別為陣列的缺口成員mdadm會自動開始重建數(shù)據(jù)。如果沒有熱備盤整個過程需要手動操作如果當時留了熱備盤故障盤失效后熱備盤就會自動接管狀態(tài)直接進入rebuild。所以我在2.1里的建議是4塊盤起步多出來那塊做熱備對白天忙碌或者半夜沒有運維盯的場景特別有用。重建期間的/proc/mdstat會顯示resync或者recovery進度速度一般受限于整機IO和盤本身能力。重建期間盡量避免在陣列上做高負載讀寫降低二次故障的風險。6.2 擴容后文件系統(tǒng)不一致與檢查我在前面提過lvextend之后忘了resize2fs是常見坑。這個問題還有一個變種擴容RAID陣列以后LV大小已經(jīng)變大了但文件系統(tǒng)是后來才想起來resize這時候不要慌直接重新跑一遍resize2fs /dev/vg_data/lv_projects就行resize2fs是冪等的已經(jīng)擴展到目標大小就不會重復動作。還有另一種情況是fstab掛載失敗系統(tǒng)啟動時直接進入到緊急模式emergency mode。這種問題多數(shù)是因為UUID變了或者mdadm.conf沒有正確更新導致陣列沒有裝配。排查順序先看blkid確認設備UUID再看/etc/fstab里的UUID是否匹配再看mdadm.conf里的陣列UUID是否在最后看initramfs是否包含新配置。一般三步能定位90%的問題。定期做數(shù)據(jù)完整性檢查也是值得納入巡檢計劃的。對于一個已經(jīng)穩(wěn)定運行的RAID 5陣列每季度做一次只讀的e2fsck檢查配合smartctl看各塊盤的SMART健康信息可以提前發(fā)現(xiàn)隱患避免被動的故障處理。6.3 性能與寫入策略不想把優(yōu)化寫成玄學只說幾個我實測下來最影響RAID 5體驗的點。首先是RAID 5的隨機寫性能天然劣勢。因為每寫一次數(shù)據(jù)都要同步更新校驗在小塊隨機寫入場景比如數(shù)據(jù)庫會很吃虧。如果應用對隨機寫要求高應該選RAID 10不要指望RAID 5通過參數(shù)調(diào)整變成快。RAID 5適合順序讀寫多、并發(fā)不算極端的場景。其次是write-back cache的設置。mdadm在較新內(nèi)核支持write-behind模式但通常要配電池保護卡或者UPS才能安全啟用否則突然斷電會造成數(shù)據(jù)不一致。沒有電池保護卡的普通服務器我建議保守一點不要強制加write-behind默認的write-through策略雖然慢一點但穩(wěn)。最后是陣列同步速度限制??梢杂孟旅婷钫{(diào)整echo 50000 /proc/sys/dev/raid/speed_limit_min echo 200000 /proc/sys/dev/raid/speed_limit_max單位是KB/s這個調(diào)整只在當前運行期間有效重啟會恢復默認。在預先規(guī)劃好的維護窗口里調(diào)高一點能加速重建但不建議在業(yè)務高峰調(diào)高反而拖垮整機IO。想長期修改可以寫在/etc/sysctl.d/里但我個人傾向只臨時調(diào)整重建設完就恢復默認。我自己折騰過不少存儲組合RAID 5LVM在Debian上的這套流程算是性價比很高的“標準答案”。每次做這類操作我的個人習慣是先看圖再動手lsblk確認一遍盤mdadm --detail確認一遍陣列blkid確認一遍文件系統(tǒng)三個命令各花幾秒鐘換取的是深夜不接報警電話的安穩(wěn)。還有一句必須有的話——RAID從來不是備份陣列的冗余只防硬件故障防不了誤刪和邏輯錯誤真正重要的數(shù)據(jù)該做備份還是老實做多一層快照也只是增援部隊不是保險箱。