DigitalOcean 主機磁盤 Ext4 轉 XFS
重要:本文中的操作具有極大風險,僅供具備相關經驗的讀者參考,請勿當成手冊來操作,操作前請務必備份數據。本文作者對可能的風險以及後果不承擔任何責任。
重要:本文中的操作具有極大風險,僅供具備相關經驗的讀者參考,請勿當成手冊來操作,操作前請務必備份數據。本文作者對可能的風險以及後果不承擔任何責任。
重要:本文中的操作具有極大風險,僅供具備相關經驗的讀者參考,請勿當成手冊來操作,操作前請務必備份數據。本文作者對可能的風險以及後果不承擔任何責任。
出於目前尚未知曉的原因,使用本文的思路對 Fedora 主機無法實操成功。
本文以將安裝於 ext4 上的 debian 遷移到 xfs 為例。
利用 Recovery 進入修復模式,do 會掛載一個 debian 或 ubuntu 的 live 鏡像方便我們操作。
進入入口在 Recovery>Boot from Recovery ISO,記得在切換啟動盤前先關機。
首先我們需要了解 Do 的虛擬主機的磁盤構成
Disk /dev/vda: 20 GiB, 21474836480 bytes, 41943040 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 4693DC13-C1AD-40C1-91D0-627B62A55102
Device Start End Sectors Size Type
/dev/vda1 6144 41943006 41936863 20G Linux filesystem
/dev/vda2 2048 6143 4096 2M BIOS boot
Do 的雲主機採用 MBR 方式進行引導,/dev/vda1 就是我們日常使用的 root 分區,危險操作主要是針對它。而/dev/vda2(即 BIOS boot)分區是保留著用於讓 grub 在其中插入 core.img。這個分區通常在實踐中是必須的(但不是理論上),因為 grub 的機理為在 MBR 512 字節結束處 到 第一個分區之間的空閒空間插入 core.img,所以理論上只要中間的空閒空間足夠,不要 BIOS boot 也可以,但實踐中,這個空間一般是不夠的,所以為了空出足夠的磁盤空間來插入 core.img,需要一個大小在 1M-2M 之間的 BIOS boot 分區,即當前的/dev/vda2。
不要試著去掛載或讀取/dev/vda2,如果我們看到有針對/dev/vda2 的報錯,也千萬不要嘗試去修復/dev/vda2,直接無視掉就好了。
對於大多數/dev/vda1 來說(除了 centos 8 虛擬主機默認是 xfs,BSD 默認是 zfs),do 通常默認的 ext4 格式。而好消息是,ext4 可以收縮,所以我們可以把/dev/vda1 裁剪到一個更小的大小,這樣就在它後面留下了空餘,在空餘處可以建立一個臨時 XFS 分區,然後把/dev/vda1 的內容複製到新分區上。
收縮/dev/vda1和建立臨時分區/dev/vda3
e2fsck -f /dev/vda1
輸出
e2fsck 1.44.1 (24-Mar-2018)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
/dev/vda1: 32002/1310720 files (0.1% non-contiguous), 339149/5242107 blocks
不報錯就是好消息。
然後收縮它,由於我這裡用的是一臺新創建的 VPS 來示範,所以它的內容比較小,大概只用了 2G 左右,為了保險起見,我把它收縮到 5G(原來是 20G)
resize2fs /dev/vda1 5G
輸出
resize2fs 1.44.1 (24-Mar-2018)
Resizing the filesystem on /dev/vda1 to 1310720 (4k) blocks.
The filesystem on /dev/vda1 is now 1310720 (4k) blocks long.
注意這一步還沒完,它的作用僅僅是把/dev/vda1 上的文件給全部集中到前 5G 的空間,而並沒有改變分區記錄,我們還需要手動利用 fdisk 操作來實現分區記錄上的收縮。
fdisk /dev/vda,然後打印下現有的分區,我們會看到
Disk /dev/vda: 20 GiB, 21474836480 bytes, 41943040 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 4693DC13-C1AD-40C1-91D0-627B62A55102
Device Start End Sectors Size Type
/dev/vda1 6144 41943006 41936863 20G Linux filesystem
/dev/vda2 2048 6143 4096 2M BIOS boot
Partition table entries are not in disk order.
果然分區記錄沒變,所以現在我們刪除分區 1,然後再建立分區 1,注意在選擇結束扇區範圍時寫+6G(比剛才的 5G 再大一點,為了保險)。
Command (m for help): d
Partition number (1,2, default 2): 1
Partition 1 has been deleted.
Command (m for help): n
Partition number (1,3-128, default 1): 1
First sector (34-41943006, default 6144):
Last sector, +sectors or +size{K,M,G,T,P} (6144-41943006, default 41943006): +6G
Created a new partition 1 of type 'Linux filesystem' and of size 6 GiB.
Partition #1 contains a ext4 signature.
Do you want to remove the signature? [Y]es/[N]o: n
Command (m for help): p
Disk /dev/vda: 20 GiB, 21474836480 bytes, 41943040 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 4693DC13-C1AD-40C1-91D0-627B62A55102
Device Start End Sectors Size Type
/dev/vda1 6144 12589055 12582912 6G Linux filesystem
/dev/vda2 2048 6143 4096 2M BIOS boot
Partition table entries are not in disk order.
別急著 w,我們再在空餘出的空間上建立一個新分區/dev/vda3。
Command (m for help): n
Partition number (3-128, default 3):
First sector (12589056-41943006, default 12589056):
Last sector, +sectors or +size{K,M,G,T,P} (12589056-41943006, default 41943006):
Created a new partition 3 of type 'Linux filesystem' and of size 14 GiB.
Command (m for help): p
Disk /dev/vda: 20 GiB, 21474836480 bytes, 41943040 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 4693DC13-C1AD-40C1-91D0-627B62A55102
Device Start End Sectors Size Type
/dev/vda1 6144 12589055 12582912 6G Linux filesystem
/dev/vda2 2048 6143 4096 2M BIOS boot
/dev/vda3 12589056 41943006 29353951 14G Linux filesystem
Partition table entries are not in disk order.
然後 write。
Command (m for help): w
The partition table has been altered.
Calling ioctl() to re-read partition table.
Syncing disks.
再檢查一下收縮後的 vda1
e2fsck /dev/vda1
應看到檢查通過,輸出類似於下面的結果
e2fsck 1.44.1 (24-Mar-2018)
/dev/vda1: clean, 32002/327680 files, 276698/1310720 blocks
將/dev/vda1的文件備份到/dev/vda3
首先需要給 vda3 建立新的文件系統,我這裡建立的是 xfs,當然我們也可以建立其它的(比如再來一個 ext4),因為這個分區只是臨時存下文件,最後還是要刪除掉(就像編程時 swap 算法裡的臨時變量)。
root@yunlingz:~# mkfs.xfs /dev/vda3
meta-data=/dev/vda3 isize=512 agcount=4, agsize=917311 blks
= sectsz=512 attr=2, projid32bit=1
= crc=1 finobt=1, sparse=0, rmapbt=0, reflink=0
data = bsize=4096 blocks=3669243, imaxpct=25
= sunit=0 swidth=0 blks
naming =version 2 bsize=4096 ascii-ci=0 ftype=1
log =internal log bsize=4096 blocks=2560, version=2
= sectsz=512 sunit=0 blks, lazy-count=1
realtime =none extsz=4096 blocks=0, rtextents=0
然後掛載 vda1 和 vda3,並把 vda1 上的文件拷貝到 vda3
root@yunlingz:~# mkdir /mnt/old
root@yunlingz:~# mkdir /mnt/new
root@yunlingz:~# mount /dev/vda1 /mnt/old
root@yunlingz:~# mount /dev/vda3 /mnt/new
root@yunlingz:~# rsync -zahP /mnt/old/ /mnt/new/
核心的一步:卸載 vda1 的掛載,把 vda1 重新格式化成 XFS 分區,再重新掛載,再把 vda3 上的文件重新拷貝回 vda1
root@yunlingz:~# umount /dev/vda1
root@yunlingz:~# mkfs.xfs /dev/vda1 -f
meta-data=/dev/vda1 isize=512 agcount=4, agsize=393216 blks
= sectsz=512 attr=2, projid32bit=1
= crc=1 finobt=1, sparse=0, rmapbt=0, reflink=0
data = bsize=4096 blocks=1572864, imaxpct=25
= sunit=0 swidth=0 blks
naming =version 2 bsize=4096 ascii-ci=0 ftype=1
log =internal log bsize=4096 blocks=2560, version=2
= sectsz=512 sunit=0 blks, lazy-count=1
realtime =none extsz=4096 blocks=0, rtextents=0
root@yunlingz:~# mount /dev/vda1 /mnt/old/
root@yunlingz:~# rsync -zahP /mnt/new/ /mnt/old/
刪除/dev/vda3並重建和擴容/dev/vda1
注意下面不要卸載錯分區,要卸載的是 vda3,vda1 就讓它在/mnt/old 繼續掛著。然後我們把 vda3 格式化一下。
root@yunlingz:~# umount /mnt/new
root@yunlingz:~# mkfs.xfs /dev/vda3 -f
meta-data=/dev/vda3 isize=512 agcount=4, agsize=917311 blks
= sectsz=512 attr=2, projid32bit=1
= crc=1 finobt=1, sparse=0, rmapbt=0, reflink=0
data = bsize=4096 blocks=3669243, imaxpct=25
= sunit=0 swidth=0 blks
naming =version 2 bsize=4096 ascii-ci=0 ftype=1
log =internal log bsize=4096 blocks=2560, version=2
= sectsz=512 sunit=0 blks, lazy-count=1
realtime =none extsz=4096 blocks=0, rtextents=0
再 fdisk 上進行兩個操作:刪除/dev/vda3,重建/dev/vda1。這次重建/dev/vda1時直接讓其使用盡可能大的空間(即吃掉 vda3 刪掉後空出來的部分)
root@yunlingz:~# fdisk /dev/vda
Welcome to fdisk (util-linux 2.31.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
Command (m for help): d
Partition number (1-3, default 3): 3
Partition 3 has been deleted.
Command (m for help): d
Partition number (1,2, default 2): 1
Partition 1 has been deleted.
Command (m for help): n
Partition number (1,3-128, default 1): 1
First sector (34-41943006, default 6144):
Last sector, +sectors or +size{K,M,G,T,P} (6144-41943006, default 41943006):
Created a new partition 1 of type 'Linux filesystem' and of size 20 GiB.
Partition #1 contains a xfs signature.
Do you want to remove the signature? [Y]es/[N]o: n
Command (m for help): p
Disk /dev/vda: 20 GiB, 21474836480 bytes, 41943040 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 4693DC13-C1AD-40C1-91D0-627B62A55102
Device Start End Sectors Size Type
/dev/vda1 6144 41943006 41936863 20G Linux filesystem
/dev/vda2 2048 6143 4096 2M BIOS boot
Partition table entries are not in disk order.
Command (m for help): w
The partition table has been altered.
Syncing disks.
注意,在上面的 fdisk 輸出中,/dev/vda1 看起來已經從被裁減的 6G 擴容到 20G,但是/dev/vda1 上的 xfs 文件系統結構並沒有得到重建,它目前能利用的依然只有 6G,我們可以驗證下這種說法
root@yunlingz:~# df -h /mnt/old
Filesystem Size Used Avail Use% Mounted on
/dev/vda1 6.0G 1012M 5.1G 17% /mnt/old
要使得 xfs 文件系統能把吃掉 vda3 的空間給利用起來,需要xfs_growfs工具。
root@yunlingz:~# xfs_growfs /mnt/old
meta-data=/dev/vda1 isize=512 agcount=4, agsize=393216 blks
= sectsz=512 attr=2, projid32bit=1
= crc=1 finobt=1 spinodes=0 rmapbt=0
= reflink=0
data = bsize=4096 blocks=1572864, imaxpct=25
= sunit=0 swidth=0 blks
naming =version 2 bsize=4096 ascii-ci=0 ftype=1
log =internal bsize=4096 blocks=2560, version=2
= sectsz=512 sunit=0 blks, lazy-count=1
realtime =none extsz=4096 blocks=0, rtextents=0
data blocks changed from 1572864 to 5242107
root@yunlingz:~# df -h /mnt/old
Filesystem Size Used Avail Use% Mounted on
/dev/vda1 20G 1.1G 19G 6% /mnt/old
現在才算正常。我們還可以用 xfs_repair 來檢查下我們現在的 vda1 有沒有錯誤(注意得先卸載 vda1)(此步非必須)。
root@yunlingz:~# umount /mnt/old
root@yunlingz:~# xfs_repair /dev/vda1
root@yunlingz:~# mount /dev/vda1 /mnt/old
(記得再把 vda1 掛載回來)
修改fstab記錄 以及 修復grub
首先 chroot 到原系統,然後把原先的 boot 備份一下
umount /dev/vda1
mount /dev/vda1 /mnt
mount -t proc none /mnt/proc
mount -o bind /dev /mnt/dev
mount -t sysfs sys /mnt/sys
chroot /mnt/ /bin/bash
root@yunlingz:/# cd ~
root@yunlingz:~# cp -R /boot/ ./boot_backup
然後修復 grub 引導
root@yunlingz:~# grub-install --target=i386-pc /dev/vda
Installing for i386-pc platform.
Installation finished. No error reported.
root@yunlingz:~# grub-mkconfig -o /boot/grub/grub.cfg
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-4.19.0-10-cloud-amd64
Found initrd image: /boot/initrd.img-4.19.0-10-cloud-amd64
done
注意現在還沒有結束,因為啟動系統時的掛載配置/etc/fstab 還寫的是原來掛載 ext4 分區的記錄,我們需要改成 xfs 的。
root@yunlingz:~# cp /etc/fstab /root/fstab.backup
root@yunlingz:~# vim /etc/fstab
更改後的/etc/fstab
# /etc/fstab: static file system information.
# UUID=4e8b8101-6a06-429a-aaca-0ccd7ff14aa1 / ext4 errors=remount-ro 0 1
/dev/vda1 / xfs defaults,noatime 0 1
至此全部過程結束。
現在退出,然後關機,把啟動盤從 Boot from Recovery ISO 切換回 Boot from Hard Drive,再開機,理應能直接用 ssh 連上系統了。
❯ ssh root@xxx.xxx.xxx.xxx
...
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
root@yunlingz:~# ls
boot_backup fstab.backup
root@yunlingz:~# mount | grep vda
/dev/vda1 on / type xfs (rw,noatime,attr2,inode64,noquota)
為什麼建議數據服務器使用XFS而非ext4
目前 DO 的雲主機,除了 BSD 和 CentOS 8,其它的主機都默認用 ext4 做文件系統。ext4 在穩定性上不如 xfs,在數據庫如 pg 的隨機讀寫效率上也低一些。XFS 的硬盤壞了,多數時候,只要 XFS 的日誌還在,我們還能快速把硬盤搶救回來,而 ext4 的修復則更具不確定性。
另一個誤區是:日誌型數據庫保證了數據的安全,所以不需要關注 file system 的安全性。 實際上:日誌型數據庫的理論安全多是建立在 file system 不出現未定義動作的前提下,而 posix 對 file system 在邊緣狀況發生後的動作多為未定義——是的,某些物理性災難發生後,file system 想怎麼做該怎麼做基本是它自己看著辦——換而言之,如果我們使用了某符合 posix 接口但可靠性極差的 fs,我們也不要指望數據庫的日誌能寫得多可靠,更不要指望數據庫的 data 有保證,即使這個數據庫使用了多麼先進的讀寫邏輯。