5

数据盘上架

·13 分钟

1. 背景

1002 是我们实验室的一台 GPU 服务器,双卡 RTX 4000 Ada Generation,主要用来跑目标跟踪的训练和测试。之前数据都堆在系统盘上,根分区已经用了 76%。虽然有一块 1.8T 的移动固态硬盘临时挂在 /data 顶着,但那毕竟是借来的,不是长久之计。

现在,一块 9.1T 的企业级机械硬盘(HGST Ultrastar He10)已经装进机箱了,接下来要做的就是让系统认到它、格式化、把数据搬过去,然后把移动固态还回去。

+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 595.71.05              Driver Version: 595.71.05      CUDA Version: 13.2     |
+-----------------------------------------+------------------------+----------------------+
| GPU  Name                 Persistence-M | Bus-Id          Disp.A | Volatile Uncorr. ECC |
| Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Compute M. |
|=========================================+========================+======================|
|   0  NVIDIA RTX 4000 Ada Gene...    Off |   00000000:01:00.0 Off |                  Off |
| 30%   32C    P8              4W /  130W |       2MiB /  20475MiB |      0%      Default |
+-----------------------------------------+------------------------+----------------------+
|   1  NVIDIA RTX 4000 Ada Gene...    Off |   00000000:05:00.0  On |                  Off |
| 30%   32C    P8              7W /  130W |      10MiB /  20475MiB |      0%      Default |
+-----------------------------------------+------------------------+----------------------+

操作前的磁盘状态:

$ df -h
Filesystem                         Size  Used Avail Use% Mounted on
/dev/mapper/ubuntu--vg-ubuntu--lv  913G  655G  212G  76% /
/dev/sdb1                          1.8T  365G  1.4T  21% /data

根分区 76%,而 /data 是一块临时借来的移动固态。


2. 认盘

硬件装好了,系统能看到吗?先用 lsblk 看一下所有磁盘:

$ lsblk
NAME                      MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
sda                         8:0    0   9.1T  0 disk
sdb                         8:16   0   1.8T  0 disk
└─sdb1                      8:17   0   1.8T  0 part /data
sdc                         8:32   1  57.7G  0 disk
└─sdc1                      8:33   1  57.7G  0 part
nvme0n1                   259:0    0 931.5G  0 disk
├─nvme0n1p1               259:1    0     1G  0 part /boot/efi
├─nvme0n1p2               259:2    0     2G  0 part /boot
└─nvme0n1p3               259:3    0 928.5G  0 part
  └─ubuntu--vg-ubuntu--lv 252:0    0 928.5G  0 lvm  /

可以看到一个 9.1T 的 sda,没有分区、没有挂载点 —— 就是我们刚装上去的新盘。但怎么确认它就是那块 HGST?用 hdparm 查看磁盘的硬件信息:

$ sudo hdparm -I /dev/sda | head -20

/dev/sda:

ATA device, with non-removable media
        Model Number:       HGST HUH721010ALE600
        Serial Number:      JEHP68BN
        Firmware Revision:  LHGAT38Q
        Transport:          Serial, ATA8-AST, SATA 1.0a, SATA II Extensions,
                            SATA Rev 2.5, SATA Rev 2.6, SATA Rev 3.0

型号 HGST HUH721010ALE600 —— 这是 HGST(西数旗下)Ultrastar He10,企业级氦气封装硬盘,可靠性比普通消费级盘好很多。SATA III 接口,理论带宽 6Gbps。

💡 另外注意 lsblk 里还有一个 57.7G 的 sdcRM 列是 1(Removable),那是一个 U 盘,别选错设备。

还有一个小技巧:怎么区分机械硬盘(HDD)和固态硬盘(SSD)?

cat /sys/block/sda/queue/rotational

输出 1 表示旋转磁盘(HDD),0 表示固态(SSD)。我们的 sda 输出 1,确认是机械盘。


3. 磁盘使用的三层结构

在动手之前,先理解一下磁盘从"裸盘"到"能存文件"需要经过哪几步。可以把一块硬盘想象成一栋毛坯楼

第一层:分区表(楼的平面图) 决定这栋楼怎么隔间 —— 哪里到哪里是一个房间。常见的分区表有两种:MBR(老图纸,最大只认 2TB)和 GPT(新图纸,支持超大的楼)。

