[{"data":1,"prerenderedAt":1307},["ShallowReactive",2],{"content:\u002Fposts\u002Fzfs-pool-migration-reconstruction-guide":3,"surround:\u002Fposts\u002Fzfs-pool-migration-reconstruction-guide":1297},{"id":4,"title":5,"body":6,"categories":1267,"date":1269,"description":1270,"draft":1271,"extension":1272,"image":1273,"meta":1274,"navigation":737,"path":1276,"permalink":1273,"pinned":1271,"published":1273,"readingTime":1277,"recommend":1273,"references":1273,"seo":1282,"sitemap":1283,"stem":1284,"tags":1285,"type":1295,"updated":1269,"__hash__":1296},"content\u002Fposts\u002Fposts\u002Fzfs-pool-migration-reconstruction-guide.md","数据无价：ZFS 存储池高可靠迁移与重建实战",{"type":7,"value":8,"toc":1229},"minimark",[9,19,23,40,47,57,64,87,91,96,124,128,138,175,179,219,223,234,240,256,260,274,281,287,312,316,320,342,348,355,363,368,440,455,473,479,483,487,497,504,510,526,530,536,607,611,614,620,626,629,633,639,643,649,656,660,666,670,676,682,689,695,699,765,769,775,781,793,797,803,815,819,825,839,846,852,865,869,872,878,881,887,891,897,900,904,921,924,930,934,941,1039,1046,1069,1073,1215],[10,11,15],"alert",{"type":12,"title":13,"icon":14},"info","AI 迁移提示","tabler:robot",[16,17,18],"p",{},"本文由 AI 协助从旧站迁移，尚未完成逐篇人工审校；内容如有疏漏，将在复核后修订。",[20,21,22],"h2",{"id":22},"为什么要做这件事",[16,24,25,26,30,31,35,36,39],{},"一台 Proxmox VE 上有一个名为 ",[27,28,29],"code",{"code":29},"ssd"," 的 ZFS 池，跑着若干虚拟机和 LXC 容器。随着机器增加，想把原来的",[32,33,34],"strong",{},"条带（无冗余）池","改成 ",[32,37,38],{},"RAIDZ1（类似 RAID5）","：加一层磁盘冗余，一块盘坏了数据还在。",[16,41,42,43,46],{},"但 ZFS 池一旦建好，",[32,44,45],{},"\"由条带改 RAIDZ1\" 是做不到在线改的","——必须销毁原池重建。于是整套流程就变成：",[48,49,54],"pre",{"className":50,"code":52,"language":53},[51],"language-text","原池 ssd (条带)\n    ↓ 1. 备份配置 + 停机\n    ↓ 2. snapshot + zfs send\n外置盘 sdg (temp_backup)\n    ↓ 3. 验证备份完整 ← ★ 不通过就回头\n    ↓ 4. 销毁原池、重建为 RAIDZ1  ← ★ 不可逆分水岭\n新池 ssd (RAIDZ1)\n    ↓ 5. 反向 zfs send 恢复\n    ↓ 6. 恢复 PVE 配置、启动 VM\n    ↓ 7. 清理临时池\n完成\n","text",[27,55,52],{"__ignoreMap":56},"",[16,58,59,60,63],{},"核心思想：",[32,61,62],{},"借一块外置盘 sdg 做中转站","。原池 → 外置盘 → 新池。",[10,65,68],{"type":66,"title":67},"error","这是不可逆操作，请先读完整篇再动手",[16,69,70,71,74,75,78,79,82,83,86],{},"本流程涉及 ",[27,72,73],{"code":73},"zpool export"," + ",[27,76,77],{"code":77},"zpool create"," 两个真正销毁原池的命令。一旦执行，原池 label 被覆盖，",[32,80,81],{},"没有撤销键","。中间任何一步出错，数据恢复只能靠外置备份盘。",[32,84,85],{},"强烈建议做这套操作前额外准备一份独立备份","（比如 PBS 或 rsync 到另一台 NAS），而不是只信任这里的 sdg 中转盘。",[20,88,90],{"id":89},"_1-前置条件与风险认知","1. 前置条件与风险认知",[92,93,95],"h3",{"id":94},"_11-硬件前提","1.1 硬件前提",[97,98,99,118],"ul",{},[100,101,102,105,106,114,117],"li",{},[32,103,104],{},"外置备份盘 sdg 容量 ≥ 原池已用量 × 1.2","\n先查原池实际占用：",[48,107,112],{"className":108,"code":110,"language":111,"meta":56},[109],"language-bash","zpool list ssd\n# NAME   SIZE   ALLOC   FREE    ...\n#                 ↑ 这一列就是已用量\n","bash",[27,113,110],{"__ignoreMap":56},[115,116],"br",{},"如果 ALLOC 是 800G，备份盘至少需要 1T（留 20% 余量，避免 ZFS 在 95% 以上性能骤降）。",[100,119,120,123],{},[32,121,122],{},"原池所有 VM \u002F LXC 镜像要能一起装下","：用同一块备份盘，不要分散到多个盘。",[92,125,127],{"id":126},"_12-pve-架构前提","1.2 PVE 架构前提",[16,129,130,131,134,135,137],{},"本文流程针对的是",[32,132,133],{},"数据池","（比如名为 ",[27,136,29],{"code":29}," 的 ZFS 池，挂载在 PVE 之外存放 VM 镜像）。",[10,139,142,157,160,166],{"type":140,"title":141},"warning","不要对 PVE 系统根池 rpool 使用本流程",[16,143,144,145,148,149,152,153,156],{},"如果你的 PVE 本身就是以 ",[32,146,147],{},"root-on-ZFS"," 的方式安装（PVE 安装时选了 ZFS 选项），那么 ",[27,150,151],{"code":151},"rpool"," 是系统根池。",[32,154,155],{},"本文流程不适用于 rpool","——重建 rpool 涉及 bootloader、initramfs、UEFI 条目等复杂操作，走本文步骤会让系统无法启动。",[16,158,159],{},"先确认一下：",[48,161,164],{"className":162,"code":163,"language":111,"meta":56},[109],"zpool list\n# 看是否有 rpool 以及它是不是本文要操作的池\nmount | grep 'on \u002F '\n# 看根文件系统是否来自 ZFS\n",[27,165,163],{"__ignoreMap":56},[16,167,168,171,172,174],{},[32,169,170],{},"本文针对的是非根的数据池","，比如 ",[27,173,29],{"code":29}," 这种专门放 VM 镜像的池。",[92,176,178],{"id":177},"_13-关键事实建池后不可改","1.3 关键事实（建池后不可改）",[97,180,181,190,203],{},[100,182,183,189],{},[32,184,185,188],{},[27,186,187],{"code":187},"ashift"," 值一旦建池就锁死","，以后不能改。选错了就是永久性的性能问题（见第 4.2 节原理）。",[100,191,192,198,199,202],{},[32,193,194,197],{},[27,195,196],{"code":196},"zpool create -f"," 一执行，原盘上的 ZFS label 立即被覆盖","，原池再也 ",[27,200,201],{"code":201},"import"," 不回来。",[100,204,205,212,213,215,216,218],{},[32,206,207,208,211],{},"PVE 的 VM 配置文件 ",[27,209,210],{"code":210},"\u002Fetc\u002Fpve\u002Fqemu-server\u002F*.conf"," 不在 ZFS 池上","（它们在 pmxcfs 的 SQLite 里），所以销毁 ",[27,214,29],{"code":29}," 池不会直接丢配置。但 VM 磁盘镜像（ZVOL）在 ",[27,217,29],{"code":29}," 池里，没备份就丢了。",[20,220,222],{"id":221},"_2-备份-pve-配置文件必做的第一步","2. 备份 PVE 配置文件（必做的第一步）",[16,224,225,226,229,230,233],{},"这一步顺序",[32,227,228],{},"非常关键","——放在整个流程最前面，而不是恢复阶段。原因：虚拟机的 CPU \u002F 内存 \u002F 磁盘映射 \u002F 网卡配置都在 ",[27,231,232],{"code":232},"*.conf"," 里，丢了就没法启动 VM（就算磁盘恢复了也不知道怎么拼回去）。",[48,235,238],{"className":236,"code":237,"language":111,"meta":56},[109],"mkdir -p \u002Froot\u002Fpve-config-backup\ncp -a \u002Fetc\u002Fpve\u002Fqemu-server\u002F*.conf \u002Froot\u002Fpve-config-backup\u002F\ncp -a \u002Fetc\u002Fpve\u002Flxc\u002F*.conf \u002Froot\u002Fpve-config-backup\u002F\n\n# 确认备份有内容\nls -lh \u002Froot\u002Fpve-config-backup\u002F\n",[27,239,237],{"__ignoreMap":56},[10,241,243,250],{"type":242},"tip",[16,244,245,246,249],{},"如果你不想只放在本机 ",[27,247,248],{"code":248},"\u002Froot\u002F","（万一根盘也出问题就一起丢了），可以顺手打包发到另一台机器：",[48,251,254],{"className":252,"code":253,"language":111,"meta":56},[109],"tar czf pve-config-backup-$(date +%F).tar.gz \u002Froot\u002Fpve-config-backup\u002F\nscp pve-config-backup-$(date +%F).tar.gz user@backup-host:\u002Fpath\u002F\n",[27,255,253],{"__ignoreMap":56},[20,257,259],{"id":258},"_3-停止所有虚拟机和容器","3. 停止所有虚拟机和容器",[16,261,262,265,266,269,270,273],{},[32,263,264],{},"为什么必须停机","：",[27,267,268],{"code":268},"zfs snapshot"," 虽然在文件系统层是原子的，但 VM 内存里还没落盘的数据",[32,271,272],{},"没法被 snapshot 到","。从 VM 视角看，这相当于\"突然断电\"——重启后可能出现文件系统不一致，严重时 VM 无法启动。",[16,275,276,277,280],{},"正确做法是先让 VM 正常关机（",[27,278,279],{"code":279},"shutdown","），内存刷盘后再做 snapshot。",[48,282,285],{"className":283,"code":284,"language":111,"meta":56},[109],"# 批量正常关机所有 VM\nfor vmid in $(qm list | awk 'NR>1 {print $1}'); do\n  echo \"Shutting down VM $vmid ...\"\n  qm shutdown $vmid\ndone\n\n# 批量正常关机所有 LXC\nfor ctid in $(pct list | awk 'NR>1 {print $1}'); do\n  echo \"Shutting down CT $ctid ...\"\n  pct shutdown $ctid\ndone\n\n# 等全部停下来\nsleep 30\nqm list\npct list\n",[27,286,284],{"__ignoreMap":56},[16,288,289,292,293,296,297,300,301,304,305,292,308,311],{},[27,290,291],{"code":291},"qm list"," \u002F ",[27,294,295],{"code":295},"pct list"," 里 ",[27,298,299],{"code":299},"STATUS"," 都应当为 ",[32,302,303],{},"stopped","。如果有卡住的，用 ",[27,306,307],{"code":307},"qm stop \u003Cid>",[27,309,310],{"code":310},"pct stop \u003Cid>"," 强制停（相当于拔电，风险自担）。",[20,313,315],{"id":314},"_4-确认外置备份盘并创建临时备份池","4. 确认外置备份盘并创建临时备份池",[92,317,319],{"id":318},"_41-查外置盘的-by-id-路径","4.1 查外置盘的 by-id 路径",[16,321,322,325,326,329,330,333,334,337,338,341],{},[32,323,324],{},"为什么用 by-id 而不是 sdg","：Linux 的设备名（",[27,327,328],{"code":328},"sdb","、",[27,331,332],{"code":332},"sdg"," 等）在重启后可能变动（跟 BIOS 扫盘顺序、热插拔顺序有关）。用 ",[27,335,336],{"code":336},"by-id"," 路径的是",[32,339,340],{},"磁盘序列号","，永久稳定。",[48,343,346],{"className":344,"code":345,"language":111,"meta":56},[109],"ls -l \u002Fdev\u002Fdisk\u002Fby-id\u002F | grep sdg\n# 找到类似：\n# ata-WDC_WD10EZEX-08WN4A0_WD-WCC6Y5XXXXXX -> ..\u002F..\u002Fsdg\n",[27,347,345],{"__ignoreMap":56},[16,349,350,351,354],{},"记下完整的 ID 串（本例 ",[27,352,353],{"code":353},"ata-WDC_WD10EZEX-08WN4A0_WD-WCC6Y5XXXXXX","）。",[92,356,358,359,362],{"id":357},"_42-ashift12-是什么为什么必须加","4.2 ",[27,360,361],{"code":361},"ashift=12"," 是什么，为什么必须加",[16,364,365,367],{},[27,366,187],{"code":187}," 告诉 ZFS 磁盘的物理扇区大小是 2^ashift 字节：",[369,370,371,386],"table",{},[372,373,374],"thead",{},[375,376,377,380,383],"tr",{},[378,379,187],"th",{},[378,381,382],{},"块大小",[378,384,385],{},"适用场景",[387,388,389,401,418,429],"tbody",{},[375,390,391,395,398],{},[392,393,394],"td",{},"9",[392,396,397],{},"512 B",[392,399,400],{},"老式 512n 硬盘（基本已绝迹）",[375,402,403,408,413],{},[392,404,405],{},[32,406,407],{},"12",[392,409,410],{},[32,411,412],{},"4 KB",[392,414,415],{},[32,416,417],{},"现代机械盘和多数 SSD（推荐默认）",[375,419,420,423,426],{},[392,421,422],{},"13",[392,424,425],{},"8 KB",[392,427,428],{},"部分高端 NVMe、企业级 SSD",[375,430,431,434,437],{},[392,432,433],{},"14",[392,435,436],{},"16 KB",[392,438,439],{},"少数超高性能 NVMe",[16,441,442,443,446,447,450,451,454],{},"现代硬盘几乎全是 ",[32,444,445],{},"4K 物理扇区","（Advanced Format \u002F 512e \u002F 4Kn），如果用 ",[27,448,449],{"code":449},"ashift=9","（默认），ZFS 以为扇区是 512B，每次写其实要触发磁盘内部的\"读-修改-写\"一个 4K 扇区，",[32,452,453],{},"性能直接砍到一半以下","。",[16,456,457,462,463,466,467,469,470,454],{},[32,458,459,461],{},[27,460,187],{"code":187}," 一旦建池就锁死，不能改","。所以",[32,464,465],{},"宁可大不可小","：现代硬盘建议至少 ",[27,468,361],{"code":361},"；NVMe SSD 条件允许给 ",[27,471,472],{"code":472},"ashift=13",[48,474,477],{"className":475,"code":476,"language":111,"meta":56},[109],"# 建临时备份池（单盘，不做冗余，只用来中转）\nzpool create -o ashift=12 temp_backup \\\n  \u002Fdev\u002Fdisk\u002Fby-id\u002Fata-WDC_WD10EZEX-08WN4A0_WD-WCC6Y5XXXXXX\n\n# 确认\nzpool status\nzfs list\n",[27,478,476],{"__ignoreMap":56},[20,480,482],{"id":481},"_5-打-snapshot-并-zfs-send-到备份池","5. 打 snapshot 并 zfs send 到备份池",[92,484,486],{"id":485},"_51-为什么必须先-snapshot","5.1 为什么必须先 snapshot",[16,488,489,492,493,496],{},[27,490,491],{"code":491},"zfs send"," ",[32,494,495],{},"只能发送 snapshot","，不能直接发送活跃的数据集或 ZVOL。原因：活跃数据集一直在变，没有\"时间点\"概念，接收端不知道该停在哪里。",[16,498,499,500,503],{},"Snapshot 是某一时刻整个数据集的",[32,501,502],{},"只读时间切片","，ZFS send 基于它才能生成确定性的数据流。",[48,505,508],{"className":506,"code":507,"language":111,"meta":56},[109],"# 递归对整个 ssd 池打一个 snapshot，名字统一好识别\nzfs snapshot -r ssd@migrate-2026-04-22\n\n# 查看确认所有 dataset\u002FZVOL 都有这个 snapshot\nzfs list -t snapshot -r ssd\n",[27,509,507],{"__ignoreMap":56},[16,511,512,515,516,518,519,329,522,525],{},[27,513,514],{"code":514},"-r"," 表示递归——",[27,517,29],{"code":29}," 池下所有 dataset \u002F ZVOL 都打上同名 snapshot（",[27,520,521],{"code":521},"ssd@migrate-2026-04-22",[27,523,524],{"code":524},"ssd\u002Fvm-100-disk-0@migrate-2026-04-22"," 等）。",[92,527,529],{"id":528},"_52-传输到备份池","5.2 传输到备份池",[48,531,534],{"className":532,"code":533,"language":111,"meta":56},[109],"# 先在备份池里建个容纳目录\nzfs create temp_backup\u002Fssd_backup\n\n# 逐个 ZVOL 发送（基于刚才打的 snapshot）\nzfs send -w -L ssd\u002Fvm-100-disk-0@migrate-2026-04-22 | \\\n  zfs receive -F temp_backup\u002Fssd_backup\u002Fvm-100-disk-0\n\nzfs send -w -L ssd\u002Fvm-101-disk-0@migrate-2026-04-22 | \\\n  zfs receive -F temp_backup\u002Fssd_backup\u002Fvm-101-disk-0\n\nzfs send -w -L ssd\u002Fvm-101-disk-1@migrate-2026-04-22 | \\\n  zfs receive -F temp_backup\u002Fssd_backup\u002Fvm-101-disk-1\n\nzfs send -w -L ssd\u002Fvm-102-disk-0@migrate-2026-04-22 | \\\n  zfs receive -F temp_backup\u002Fssd_backup\u002Fvm-102-disk-0\n\nzfs send -w -L ssd\u002Fvm-102-disk-1@migrate-2026-04-22 | \\\n  zfs receive -F temp_backup\u002Fssd_backup\u002Fvm-102-disk-1\n",[27,535,533],{"__ignoreMap":56},[10,537,539,590],{"type":242,"title":538},"zfs send 参数说明",[97,540,541,553,568,579],{},[100,542,543,548,549,552],{},[32,544,545],{},[27,546,547],{"code":547},"-w"," (",[27,550,551],{"code":551},"--raw",")：按磁盘原样发送。如果数据集启用了压缩 \u002F 加密 \u002F 去重，raw 模式不解压不解密，直接发送压缩\u002F加密后的块。传输最快、占用最小",[100,554,555,548,560,563,564,567],{},[32,556,557],{},[27,558,559],{"code":559},"-L",[27,561,562],{"code":562},"--large-block",")：允许发送 >128K 的 record size。接收端池必须启用 ",[27,565,566],{"code":566},"large_blocks"," feature（OpenZFS 默认已开）",[100,569,570,548,575,578],{},[32,571,572],{},[27,573,574],{"code":574},"-R",[27,576,577],{"code":577},"--replicate",")：递归复制整棵树（含子 dataset、snapshot、properties），常用于整池迁移",[100,580,581,548,586,589],{},[32,582,583],{},[27,584,585],{"code":585},"-i",[27,587,588],{"code":588},"--incremental",")：只发增量（见 5.3 节）",[16,591,592,595,596,599,600,606],{},[27,593,594],{"code":594},"zfs receive -F"," 的 ",[27,597,598],{"code":598},"-F"," 是\"强制覆盖接收端同名数据集\"。",[32,601,602,603,605],{},"接收端名字如果已存在但不是你想要的，",[27,604,598],{"code":598}," 会把它抹掉","——确认无误再用。",[92,608,610],{"id":609},"_53-进阶用增量-send-降低停机窗口","5.3 进阶：用增量 send 降低停机窗口",[16,612,613],{},"上面的流程需要 VM 全程停机 → 全量传输完成才能启动。大数据量时可能停机好几个小时。",[16,615,616,619],{},[32,617,618],{},"增量 send 的思路","：VM 继续运行时先做一次全量，停机后只发增量。",[48,621,624],{"className":622,"code":623,"language":111,"meta":56},[109],"# 第 1 步：VM 运行中（不停机），先做一次全量快照 + 全量 send\nzfs snapshot -r ssd@full-before-stop\nzfs send -R -w -L ssd@full-before-stop | zfs receive -F temp_backup\u002Fssd_backup\n\n# 第 2 步：这时才停机（见第 3 节）\n\n# 第 3 步：停机后再打一次快照\nzfs snapshot -r ssd@final-stopped\n\n# 第 4 步：只发从 full-before-stop 到 final-stopped 的增量\nzfs send -R -w -L -i @full-before-stop ssd@final-stopped | \\\n  zfs receive -F temp_backup\u002Fssd_backup\n",[27,625,623],{"__ignoreMap":56},[16,627,628],{},"这样 VM 实际停机时间 = 增量传输时间（通常几分钟），远少于全量传输时间（几十分钟到几小时）。",[20,630,632],{"id":631},"_6-验证备份完整性不通过就回头","6. 验证备份完整性（不通过就回头！）",[10,634,636],{"type":140,"title":635},"这一节通不过，千万不要执行下一节的销毁操作",[16,637,638],{},"备份有没有真的完整，是整个流程的生死线。任何一项校验不通过都应该先查问题、必要时重做备份，再进入第 7 节。",[92,640,642],{"id":641},"_61-空间对比","6.1 空间对比",[48,644,647],{"className":645,"code":646,"language":111,"meta":56},[109],"# 源池和备份池并排看 used\nzfs list -r -o name,used,written ssd\nzfs list -r -o name,used,written temp_backup\n",[27,648,646],{"__ignoreMap":56},[16,650,651,652,655],{},"对应 dataset 的 ",[27,653,654],{"code":654},"used"," 应当接近（raw send 下可以精确匹配；非 raw 由于压缩差异可能略有出入，但数量级必须一致）。",[92,657,659],{"id":658},"_62-snapshot-完整性","6.2 snapshot 完整性",[48,661,664],{"className":662,"code":663,"language":111,"meta":56},[109],"# 备份池里应该能看到全部迁移用的 snapshot\nzfs list -t snapshot -r temp_backup | grep migrate-2026-04-22\n",[27,665,663],{"__ignoreMap":56},[92,667,669],{"id":668},"_63-端到端启动测试最可靠","6.3 端到端启动测试（最可靠）",[16,671,672,673,454],{},"最硬核的校验是：",[32,674,675],{},"在备份池上启动一台 VM，确认系统能正常跑",[48,677,680],{"className":678,"code":679,"language":111,"meta":56},[109],"# 举例：把 VM 100 临时指向备份池的 ZVOL\n# 用 \u002Froot\u002Fpve-config-backup\u002F100.conf 里的配置修改磁盘指向 temp_backup\u002Fssd_backup\u002Fvm-100-disk-0\n# 启动测试\nqm start 100\n# 进 VM 里确认系统、应用正常\n# 确认无误后关机再改回来\nqm stop 100\n",[27,681,679],{"__ignoreMap":56},[16,683,684,685,688],{},"如果不想动配置，至少用 ",[27,686,687],{"code":687},"zfs clone"," 克隆一份出来挂载读取：",[48,690,693],{"className":691,"code":692,"language":111,"meta":56},[109],"zfs clone temp_backup\u002Fssd_backup\u002Fvm-100-disk-0@migrate-2026-04-22 \\\n  temp_backup\u002Fssd_backup\u002Fvm-100-disk-0-clone\n\n# 映射为块设备（如果是 ZVOL）\nls -l \u002Fdev\u002Fzvol\u002Ftemp_backup\u002Fssd_backup\u002Fvm-100-disk-0-clone\n\n# 或用 kpartx \u002F parted 进一步挂载 partition\n",[27,694,692],{"__ignoreMap":56},[20,696,698],{"id":697},"_7-销毁原池并重建为-raidz1不可逆分水岭","7. 销毁原池并重建为 RAIDZ1（不可逆分水岭）",[10,700,702,723,726],{"type":66,"title":701},"执行下面两条命令后，原池的数据就回不来了",[16,703,704,705,454,708,711,712,715,716,719,720,454],{},"这是整个流程的",[32,706,707],{},"分水岭",[27,709,710],{"code":710},"zpool export ssd"," 还能 ",[27,713,714],{"code":714},"zpool import ssd"," 回来；但 ",[27,717,718],{"code":718},"zpool create -f ssd ..."," 一旦执行，原盘的 ZFS label 被新池覆盖，",[32,721,722],{},"再也 import 不回来",[16,724,725],{},"执行前最后确认：",[97,727,730,742,748,757],{"className":728},[729],"contains-task-list",[100,731,734,739,740],{"className":732},[733],"task-list-item",[735,736],"input",{"disabled":737,"type":738},true,"checkbox"," VM \u002F LXC 都已 ",[27,741,303],{"code":303},[100,743,745,747],{"className":744},[733],[735,746],{"disabled":737,"type":738}," 第 6 节所有校验都通过",[100,749,751,753,754],{"className":750},[733],[735,752],{"disabled":737,"type":738}," PVE 配置文件已在 ",[27,755,756],{"code":756},"\u002Froot\u002Fpve-config-backup\u002F",[100,758,760,492,762],{"className":759},[733],[735,761],{"disabled":737,"type":738},[32,763,764],{},"备份盘 sdg 的 ID 和即将要格式化的 sdb-sde 的 ID 分清楚了",[92,766,768],{"id":767},"_71-先人工核对磁盘-id","7.1 先人工核对磁盘 ID",[48,770,773],{"className":771,"code":772,"language":111,"meta":56},[109],"# 把所有要参与重建的盘的 by-id 路径打出来\nls -l \u002Fdev\u002Fdisk\u002Fby-id\u002F | grep -E 'sd[b-e]$'\n",[27,774,772],{"__ignoreMap":56},[16,776,777,778,454],{},"把输出复制保存，核对每个 ID 都是原池里的，",[32,779,780],{},"sdg 的 ID 绝对不在其中",[10,782,784,787],{"type":140,"title":783},"临时备份池 temp_backup 务必先导出",[16,785,786],{},"重建 ssd 池之前，把 temp_backup 先 export 掉（但不销毁），避免手误把 sdg 写进下一步命令：",[48,788,791],{"className":789,"code":790,"language":111,"meta":56},[109],"zpool export temp_backup\n",[27,792,790],{"__ignoreMap":56},[92,794,796],{"id":795},"_72-导出原池可回滚的最后一步","7.2 导出原池（可回滚的最后一步）",[48,798,801],{"className":799,"code":800,"language":111,"meta":56},[109],"zpool export ssd\n",[27,802,800],{"__ignoreMap":56},[16,804,805,806,808,809],{},"如果这一步之后反悔，还能 ",[27,807,714],{"code":714}," 恢复。",[32,810,811,812,814],{},"下一步 ",[27,813,196],{"code":196}," 才是真正的不可逆点。",[92,816,818],{"id":817},"_73-重建为-raidz1先不加-f-试运行","7.3 重建为 RAIDZ1（先不加 -f 试运行）",[48,820,823],{"className":821,"code":822,"language":111,"meta":56},[109],"# 先不加 -f 试探，让 ZFS 自己报盘上有残留 label\nzpool create -o ashift=12 ssd raidz1 \\\n  \u002Fdev\u002Fdisk\u002Fby-id\u002F你的-sdb-设备ID \\\n  \u002Fdev\u002Fdisk\u002Fby-id\u002F你的-sdc-设备ID \\\n  \u002Fdev\u002Fdisk\u002Fby-id\u002F你的-sdd-设备ID \\\n  \u002Fdev\u002Fdisk\u002Fby-id\u002F你的-sde-设备ID\n",[27,824,822],{"__ignoreMap":56},[16,826,827,830,831,834,835,838],{},[32,828,829],{},"期望输出","：会报类似 ",[27,832,833],{"code":833},"invalid vdev specification: use '-f' to override"," 的错，提示磁盘上有旧池 label。这个报错是",[32,836,837],{},"保护性的","——让你确认盘没选错。",[16,840,841,842,845],{},"确认 4 块盘 ID 没错、没夹带 sdg 之后，加 ",[27,843,844],{"code":844},"-f"," 正式执行：",[48,847,850],{"className":848,"code":849,"language":111,"meta":56},[109],"zpool create -f -o ashift=12 ssd raidz1 \\\n  \u002Fdev\u002Fdisk\u002Fby-id\u002F你的-sdb-设备ID \\\n  \u002Fdev\u002Fdisk\u002Fby-id\u002F你的-sdc-设备ID \\\n  \u002Fdev\u002Fdisk\u002Fby-id\u002F你的-sdd-设备ID \\\n  \u002Fdev\u002Fdisk\u002Fby-id\u002F你的-sde-设备ID\n\nzpool status ssd\n",[27,851,849],{"__ignoreMap":56},[16,853,854,857,858,861,862,454],{},[27,855,856],{"code":856},"zpool status"," 应该显示 ",[27,859,860],{"code":860},"state: ONLINE"," 且 vdev 是 ",[27,863,864],{"code":864},"raidz1-0",[20,866,868],{"id":867},"_8-从备份池恢复数据到新池","8. 从备份池恢复数据到新池",[16,870,871],{},"先把备份池 import 回来：",[48,873,876],{"className":874,"code":875,"language":111,"meta":56},[109],"zpool import temp_backup\n",[27,877,875],{"__ignoreMap":56},[16,879,880],{},"然后反向 send：",[48,882,885],{"className":883,"code":884,"language":111,"meta":56},[109],"# 先对备份池的数据也打一个恢复用的 snapshot（保持一致性）\nzfs snapshot -r temp_backup\u002Fssd_backup@restore-2026-04-22\n\n# 循环恢复所有 ZVOL\nfor disk in vm-100-disk-0 vm-101-disk-0 vm-101-disk-1 vm-102-disk-0 vm-102-disk-1; do\n  echo \"Restoring $disk ...\"\n  zfs send -w -L temp_backup\u002Fssd_backup\u002F$disk@restore-2026-04-22 | \\\n    zfs receive -F ssd\u002F$disk\ndone\n\n# 确认\nzfs list -r ssd\n",[27,886,884],{"__ignoreMap":56},[20,888,890],{"id":889},"_9-恢复-pve-配置并启动-vm","9. 恢复 PVE 配置并启动 VM",[48,892,895],{"className":893,"code":894,"language":111,"meta":56},[109],"# 把之前备份的 .conf 文件放回去\ncp -a \u002Froot\u002Fpve-config-backup\u002F*.conf \u002Fetc\u002Fpve\u002Fqemu-server\u002F 2>\u002Fdev\u002Fnull\ncp -a \u002Froot\u002Fpve-config-backup\u002F*.conf \u002Fetc\u002Fpve\u002Flxc\u002F      2>\u002Fdev\u002Fnull\n\n# 启动 VM\u002FCT 做最终验证\nqm start 100\nqm start 101\nqm start 102\npct start \u003Cctid>\n",[27,896,894],{"__ignoreMap":56},[16,898,899],{},"逐台进 VM 里确认：系统能进入、服务能起、数据文件存在。",[20,901,903],{"id":902},"_10-清理临时备份池","10. 清理临时备份池",[10,905,907],{"type":242,"title":906},"建议：新池稳定运行 48 小时以上再清理",[16,908,909,910,913,914,916,917,920],{},"新池刚建好头几天仍有微概率因硬件 \u002F 配置问题暴露。强烈建议",[32,911,912],{},"保留备份池至少 48 小时","并观察 ",[27,915,856],{"code":856},"、VM 稳定性后再清理——有问题还能从 ",[27,918,919],{"code":919},"temp_backup"," 再恢复一次。",[16,922,923],{},"确认一切 OK 后：",[48,925,928],{"className":926,"code":927,"language":111,"meta":56},[109],"zpool export temp_backup\n# 物理拔出 sdg，或者重新分区用于其他用途\n",[27,929,927],{"__ignoreMap":56},[20,931,933],{"id":932},"_11-回滚与容灾思考","11. 回滚与容灾思考",[16,935,936,937,940],{},"本方案是",[32,938,939],{},"单副本中转","——数据只在 sdg 这一个备份盘上。现实中有若干失败场景：",[369,942,943,956],{},[372,944,945],{},[375,946,947,950,953],{},[378,948,949],{},"失败场景",[378,951,952],{},"影响",[378,954,955],{},"能否救回",[387,957,958,973,986,999,1015,1027],{},[375,959,960,963,970],{},[392,961,962],{},"sdg 临时掉线，但数据盘 label 还没被覆盖",[392,964,965,966,969],{},"重插 sdg 再 ",[27,967,968],{"code":968},"zpool import"," 即可",[392,971,972],{},"✅",[375,974,975,980,984],{},[392,976,977,979],{},[27,978,710],{"code":710}," 之后后悔",[392,981,982,969],{},[27,983,714],{"code":714},[392,985,972],{},[375,987,988,994,997],{},[392,989,990,993],{},[27,991,992],{"code":992},"zpool create -f ssd"," 执行后备份完整",[392,995,996],{},"按第 8 节流程恢复",[392,998,972],{},[375,1000,1001,1006,1009],{},[392,1002,1003,1005],{},[27,1004,992],{"code":992}," 执行后发现备份有损坏",[392,1007,1008],{},"原池 label 已被覆盖",[392,1010,1011,1012],{},"❌ ",[32,1013,1014],{},"数据全丢",[375,1016,1017,1020,1025],{},[392,1018,1019],{},"sdg 本身故障 + 还没 create 新池",[392,1021,1022,1024],{},[27,1023,714],{"code":714}," 回退",[392,1026,972],{},[375,1028,1029,1032,1035],{},[392,1030,1031],{},"sdg 故障 + 已 create 新池",[392,1033,1034],{},"两边都没了",[392,1036,1011,1037],{},[32,1038,1014],{},[16,1040,1041,1042,1045],{},"结论：",[32,1043,1044],{},"sdg 这一份备份不够","。负担得起的话：",[97,1047,1048,1054,1063],{},[100,1049,1050,1053],{},[32,1051,1052],{},"方案 A","：Proxmox Backup Server (PBS) 做 VM 级别的定时备份，这是 PVE 官方方案",[100,1055,1056,1059,1060,1062],{},[32,1057,1058],{},"方案 B","：把 ",[27,1061,491],{"code":491}," 的数据流同时发到两块独立备份盘",[100,1064,1065,1068],{},[32,1066,1067],{},"方案 C","：关键数据（如数据库）额外跑一份应用层备份（mysqldump \u002F pg_dump 到另一台机器）",[20,1070,1072],{"id":1071},"_12-常见故障排查","12. 常见故障排查",[369,1074,1075,1088],{},[372,1076,1077],{},[375,1078,1079,1082,1085],{},[378,1080,1081],{},"现象",[378,1083,1084],{},"可能原因",[378,1086,1087],{},"对策",[387,1089,1090,1112,1129,1146,1168,1191],{},[375,1091,1092,1100,1109],{},[392,1093,1094,1096,1097],{},[27,1095,491],{"code":491}," 报 ",[27,1098,1099],{"code":1099},"must specify a snapshot",[392,1101,1102,1103,1105,1106],{},"忘了先 ",[27,1104,268],{"code":268}," 或写的是 dataset 而不是 ",[27,1107,1108],{"code":1108},"dataset@snap",[392,1110,1111],{},"按 5.1 节先打 snapshot",[375,1113,1114,1121,1124],{},[392,1115,1116,1096,1118],{},[27,1117,77],{"code":77},[27,1119,1120],{"code":1120},"invalid vdev specification",[392,1122,1123],{},"磁盘上有旧 label\u002F 分区表残留",[392,1125,1126,1127],{},"确认盘没错之后加 ",[27,1128,844],{"code":844},[375,1130,1131,1134,1140],{},[392,1132,1133],{},"VM 启动后提示文件系统不一致 \u002F 需要 fsck",[392,1135,1136,1137,1139],{},"当时没正常 ",[27,1138,279],{"code":279}," 就 snapshot 了",[392,1141,1142,1143],{},"进 VM 恢复模式跑 fsck；下次务必先 ",[27,1144,1145],{"code":1145},"qm shutdown",[375,1147,1148,1151,1154],{},[392,1149,1150],{},"恢复后 VM 启动报\"磁盘找不到\"",[392,1152,1153],{},"配置里磁盘指向的 storage 名对不上",[392,1155,1156,1157,296,1160,1163,1164,1167],{},"检查 ",[27,1158,1159],{"code":1159},"\u002Fetc\u002Fpve\u002Fqemu-server\u002F\u003Cid>.conf",[27,1161,1162],{"code":1162},"scsi0:"," 等行的 storage id，必要时 ",[27,1165,1166],{"code":1166},"qm set"," 修正",[375,1169,1170,1175,1181],{},[392,1171,1172,1174],{},[27,1173,491],{"code":491}," 速度极慢",[392,1176,1177,1178,1180],{},"没加 ",[27,1179,547],{"code":547}," \u002F 两端都在压缩计算 \u002F 网络\u002F磁盘带宽瓶颈",[392,1182,1183,1184,1186,1187,1190],{},"加 ",[27,1185,547],{"code":547}," raw send；大文件量时用 ",[27,1188,1189],{"code":1189},"pv"," 观察吞吐",[375,1192,1193,1205,1208],{},[392,1194,1195,1096,1197,1200,1201,1204],{},[27,1196,856],{"code":856},[27,1198,1199],{"code":1199},"DEGRADED"," 且有 ",[27,1202,1203],{"code":1203},"FAULTED"," 盘",[392,1206,1207],{},"某块参与重建的磁盘本身故障",[392,1209,1210,1211,1214],{},"先 ",[27,1212,1213],{"code":1213},"zpool replace"," 换盘；不要接着把数据 restore 上去",[10,1216,1218],{"type":12,"title":1217},"作者注",[16,1219,1220,1221,1224,1225,1228],{},"本文基于作者一次真实的 PVE ZFS 池从条带升级为 RAIDZ1 的实操流程整理。涉及命令经过修正（如补上强制先打 snapshot），尽量贴近 OpenZFS 2.x + PVE 8.x 的现代实践。不同 ZFS \u002F PVE 版本参数可能微调，执行前请对照 ",[27,1222,1223],{"code":1223},"man zfs-send"," 与 ",[27,1226,1227],{"code":1227},"man zpool-create"," 确认。",{"title":56,"searchDepth":1230,"depth":1230,"links":1231},4,[1232,1234,1240,1241,1242,1247,1252,1257,1262,1263,1264,1265,1266],{"id":22,"depth":1233,"text":22},2,{"id":89,"depth":1233,"text":90,"children":1235},[1236,1238,1239],{"id":94,"depth":1237,"text":95},3,{"id":126,"depth":1237,"text":127},{"id":177,"depth":1237,"text":178},{"id":221,"depth":1233,"text":222},{"id":258,"depth":1233,"text":259},{"id":314,"depth":1233,"text":315,"children":1243},[1244,1245],{"id":318,"depth":1237,"text":319},{"id":357,"depth":1237,"text":1246},"4.2 ashift=12 是什么，为什么必须加",{"id":481,"depth":1233,"text":482,"children":1248},[1249,1250,1251],{"id":485,"depth":1237,"text":486},{"id":528,"depth":1237,"text":529},{"id":609,"depth":1237,"text":610},{"id":631,"depth":1233,"text":632,"children":1253},[1254,1255,1256],{"id":641,"depth":1237,"text":642},{"id":658,"depth":1237,"text":659},{"id":668,"depth":1237,"text":669},{"id":697,"depth":1233,"text":698,"children":1258},[1259,1260,1261],{"id":767,"depth":1237,"text":768},{"id":795,"depth":1237,"text":796},{"id":817,"depth":1237,"text":818},{"id":867,"depth":1233,"text":868},{"id":889,"depth":1233,"text":890},{"id":902,"depth":1233,"text":903},{"id":932,"depth":1233,"text":933},{"id":1071,"depth":1233,"text":1072},[1268],"系统","2026-02-12","在 Proxmox VE 上借助外置盘做中转，把现有 ZFS 池安全重建为 RAIDZ1——完整流程含配置备份、VM 停机、ashift 与 4K 对齐原理、zfs snapshot\u002Fsend 全量与增量、备份完整性校验、销毁与恢复、回滚预案。",false,"md",null,{"slots":1275},{},"\u002Fposts\u002Fzfs-pool-migration-reconstruction-guide",{"text":1278,"minutes":1279,"time":1280,"words":1281},"18 min read",17.365,1041900,3473,{"title":5,"description":1270},{"loc":1276},"posts\u002Fposts\u002Fzfs-pool-migration-reconstruction-guide",[1286,1287,1288,1289,1290,1291,1292,1293,1294],"ZFS","Proxmox","PVE","RAIDZ","zfs-send","Storage","数据迁移","VM 迁移","HomeLab","tech","PDLKyiMBvRH2QgrRnn3pFsG8kctlZtNdO1nS7iYC3-M",[1298,1302],{"title":1299,"path":1300,"stem":1301,"date":1269,"type":1295,"children":-1},"JumpServer 开源堡垒机安装指南","\u002Fposts\u002Fjumpserver-install","posts\u002Fposts\u002Fjumpserver-install",{"title":1303,"path":1304,"stem":1305,"date":1306,"type":1295,"children":-1},"服务器初始化完整配置流程","\u002Fposts\u002Fserver-init","posts\u002Fposts\u002Fserver-init","2026-02-13",1788712223966]