[{"data":1,"prerenderedAt":1200},["ShallowReactive",2],{"content:\u002Fposts\u002Flinux-software-raid-mdadm-guide":3,"surround:\u002Fposts\u002Flinux-software-raid-mdadm-guide":1190},{"id":4,"title":5,"body":6,"categories":1159,"date":1161,"description":1162,"draft":1163,"extension":1164,"image":1165,"meta":1166,"navigation":1168,"path":1169,"permalink":1165,"pinned":1163,"published":1165,"readingTime":1170,"recommend":1165,"references":1165,"seo":1175,"sitemap":1176,"stem":1177,"tags":1178,"type":1188,"updated":1161,"__hash__":1189},"content\u002Fposts\u002Fposts\u002Flinux-software-raid-mdadm-guide.md","Linux 软 RAID 实战指南：使用 mdadm 构建可靠存储",{"type":7,"value":8,"toc":1126},"minimark",[9,19,23,35,51,91,95,98,245,256,260,275,278,288,341,345,351,354,373,376,380,386,406,413,417,423,429,452,455,463,466,470,506,509,515,522,527,533,547,551,557,564,585,589,595,609,613,619,627,633,639,646,652,685,689,695,699,705,708,714,717,723,733,737,743,747,753,757,763,780,784,787,793,796,800,806,816,820,826,839,843,853,869,879,888,894,903,909,915,921,928,937,949,953,956,962,968,972,1107],[10,11,15],"alert",{"title":12,"type":13,"icon":14},"AI 迁移提示","info","tabler:robot",[16,17,18],"p",{},"本文由 AI 协助从旧站迁移，尚未完成逐篇人工审校；内容如有疏漏，将在复核后修订。",[20,21,22],"h2",{"id":22},"为什么要做这件事",[16,24,25,26,30,31,34],{},"Ubuntu Server 上跑一堆 Docker 容器，数据都落在某一块数据盘上——",[27,28,29],"strong",{},"单盘 = 单点故障","，盘一坏数据全没。",[27,32,33],{},"软 RAID"," 是成本最低、最通用的冗余方案：不用阵列卡、不用特殊硬件，两块空闲盘 + 半小时就能把可靠性拉高一个量级。",[16,36,37,38,41,42,46,47,50],{},"本文记录从零做一套 ",[27,39,40],{},"RAID 1（镜像）"," 的完整流程：准备磁盘 → 创建阵列 → 持久化 → 挂载到 ",[43,44,45],"code",{"code":45},"\u002Fdata"," 给 Docker 用 → 故障盘替换 → ",[27,48,49],{},"邮件 + Bark 告警","。",[10,52,55,66,85],{"title":53,"type":54},"RAID ≠ 备份","error",[16,56,57,58,61,62,65],{},"RAID 防的是",[27,59,60],{},"单块磁盘硬件故障","。以下场景 RAID ",[27,63,64],{},"完全不保护","：",[67,68,69,76,79,82],"ul",{},[70,71,72,73],"li",{},"误删、误 ",[43,74,75],{"code":75},"rm -rf",[70,77,78],{},"勒索病毒、应用 bug 写坏数据",[70,80,81],{},"文件系统损坏、同时多盘坏",[70,83,84],{},"电源 \u002F 控制器 \u002F 主板问题打穿所有盘",[16,86,87,90],{},[27,88,89],{},"RAID 是高可用方案，不是备份方案。"," 重要数据仍然要做独立备份（rsync 到另一台机器 \u002F PBS \u002F 云盘都行），两者互不替代。",[20,92,94],{"id":93},"_1-raid-级别速览","1. RAID 级别速览",[16,96,97],{},"本文只用 RAID 1，但选型思路通用，列一张对比表方便以后扩展：",[99,100,101,129],"table",{},[102,103,104],"thead",{},[105,106,107,111,114,117,120,123,126],"tr",{},[108,109,110],"th",{},"级别",[108,112,113],{},"最少盘数",[108,115,116],{},"容错",[108,118,119],{},"读性能",[108,121,122],{},"写性能",[108,124,125],{},"容量利用率",[108,127,128],{},"典型场景",[130,131,132,155,181,203,225],"tbody",{},[105,133,134,138,141,144,147,149,152],{},[135,136,137],"td",{},"RAID 0",[135,139,140],{},"2",[135,142,143],{},"❌ 无",[135,145,146],{},"最快",[135,148,146],{},[135,150,151],{},"100%",[135,153,154],{},"临时 scratch 数据，丢了无所谓",[105,156,157,162,164,167,170,173,176],{},[135,158,159],{},[27,160,161],{},"RAID 1",[135,163,140],{},[135,165,166],{},"任 1 盘",[135,168,169],{},"快（双路读）",[135,171,172],{},"单盘速度",[135,174,175],{},"50%",[135,177,178],{},[27,179,180],{},"系统盘、数据量不大的重要数据",[105,182,183,186,189,191,194,197,200],{},[135,184,185],{},"RAID 5",[135,187,188],{},"3",[135,190,166],{},[135,192,193],{},"快",[135,195,196],{},"中（parity 计算）",[135,198,199],{},"(N-1)\u002FN",[135,201,202],{},"大容量 + 成本敏感",[105,204,205,208,211,214,216,219,222],{},[135,206,207],{},"RAID 6",[135,209,210],{},"4",[135,212,213],{},"任 2 盘",[135,215,193],{},[135,217,218],{},"慢（双 parity）",[135,220,221],{},"(N-2)\u002FN",[135,223,224],{},"大盘组（4 TB+），怕 URE",[105,226,227,230,232,235,237,240,242],{},[135,228,229],{},"RAID 10",[135,231,210],{},[135,233,234],{},"每 mirror 1 盘",[135,236,146],{},[135,238,239],{},"很快",[135,241,175],{},[135,243,244],{},"数据库、高 IO 负载",[10,246,249],{"title":247,"type":248},"小规模 HomeLab 优先选 RAID 1","tip",[16,250,251,252,255],{},"两块相同容量的盘做 RAID 1，",[27,253,254],{},"可用性最高、操作最简单、故障场景最容易理解","。RAID 5\u002F6 容量利用率高但有\"写惩罚\"和 rebuild 期间再坏盘就全丢的风险，建议 4 盘以上再考虑。",[20,257,259],{"id":258},"_2-前置条件","2. 前置条件",[67,261,262,265,272],{},[70,263,264],{},"Ubuntu Server（本文基于 22.04 \u002F 24.04 验证）",[70,266,267,268,271],{},"至少 ",[27,269,270],{},"2 块容量相同的空闲数据盘","（容量不同也能做，但会以小盘为准，多出来的浪费）",[70,273,274],{},"root \u002F sudo 权限",[16,276,277],{},"先看看当前磁盘：",[279,280,286],"pre",{"className":281,"code":283,"language":284,"meta":285},[282],"language-bash","lsblk\n# 假设 sda 是系统盘、sdb 和 sdc 是要做 RAID 的数据盘\n","bash","",[43,287,283],{"__ignoreMap":285},[10,289,291,308],{"title":290,"type":54},"严重提醒：下面的操作会抹掉目标盘",[16,292,293,294,297,298,297,301,304,305,50],{},"后续 ",[43,295,296],{"code":296},"wipefs"," \u002F ",[43,299,300],{"code":300},"parted",[43,302,303],{"code":303},"mdadm --create"," 都是",[27,306,307],{},"不可逆破坏性操作",[67,309,310,321,334],{},[70,311,312,313,316,317,320],{},"执行前务必用 ",[43,314,315],{"code":315},"lsblk"," + ",[43,318,319],{"code":319},"sudo fdisk -l"," 反复确认目标盘",[70,322,323],{},[27,324,325,326,329,330,333],{},"绝对不要把系统盘（通常是 ",[43,327,328],{"code":328},"\u002Fdev\u002Fsda"," 或 ",[43,331,332],{"code":332},"\u002Fdev\u002Fnvme0n1","）当成目标盘",[70,335,336,337,340],{},"不确定时，先 ",[43,338,339],{"code":339},"mount | grep \u003C盘名>"," 看盘是否被系统挂着",[20,342,344],{"id":343},"_3-准备磁盘","3. 准备磁盘",[279,346,349],{"className":347,"code":348,"language":284,"meta":285},[282],"# 再次确认目标盘\nlsblk\nsudo fdisk -l \u002Fdev\u002Fsdb \u002Fdev\u002Fsdc\n\n# 擦除磁盘元数据（旧分区表、文件系统签名、RAID 残留等）\nsudo wipefs -a \u002Fdev\u002Fsdb\nsudo wipefs -a \u002Fdev\u002Fsdc\n\n# 创建 GPT 分区表\nsudo parted \u002Fdev\u002Fsdb --script mklabel gpt\nsudo parted \u002Fdev\u002Fsdc --script mklabel gpt\n\n# 创建占满整盘的分区（0% 100% 让 parted 自动做 4K 对齐）\nsudo parted \u002Fdev\u002Fsdb --script mkpart primary 0% 100%\nsudo parted \u002Fdev\u002Fsdc --script mkpart primary 0% 100%\n\n# 设置 RAID 标志，告诉内核这些分区将用作 RAID 成员\nsudo parted \u002Fdev\u002Fsdb --script set 1 raid on\nsudo parted \u002Fdev\u002Fsdc --script set 1 raid on\n\n# 确认：应该看到 sdb1 和 sdc1，大小相同\nlsblk\n",[43,350,348],{"__ignoreMap":285},[16,352,353],{},"::alert{type=\"tip\" title=\"GPT 上的 \"primary\" 是什么\"}",[16,355,356,357,360,361,364,365,368,369,372],{},"GPT 分区表",[27,358,359],{},"没有"," primary \u002F extended 的概念（那是 MBR 老术语）。",[43,362,363],{"code":363},"parted mkpart primary ..."," 里的 ",[43,366,367],{"code":367},"primary"," 在 GPT 上只是充当分区名字，不影响功能。用 ",[43,370,371],{"code":371},"mkpart data"," 或其他名字也一样。",[16,374,375],{},"::",[20,377,379],{"id":378},"_4-创建-raid-1-阵列","4. 创建 RAID 1 阵列",[279,381,384],{"className":382,"code":383,"language":284,"meta":285},[282],"sudo mdadm --create --verbose \u002Fdev\u002Fmd0 \\\n  --level=1 \\\n  --raid-devices=2 \\\n  \u002Fdev\u002Fsdb1 \u002Fdev\u002Fsdc1\n",[43,385,383],{"__ignoreMap":285},[67,387,388,394,400],{},[70,389,390,393],{},[43,391,392],{"code":392},"\u002Fdev\u002Fmd0","：RAID 设备节点名字，多个阵列时递增（md0、md1...）",[70,395,396,399],{},[43,397,398],{"code":398},"--level=1","：RAID 级别（想换别的级别就改这里，对应第 1 节表格）",[70,401,402,405],{},[43,403,404],{"code":404},"--raid-devices=2","：参与成员数量",[16,407,408,409,412],{},"命令执行后，阵列",[27,410,411],{},"立即开始首次同步","——把两块盘的数据对齐（即使现在都是空盘也会全盘对齐一次）。",[20,414,416],{"id":415},"_5-监控同步进度","5. 监控同步进度",[279,418,421],{"className":419,"code":420,"language":284,"meta":285},[282],"# 实时看同步进度（5 秒刷新一次即可，太频繁反而占 CPU）\nwatch -n 5 cat \u002Fproc\u002Fmdstat\n\n# 或单次看详细状态\nsudo mdadm --detail \u002Fdev\u002Fmd0\n",[43,422,420],{"__ignoreMap":285},[16,424,425,428],{},[27,426,427],{},"判定同步完成","需要两个条件同时满足：",[430,431,432,439],"ol",{},[70,433,434,435,438],{},"状态显示 ",[43,436,437],{"code":437},"[UU]","（两块盘都是 Up）",[70,440,441,443,444,447,448,451],{},[27,442,359],{}," ",[43,445,446],{"code":446},"resync","、",[43,449,450],{"code":450},"recovery"," 这种进度行",[16,453,454],{},"例如完成状态的输出：",[279,456,461],{"className":457,"code":459,"language":460},[458],"language-text","md0 : active raid1 sdc1[1] sdb1[0]\n      1048512 blocks super 1.2 [2\u002F2] [UU]\n\nunused devices: \u003Cnone>\n","text",[43,462,459],{"__ignoreMap":285},[16,464,465],{},"同步期间阵列仍可使用（性能略低），但推荐等完成再挂数据。",[20,467,469],{"id":468},"_6-持久化配置","6. 持久化配置",[10,471,473],{"title":472,"type":13},"mdadm 配置文件路径因发行版而异",[67,474,475,484,496],{},[70,476,477,65,480,483],{},[27,478,479],{},"Debian \u002F Ubuntu",[43,481,482],{"code":482},"\u002Fetc\u002Fmdadm\u002Fmdadm.conf","（本文用这个）",[70,485,486,65,489,492,493,495],{},[27,487,488],{},"CentOS \u002F RHEL \u002F Rocky",[43,490,491],{"code":491},"\u002Fetc\u002Fmdadm.conf","（",[27,494,359],{}," mdadm 子目录）",[70,497,498,499,502,503],{},"对应的 initramfs 刷新命令：Debian\u002FUbuntu 是 ",[43,500,501],{"code":501},"update-initramfs -u","，CentOS\u002FRHEL 是 ",[43,504,505],{"code":505},"dracut -f",[16,507,508],{},"先 dry-run 看要写入什么：",[279,510,513],{"className":511,"code":512,"language":284,"meta":285},[282],"sudo mdadm --detail --scan\n# 输出类似：\n# ARRAY \u002Fdev\u002Fmd0 metadata=1.2 name=server-01:0 UUID=abcd1234:5678efgh:9012ijkl:3456mnop\n",[43,514,512],{"__ignoreMap":285},[16,516,517,518,521],{},"然后写进配置文件，",[27,519,520],{},"根据系统是否已存在其他 mdadm RAID","选一种方式：",[523,524,526],"h3",{"id":525},"_61-方式-a追加系统上已经有其他-raid-时选这个","6.1 方式 A：追加（系统上已经有其他 RAID 时选这个）",[279,528,531],{"className":529,"code":530,"language":284,"meta":285},[282],"sudo mdadm --detail --scan | sudo tee -a \u002Fetc\u002Fmdadm\u002Fmdadm.conf\n",[43,532,530],{"__ignoreMap":285},[16,534,535,538,539,542,543,546],{},[43,536,537],{"code":537},"tee -a"," 的 ",[43,540,541],{"code":541},"-a"," 是 ",[27,544,545],{},"append（追加）","，原文件里的条目保留，新阵列追加到末尾。适合\"加阵列\"场景。",[523,548,550],{"id":549},"_62-方式-b备份后覆盖全新系统只做这一个-raid","6.2 方式 B：备份后覆盖（全新系统、只做这一个 RAID）",[279,552,555],{"className":553,"code":554,"language":284,"meta":285},[282],"# 先备份原文件\nsudo cp \u002Fetc\u002Fmdadm\u002Fmdadm.conf \u002Fetc\u002Fmdadm\u002Fmdadm.conf.bak\n\n# 然后覆盖写入\nsudo mdadm --detail --scan | sudo tee \u002Fetc\u002Fmdadm\u002Fmdadm.conf\n",[43,556,554],{"__ignoreMap":285},[16,558,559,560,563],{},"好处是文件干净、无历史残留；坏处是一旦手误漏写了某个阵列的 UUID，重启后那个阵列就识别不出来——好在有 ",[43,561,562],{"code":562},".bak"," 备份可以恢复。",[10,565,568],{"title":566,"type":567},"不要裸用 tee 覆盖","warning",[16,569,570,571,492,574,580,581,584],{},"直接 ",[43,572,573],{"code":573},"... | sudo tee \u002Fetc\u002Fmdadm\u002Fmdadm.conf",[27,575,576,577,579],{},"不加 ",[43,578,541],{"code":541},"、不备份","）是最危险的写法。如果系统里已有其他 mdadm RAID，原配置会被",[27,582,583],{},"直接抹掉","，重启后那个阵列认不出来。不确定时选 6.1 的追加方式更稳。",[523,586,588],{"id":587},"_63-更新-initramfs","6.3 更新 initramfs",[279,590,593],{"className":591,"code":592,"language":284,"meta":285},[282],"sudo update-initramfs -u\n",[43,594,592],{"__ignoreMap":285},[16,596,597,598,601,602,604,605,608],{},"这一步把 RAID 配置打包进内核启动镜像。对",[27,599,600],{},"数据盘"," RAID 不是强制必需，但做了可以避免极个别\"重启后 ",[43,603,392],{"code":392}," 变成 ",[43,606,607],{"code":607},"\u002Fdev\u002Fmd127","\"之类的扫盘顺序问题。",[20,610,612],{"id":611},"_7-创建文件系统并挂载","7. 创建文件系统并挂载",[279,614,617],{"className":615,"code":616,"language":284,"meta":285},[282],"# 创建 ext4 文件系统\nsudo mkfs.ext4 \u002Fdev\u002Fmd0\n\n# 创建挂载点\nsudo mkdir -p \u002Fdata\n\n# 临时挂载一下看是否正常（重启会失效，下一步才是开机自动挂载）\nsudo mount \u002Fdev\u002Fmd0 \u002Fdata\n\n# 确认\ndf -h \u002Fdata\n",[43,618,616],{"__ignoreMap":285},[523,620,622,623,626],{"id":621},"_71-写入-etcfstab让重启后自动挂载","7.1 写入 ",[43,624,625],{"code":625},"\u002Fetc\u002Ffstab","，让重启后自动挂载",[16,628,629,630,632],{},"用 UUID 挂载比用 ",[43,631,392],{"code":392}," 更稳（设备名有概率变成 md127 之类）：",[279,634,637],{"className":635,"code":636,"language":284,"meta":285},[282],"# 获取 md0 的 UUID\nUUID=$(sudo blkid -s UUID -o value \u002Fdev\u002Fmd0)\n\n# 追加到 fstab\necho \"UUID=$UUID \u002Fdata ext4 defaults 0 2\" | sudo tee -a \u002Fetc\u002Ffstab\n\n# 验证 fstab 语法没错（不会真的重新挂载，只是 lint）\nsudo mount -a\n",[43,638,636],{"__ignoreMap":285},[16,640,641,642,645],{},"强烈建议",[27,643,644],{},"重启一次实际测试","一下：",[279,647,650],{"className":648,"code":649,"language":284,"meta":285},[282],"sudo reboot\n# 重启后：\ndf -h \u002Fdata          # 应该能看到\ncat \u002Fproc\u002Fmdstat     # 应该 [UU]\n",[43,651,649],{"__ignoreMap":285},[10,653,655],{"title":654,"type":248},"fstab 最后两列的含义",[67,656,657,668],{},[70,658,659,665,666],{},[27,660,661,662],{},"第 5 列 ",[43,663,664],{"code":664},"0","：dump 备份工具的扫描标志，现在都不用 dump，填 ",[43,667,664],{"code":664},[70,669,670,675,676,679,680,682,683],{},[27,671,672,673],{},"第 6 列 ",[43,674,140],{"code":140},"：fsck 启动时的检查顺序——根分区填 ",[43,677,678],{"code":678},"1","，其他数据分区填 ",[43,681,140],{"code":140},"，不检查填 ",[43,684,664],{"code":664},[20,686,688],{"id":687},"_8-故障磁盘替换","8. 故障磁盘替换",[16,690,691,692,50],{},"RAID 1 的核心价值：一块盘挂了另一块继续工作，换盘后 rebuild 即可，",[27,693,694],{},"不丢数据",[523,696,698],{"id":697},"_81-识别故障盘","8.1 识别故障盘",[279,700,703],{"className":701,"code":702,"language":284,"meta":285},[282],"cat \u002Fproc\u002Fmdstat\n",[43,704,702],{"__ignoreMap":285},[16,706,707],{},"正常：",[279,709,712],{"className":710,"code":711,"language":460},[458],"md0 : active raid1 sdc1[1] sdb1[0]\n      ... [2\u002F2] [UU]\n",[43,713,711],{"__ignoreMap":285},[16,715,716],{},"有盘故障：",[279,718,721],{"className":719,"code":720,"language":460},[458],"md0 : active raid1 sdc1[1](F) sdb1[0]\n      ... [2\u002F1] [U_]\n",[43,722,720],{"__ignoreMap":285},[16,724,725,728,729,732],{},[43,726,727],{"code":727},"[U_]"," 的下划线就是挂掉的那一块，",[43,730,731],{"code":731},"(F)"," 标志位也印证了状态是 failed。",[523,734,736],{"id":735},"_82-把故障盘正式移除","8.2 把故障盘正式移除",[279,738,741],{"className":739,"code":740,"language":284,"meta":285},[282],"# 先标记为 fail（状态已经 fail 的也要走这一步）\nsudo mdadm --manage \u002Fdev\u002Fmd0 --fail \u002Fdev\u002Fsdc1\n\n# 再从阵列里移除\nsudo mdadm --manage \u002Fdev\u002Fmd0 --remove \u002Fdev\u002Fsdc1\n",[43,742,740],{"__ignoreMap":285},[523,744,746],{"id":745},"_83-物理换盘-对新盘分区","8.3 物理换盘 + 对新盘分区",[279,748,751],{"className":749,"code":750,"language":284,"meta":285},[282],"# 新盘插上后，假设还是识别为 \u002Fdev\u002Fsdc\nsudo wipefs -a \u002Fdev\u002Fsdc\nsudo parted \u002Fdev\u002Fsdc --script mklabel gpt\nsudo parted \u002Fdev\u002Fsdc --script mkpart primary 0% 100%\nsudo parted \u002Fdev\u002Fsdc --script set 1 raid on\n",[43,752,750],{"__ignoreMap":285},[523,754,756],{"id":755},"_84-加回阵列自动开始-rebuild","8.4 加回阵列，自动开始 rebuild",[279,758,761],{"className":759,"code":760,"language":284,"meta":285},[282],"sudo mdadm --manage \u002Fdev\u002Fmd0 --add \u002Fdev\u002Fsdc1\n\n# 观察 rebuild 进度\nwatch -n 5 cat \u002Fproc\u002Fmdstat\n",[43,762,760],{"__ignoreMap":285},[16,764,765,768,769,772,773,776,777,779],{},[43,766,767],{"code":767},"\u002Fproc\u002Fmdstat"," 会多出一行 ",[43,770,771],{"code":771},"recovery = X% (done)","。rebuild 期间阵列",[27,774,775],{},"仍可用","（降级模式），性能略低；等 ",[43,778,437],{"code":437}," 且无 recovery 行即恢复完成。",[523,781,783],{"id":782},"_85-上线前的故障演练推荐新手做一次","8.5 上线前的故障演练（推荐新手做一次）",[16,785,786],{},"RAID 坏盘的那一刻通常来得毫无预警。上线前主动模拟一次，心里有数：",[279,788,791],{"className":789,"code":790,"language":284,"meta":285},[282],"# 手动把 sdc1 标记为故障\nsudo mdadm --manage \u002Fdev\u002Fmd0 --fail \u002Fdev\u002Fsdc1\ncat \u002Fproc\u002Fmdstat    # 此时应进入降级状态 [U_]\n\n# 模拟完成后，把它重新加回来观察 rebuild\nsudo mdadm --manage \u002Fdev\u002Fmd0 --remove \u002Fdev\u002Fsdc1\nsudo mdadm --manage \u002Fdev\u002Fmd0 --add \u002Fdev\u002Fsdc1\nwatch -n 5 cat \u002Fproc\u002Fmdstat\n",[43,792,790],{"__ignoreMap":285},[16,794,795],{},"走完一遍，真出故障时直接按流程复刻，不会临时抓瞎。",[20,797,799],{"id":798},"_9-故障监控与告警","9. 故障监控与告警",[16,801,802,803,50],{},"RAID 坏了一块盘后如果没人注意，下一步很可能又坏一块——两块都坏就全丢。",[27,804,805],{},"必须配监控告警",[16,807,808,809,329,812,815],{},"Ubuntu 装 mdadm 时会自动装 mdmonitor 服务（systemd 单元通常名为 ",[43,810,811],{"code":811},"mdmonitor",[43,813,814],{"code":814},"mdadm","，视版本而定），它周期性扫描所有阵列，一旦状态变化就按配置好的方式通知。",[523,817,819],{"id":818},"_91-邮件通知传统方式","9.1 邮件通知（传统方式）",[279,821,824],{"className":822,"code":823,"language":284,"meta":285},[282],"# 在 \u002Fetc\u002Fmdadm\u002Fmdadm.conf 里加一行邮件地址\necho \"MAILADDR your-email@example.com\" | sudo tee -a \u002Fetc\u002Fmdadm\u002Fmdadm.conf\n\n# 重启 mdmonitor 服务\nsudo systemctl restart mdmonitor\n\n# 触发一条测试通知\nsudo mdadm --monitor --scan --test --oneshot\n",[43,825,823],{"__ignoreMap":285},[16,827,828,829,297,832,297,835,838],{},"前提是这台机器本身能发邮件（装了 ",[43,830,831],{"code":831},"postfix",[43,833,834],{"code":834},"msmtp",[43,836,837],{"code":837},"ssmtp"," 等本地邮件转发工具）。对 HomeLab 用户这往往比较麻烦——下面的 HTTP Webhook 方式更现代。",[523,840,842],{"id":841},"_92-http-webhook-通知推荐以-bark-为例","9.2 HTTP Webhook 通知（推荐，以 Bark 为例）",[16,844,845,852],{},[846,847,851],"a",{"href":848,"rel":849},"https:\u002F\u002Fgithub.com\u002FFinb\u002FBark",[850],"nofollow","Bark"," 是 iOS 上一个免费的 Push 应用，服务端只需要发 HTTP POST。配置思路：",[430,854,855,862],{},[70,856,857,858,861],{},"mdmonitor 发现故障 → 调用 ",[43,859,860],{"code":860},"PROGRAM"," 指定的脚本",[70,863,864,865,868],{},"脚本里用 ",[43,866,867],{"code":867},"curl"," POST 到 Bark API → 手机收到推送",[16,870,871,874,875,878],{},[27,872,873],{},"第 1 步","：在 iPhone 上安装 Bark App，复制它给你的 API URL（形如 ",[43,876,877],{"code":877},"https:\u002F\u002Fapi.day.app\u002Fyour_device_key","）。",[16,880,881,884,885,65],{},[27,882,883],{},"第 2 步","：写通知脚本 ",[43,886,887],{"code":887},"\u002Fusr\u002Flocal\u002Fbin\u002Fmdadm-notify.sh",[279,889,892],{"className":890,"code":891,"language":284,"meta":285},[282],"sudo tee \u002Fusr\u002Flocal\u002Fbin\u002Fmdadm-notify.sh > \u002Fdev\u002Fnull \u003C\u003C'EOF'\n#!\u002Fbin\u002Fbash\n# mdmonitor 触发时以三个参数调用本脚本：\n#   $1 = 事件类型 (Fail \u002F DegradedArray \u002F RebuildFinished \u002F TestMessage 等)\n#   $2 = 涉及的阵列 (如 \u002Fdev\u002Fmd0)\n#   $3 = 涉及的成员盘 (Fail 等事件会带，其他可能为空)\n\nEVENT=\"$1\"\nARRAY=\"$2\"\nDEV=\"$3\"\n\nBARK_KEY=\"your_device_key_here\"        # ← 改成你自己的 key\nHOSTNAME=\"$(hostname)\"\n\ncurl -s -X POST \"https:\u002F\u002Fapi.day.app\u002F$BARK_KEY\" \\\n  --data-urlencode \"title=[$HOSTNAME] RAID $EVENT\" \\\n  --data-urlencode \"body=Array: $ARRAY  Device: $DEV\" \\\n  --data-urlencode \"group=mdadm\" \\\n  > \u002Fdev\u002Fnull\nEOF\n\nsudo chmod +x \u002Fusr\u002Flocal\u002Fbin\u002Fmdadm-notify.sh\n",[43,893,891],{"__ignoreMap":285},[16,895,896,899,900,902],{},[27,897,898],{},"第 3 步","：在 ",[43,901,482],{"code":482}," 里加一行，让 mdmonitor 触发这个脚本：",[279,904,907],{"className":905,"code":906,"language":460},[458],"PROGRAM \u002Fusr\u002Flocal\u002Fbin\u002Fmdadm-notify.sh\n",[43,908,906],{"__ignoreMap":285},[16,910,911,914],{},[27,912,913],{},"第 4 步","：重启 mdmonitor 并测试：",[279,916,919],{"className":917,"code":918,"language":284,"meta":285},[282],"sudo systemctl restart mdmonitor\n\n# 触发一条测试事件，会同时调用 PROGRAM 脚本和 MAILADDR 邮件\nsudo mdadm --monitor --scan --test --oneshot\n",[43,920,918],{"__ignoreMap":285},[16,922,923,924,927],{},"iPhone 应该立即收到一条 Bark 推送，标题类似 ",[43,925,926],{"code":926},"[server-01] RAID TestMessage","，说明链路已通。",[16,929,930,933,934,936],{},[27,931,932],{},"换成其他服务同理","：把 ",[43,935,867],{"code":867}," 里的 Bark URL 换成企业微信机器人、钉钉机器人、Discord \u002F Telegram Bot、Gotify \u002F ntfy 等任一个接收 HTTP POST 的服务即可。",[10,938,940],{"title":939,"type":248},"邮件 + HTTP 建议同时配",[16,941,942,945,946,948],{},[43,943,944],{"code":944},"MAILADDR"," 和 ",[43,947,860],{"code":860}," 可以并存，mdmonitor 会两个都触发。关键数据盘推荐都配上——万一 Bark 服务抖动，还有邮件作兜底通道。",[20,950,952],{"id":951},"_10-销毁-停用-raid","10. 销毁 \u002F 停用 RAID",[16,954,955],{},"以后如果不想用 RAID 了（换方案、要拆盘、清理旧环境），正确的流程：",[279,957,960],{"className":958,"code":959,"language":284,"meta":285},[282],"# 1. 卸载文件系统\nsudo umount \u002Fdata\n\n# 2. 从 \u002Fetc\u002Ffstab 里删除对应行（避免下次开机挂载失败阻塞启动）\nsudo sed -i '\u002F\\\u002Fdata\u002Fd' \u002Fetc\u002Ffstab\n\n# 3. 停止阵列\nsudo mdadm --stop \u002Fdev\u002Fmd0\n\n# 4. 擦除每块成员盘上的 mdadm 超级块（关键！）\nsudo mdadm --zero-superblock \u002Fdev\u002Fsdb1\nsudo mdadm --zero-superblock \u002Fdev\u002Fsdc1\n\n# 5. 从 \u002Fetc\u002Fmdadm\u002Fmdadm.conf 里删掉对应的 ARRAY 行（手动编辑）\nsudo nano \u002Fetc\u002Fmdadm\u002Fmdadm.conf\n\n# 6. 更新 initramfs\nsudo update-initramfs -u\n\n# 7. (可选) 完全擦磁盘，准备做新用途\nsudo wipefs -a \u002Fdev\u002Fsdb\nsudo wipefs -a \u002Fdev\u002Fsdc\n",[43,961,959],{"__ignoreMap":285},[10,963,965],{"title":964,"type":567},"第 4 步 --zero-superblock 最容易漏",[16,966,967],{},"不擦掉超级块的话，这两块盘上的 RAID 元数据还在，下次你想用它们建别的 RAID、或当普通盘用时，系统会报警或\"默默把它们认成旧阵列的一部分\"。务必执行。",[20,969,971],{"id":970},"_11-常见故障排查","11. 常见故障排查",[99,973,974,987],{},[102,975,976],{},[105,977,978,981,984],{},[108,979,980],{},"现象",[108,982,983],{},"可能原因",[108,985,986],{},"对策",[130,988,989,1009,1026,1043,1057,1074,1092],{},[105,990,991,999,1002],{},[135,992,993,995,996],{},[43,994,303],{"code":303}," 报 ",[43,997,998],{"code":998},"not large enough",[135,1000,1001],{},"两块盘实际可用空间不一致（哪怕标称一样）",[135,1003,1004,1005,1008],{},"用 ",[43,1006,1007],{"code":1007},"--size=\u003C具体值>"," 显式指定较小值，单位 K",[105,1010,1011,1017,1023],{},[135,1012,1013,1014,1016],{},"重启后 ",[43,1015,45],{"code":45}," 没自动挂载",[135,1018,1019,1020,1022],{},"fstab 里用了 ",[43,1021,392],{"code":392}," 但设备名变了",[135,1024,1025],{},"改用 UUID（见 7.1 节）",[105,1027,1028,1034,1037],{},[135,1029,1013,1030,604,1032],{},[43,1031,392],{"code":392},[43,1033,607],{"code":607},[135,1035,1036],{},"mdadm.conf 里没有该阵列的 ARRAY 行，或 initramfs 没更新",[135,1038,1039,1040],{},"重写 mdadm.conf + ",[43,1041,1042],{"code":1042},"sudo update-initramfs -u",[105,1044,1045,1048,1051],{},[135,1046,1047],{},"Rebuild 速度很慢",[135,1049,1050],{},"内核默认速度上限偏低",[135,1052,1053,1056],{},[43,1054,1055],{"code":1055},"echo 200000 | sudo tee \u002Fproc\u002Fsys\u002Fdev\u002Fraid\u002Fspeed_limit_max","（单位 KB\u002Fs）",[105,1058,1059,1062,1065],{},[135,1060,1061],{},"mdmonitor 不发通知",[135,1063,1064],{},"服务没起 \u002F mdadm.conf 格式错 \u002F MAILADDR 写错",[135,1066,1067,316,1070,1073],{},[43,1068,1069],{"code":1069},"systemctl status mdmonitor",[43,1071,1072],{"code":1072},"journalctl -u mdmonitor"," 看日志",[105,1075,1076,1079,1082],{},[135,1077,1078],{},"Bark 脚本不触发",[135,1080,1081],{},"PROGRAM 路径错 \u002F 脚本没可执行权限",[135,1083,1084,1085,1088,1089],{},"确认脚本已 ",[43,1086,1087],{"code":1087},"chmod +x","，首行是 ",[43,1090,1091],{"code":1091},"#!\u002Fbin\u002Fbash",[105,1093,1094,1101,1104],{},[135,1095,1096,1097,1100],{},"换完盘 ",[43,1098,1099],{"code":1099},"--add"," 后 rebuild 立刻失败",[135,1102,1103],{},"新盘也有问题 \u002F 新分区比老分区小",[135,1105,1106],{},"SMART 检查新盘；确认新分区 ≥ 老分区",[10,1108,1110],{"title":1109,"type":13},"作者注",[16,1111,1112,1113,1115,1116,1118,1119,1121,1122,1125],{},"本文基于 Ubuntu Server 22.04 \u002F 24.04 + 数据盘 RAID 的场景整理。对 CentOS \u002F RHEL 系读者，主要差异是 ",[43,1114,491],{"code":491},"（无子目录）和 ",[43,1117,505],{"code":505}," 替代 ",[43,1120,501],{"code":501},"；其他命令和流程通用。如果要做",[27,1123,1124],{},"系统盘 RAID","（root \u002F boot 在 RAID 上），复杂度显著提升——涉及 GRUB、initramfs 内的 raid 模块、metadata 版本选择等，本文不涉及。",{"title":285,"searchDepth":1127,"depth":1127,"links":1128},4,[1129,1131,1132,1133,1134,1135,1136,1142,1146,1153,1157,1158],{"id":22,"depth":1130,"text":22},2,{"id":93,"depth":1130,"text":94},{"id":258,"depth":1130,"text":259},{"id":343,"depth":1130,"text":344},{"id":378,"depth":1130,"text":379},{"id":415,"depth":1130,"text":416},{"id":468,"depth":1130,"text":469,"children":1137},[1138,1140,1141],{"id":525,"depth":1139,"text":526},3,{"id":549,"depth":1139,"text":550},{"id":587,"depth":1139,"text":588},{"id":611,"depth":1130,"text":612,"children":1143},[1144],{"id":621,"depth":1139,"text":1145},"7.1 写入 \u002Fetc\u002Ffstab，让重启后自动挂载",{"id":687,"depth":1130,"text":688,"children":1147},[1148,1149,1150,1151,1152],{"id":697,"depth":1139,"text":698},{"id":735,"depth":1139,"text":736},{"id":745,"depth":1139,"text":746},{"id":755,"depth":1139,"text":756},{"id":782,"depth":1139,"text":783},{"id":798,"depth":1130,"text":799,"children":1154},[1155,1156],{"id":818,"depth":1139,"text":819},{"id":841,"depth":1139,"text":842},{"id":951,"depth":1130,"text":952},{"id":970,"depth":1130,"text":971},[1160],"系统","2026-02-10","在 Ubuntu Server 上用 mdadm 把两块以上数据盘做成软 RAID，承载 Docker 等应用数据——从磁盘准备、RAID 1 创建、持久化挂载，到故障磁盘替换、mdmonitor 邮件\u002FBark 告警的完整流程。",false,"md",null,{"slots":1167},{},true,"\u002Fposts\u002Flinux-software-raid-mdadm-guide",{"text":1171,"minutes":1172,"time":1173,"words":1174},"16 min read",15.34,920400,3068,{"title":5,"description":1162},{"loc":1169},"posts\u002Fposts\u002Flinux-software-raid-mdadm-guide",[1179,1180,1181,1182,814,1183,1184,1185,1186,1187],"Linux","Ubuntu Server","RAID","软RAID","ext4","存储","高可用","故障恢复","运维","tech","Gyk7hfynxOlnAInatv4C5KDune0HYnVyoTqFRXqsgMY",[1191,1196],{"title":1192,"path":1193,"stem":1194,"date":1195,"type":1188,"children":-1},"iStoreOS 安装 OpenClash 配置旁路由","\u002Fposts\u002Fistoreos-openclash","posts\u002Fposts\u002Fistoreos-openclash","2026-02-09",{"title":1197,"path":1198,"stem":1199,"date":1161,"type":1188,"children":-1},"使用 TrueNAS 运行 Alist 容器","\u002Fposts\u002Ftruenas-alist","posts\u002Fposts\u002Ftruenas-alist",1788712224000]