第二层:文件系统 = 格式化(装修风格) 每个房间怎么收纳东西。ext4 是 Linux 标配,NTFS 是 Windows 标配,exFAT 适合移动存储跨平台使用。

第三层:挂载(给房间编门牌号) 把装修好的房间接入走廊 —— 比如 /data 就是门牌号,进了这个门就能访问对应磁盘上的文件。

分区表决定怎么切,文件系统决定怎么存,挂载决定从哪访问。三步缺一不可。

另外,分区是可选的 —— 技术上可以跳过分区直接格式化整块盘(就像 loft 不隔墙也能住),但有分区表更规范:别人接手一看 lsblk 就能看清结构,而且以后想切出一块做别的用途也方便。分区表本身才几 KB,在 9.1T 面前连灰尘都算不上。


4. 分区

因为这块盘是 9.1T,超过了 MBR 的 2TB 上限,必须用 GPT 分区表。用 parted 来操作:

sudo parted /dev/sda

进入 (parted) 交互界面后,依次输入:

mklabel gpt
mkpart primary ext4 0% 100%
print
quit

解释一下:

  • mklabel gpt —— 创建 GPT 分区表
  • mkpart primary ext4 0% 100% —— 整块盘建一个分区,用百分比自动 4K 对齐
  • print —— 打印分区表确认
  • quit —— 退出

print 的输出:

Model: ATA HGST HUH721010AL (scsi)
Disk /dev/sda: 10.0TB
Sector size (logical/physical): 512B/4096B
Partition Table: gpt

Number  Start   End     Size    File system  Name     Flags
 1      1049kB  10.0TB  10.0TB  ext4         primary

完成后 lsblk 就能看到 sda 下面多了一个 sda1 分区。


5. 格式化

分区切好了,现在给它"装修" —— 创建文件系统:

sudo mkfs.ext4 -m 0 /dev/sda1

参数说明:

  • -m 0 —— 保留空间设为 0%。ext4 默认保留 5% 给 root 用户,在 9.1T 的盘上就是 455G,纯数据盘不需要这个,直接省下来。

格式化很快,十几秒就完成了。输出里有几个关键信息:

Creating filesystem with 2441608704 4k blocks and 305201152 inodes

3.05 亿个 inode —— 每个文件需要一个 inode,我们的数据集大约 2000 万个文件,完全够用。

踩坑:inode 不够

其实我第一次格式化时加了 -T largefile4 参数,以为数据集都是大文件。结果只分配了 238 万个 inode —— 连 2000 万个文件的零头都不够!

-T largefile4 的意思是"平均每 4MB 才分配一个 inode",适合存视频、大模型权重这种大文件。而我们的数据集是大量的小图片,用默认设置(每 16KB 一个 inode)才对。

⚠️ inode 数量在格式化后不能修改,选错了只能重新格式化。好在这时候盘上还没写数据,重来成本为零。


6. 数据迁移

现在新盘格式化好了,但旧的移动固态上还有 365G 数据要搬过来。策略是:先不动 /data,用临时挂载点完成数据迁移,最后再切换。这样万一复制出问题,数据还在旧盘上能兜底。

6.1 临时挂载

把新盘挂到一个临时位置:

sudo mkdir /data2
sudo mount /dev/sda1 /data2

df -h /data2 确认 9.1T 出现了。

6.2 rsync 复制

sudo rsync -ah --partial --info=progress2 /data/ /data2/

参数说明:

  • -a —— archive 模式,保留权限、时间戳、软链接等全部文件属性
  • -h —— 人类可读的大小(GB/MB)
  • --partial —— 支持断点续传,中断了再跑一次能接着传
  • --info=progress2 —— 只显示一行总进度(百分比 + 速度 + 剩余时间),不刷屏
  • /data/ —— ⚠️ 末尾的 / 很重要!表示复制目录里面的内容,不带斜杠会多嵌套一层

365G 数据,HDD 写入速度约 130-160 MB/s,大概跑了 37 分钟。

6.3 验证

复制完后再跑一次 rsync,它会自动扫描差异:

sudo rsync -ah --partial --info=progress2 /data/ /data2/

如果输出显示传输量为 0、几秒就跑完,说明数据完全一致。

0   0%    0.00kB/s    0:00:00 (xfr#0, to-chk=0/3884189)

0 差异,380 万个文件全部一致 ✅

踩坑:rsync 写到了根分区

操作过程中出了一个事故:我先卸载了 /data2,然后想卸载 /data 时失败了(有人在用),但 /data2 这个目录还在 —— 只是它不再指向 HDD 了,变成了根分区上的一个普通文件夹。这时候我习惯性地跑了一遍 rsync,结果数据写到了根分区上,差点把系统盘撑爆。

好在及时 Ctrl+C 了,只写了大约 9G。清理方法:

sudo rm -rf /data2/*          # 清掉误写的数据
sudo mount /dev/sda1 /data2   # 重新挂回 HDD

📌 教训:操作挂载之前先用 df -hmount | grep 确认挂载状态。目录存在 ≠ 磁盘挂在上面。


7. 切换挂载

数据迁移验证完毕,现在把 HDD 从临时位置 /data2 切到正式位置 /data

sudo umount /data2    # 卸载 HDD
sudo umount /data     # 卸载移动固态
sudo mount /dev/sda1 /data   # 把 HDD 挂到 /data

踩坑:target is busy

卸载 /data 时报了 target is busy —— 有人在占用这个目录。用 lsof 查看:

sudo lsof /data

发现一个同学的 bash 终端 cd/data/renzhonghang 里。让他退出(或者 sudo kill 掉进程)就好。

另外,我自己的终端也 cd 在 /data 里,也会导致 busy。看命令提示符 yustia@1002:/data$ 就能发现 —— 先 cd ~ 回到家目录再操作。

切换完用 df -h 确认:

df -h /data
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1       9.1T  368G  8.7T   4% /data

9.1T HDD 已经挂在 /data


8. 持久化:fstab

现在的挂载是临时的 —— 重启后就没了。要让系统开机自动挂载,需要写入 /etc/fstab

先拿到分区的 UUID:

sudo blkid /dev/sda1
/dev/sda1: UUID="8a77fcb2-9fcb-4b68-ad81-f4f675b8997d" ...

💡 为什么用 UUID 而不是 /dev/sda1?因为设备名不稳定 —— 插拔磁盘、加新盘、换 SATA 口都可能导致 sda 变成 sdb。UUID 是分区的唯一身份证,不会变。

编辑 /etc/fstab,把旧的移动固态 UUID 替换为新盘的:

UUID=8a77fcb2-9fcb-4b68-ad81-f4f675b8997d /data ext4 defaults,nofail 0 2

其中 nofail 表示:如果这个盘不在(比如坏了或者被拔了),系统照样能正常启动,不会卡在开机界面。

最后刷新 systemd 的缓存:

sudo systemctl daemon-reload

9. 旧盘善后

移动固态的数据已经全部迁移到 HDD 了,现在把它格式化还给原主。

因为这块盘要在 Windows 和 Linux 之间来回插,选 exFAT 格式:

文件系统WindowsLinux适合场景
NTFS✅ 原生⚠️ 靠 ntfs-3g 驱动固定硬盘、Windows 系统盘
exFAT✅ 原生✅ 内核原生(5.4+)移动存储、跨平台
sudo apt install exfatprogs -y
sudo mkfs.exfat -L "Portable" /dev/sdb1

格式化完成后安全弹出:

sudo eject /dev/sdb

拔盘,收工!


10. 最终状态

$ lsblk
NAME                      MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
sda                         8:0    0   9.1T  0 disk
└─sda1                      8:1    0   9.1T  0 part /data
sdb                         8:16   0   1.8T  0 disk
└─sdb1                      8:17   0   1.8T  0 part
nvme0n1                   259:0    0 931.5G  0 disk
├─nvme0n1p1               259:1    0     1G  0 part /boot/efi
├─nvme0n1p2               259:2    0     2G  0 part /boot
└─nvme0n1p3               259:3    0 928.5G  0 part
  └─ubuntu--vg-ubuntu--lv 252:0    0 928.5G  0 lvm  /

$ df -h
Filesystem                         Size  Used Avail Use% Mounted on
/dev/mapper/ubuntu--vg-ubuntu--lv  913G  655G  212G  76% /
/dev/sda1                          9.1T  368G  8.7T   4% /data
设备容量用途挂载点状态
nvme0n1931.5G系统盘(NVMe SSD)/
sda19.1T数据盘(HGST 企业级 HDD)/data✅ 新挂载
sdb1.8T移动固态(已格式化 exFAT)已拔除
💬

留言区待配置

部署 Twikoo 后端后,设置环境变量 NEXT_PUBLIC_TWIKOO_ENV_ID