Btrfs maintenance
本页介绍 Btrfs 维护任务,包括通过定期 scrub 检测并修复 RAID 阵列中的数据损坏、通过 balance 优化存储空间使用,以及创建快照用于数据恢复。文中提供了建议的间隔、示例命令以及关于存储设备健康状况的警告。
Btrfs 维护
信息
此功能需要 Storage 软件包。 与其它功能丰富的文件系统类似,Btrfs 需要定期维护。本页介绍与 Btrfs 相关的日常任务。
定期 scrub
在 RAID 阵列中,你的数据存储在多个磁盘上,或者多个磁盘包含用于重新组装数据的信息。在没有 RAID 的情况下,磁盘在少数情况下可能会损坏你数据中的几个字节,而你甚至可能不会察觉数据已被损坏。使用 RAID 阵列时,你在读取文件时会将数据与其他数据副本进行比对(或在组装时校验),并会提醒你数据已损坏。对于常规 RAID,例如在 RAID1 配置中,RAID 阵列无法判断哪个文件副本是正确的,它只会通知你检测到了数据损坏。使用 Btrfs RAID 时,你不仅能够检测数据损坏,还能通过校验和区分哪个文件副本是正确的,并自动恢复它。
Scrub 是一个重新读取整个 RAID 阵列的过程,对于 Btrfs RAID,它还会修复任何数据损坏。虽然 Btrfs RAID 会在文件读取操作时修复数据,例如当你想要从 RouterOS 设备下载文件时,但强烈不建议跳过 scrub。在少数情况下,例如在 RAID1 配置中两个磁盘的数据都损坏了,Btrfs RAID 可能无法恢复数据。为避免此类情况并保护有价值的数据,请考虑定期运行 scrub。
警告
检测到大量数据损坏通常表明存储设备正在失效。当你注意到许多数据损坏警告时,请考虑检查该存储设备。
运行 scrub 的间隔取决于每个具体用例。Scrub 对存储设备来说是一项密集型任务。它会重新读取整个 RAID 阵列并执行额外的检查。在 scrub 期间,你可能会感觉到磁盘性能明显下降,直到 scrub 完成。如果你担心 scrub 期间的性能,请考虑降低 scrub 频率。如果你更关心数据完整性,请考虑提高 scrub 频率。
- 概述:用于检测并修复数据损坏
- 建议间隔:1 周
- 工作示例
示例命令:
/disk/btrfs/filesystem/print
/disk/btrfs/filesystem/scrub-start 0
你也可以使用以下命令取消 scrub:
/disk/btrfs/filesystem/scrub-cancel
定期 balance
在 Btrfs 中,数据存储在已分配的 chunk 中,这些 chunk 又允许以块的形式存储你的数据。随着时间推移,由于各种数据活动,chunk 可能会部分填满,并以次优的方式分散在许多 chunk 之间。对 Btrfs 文件系统执行 balance 意味着重新排列这些 chunk 中的数据并恢复未分配空间。因此,你可以恢复丢失的可用空间以及 Btrfs 文件系统的性能。这在某种程度上类似于其它文件系统上的碎片整理操作。
Balance 的一个重要参数是 data-usage 参数。它是一个过滤器,阻止 balance 功能处理使用率高于某个百分比的 chunk。例如,data-usage=50 只会处理已满 50% 或更少的 chunk。你可以用不同的值多次运行 balance 命令,从而减少每次 balance 操作所需的时间。根据可用空间以及自上次 balance 以来数据的写入方式,Balance 可能是一项密集型任务,因此分次使用不同 data-usage 值运行 balance 命令可能会让你受益,从而缩短因密集磁盘读写而导致 balance 性能下降的时间窗口。
如果你想分次运行 balance 命令,应使用 25、50、75 和 90 这些 data-usage 值。不建议超过 90%。对大多数用户来说,无需分次运行 balance 命令,每个间隔以 50% 的 data-usage 运行一次即可。
- 概述:用于恢复可用空间并提升性能。
- 建议间隔:每月两次。
- 建议的
data-usage:50。 - 工作示例。
示例命令:
/disk/btrfs/filesystem/print
/disk/btrfs/filesystem/balance-start data-usage=50 0
你也可以使用以下命令取消 balance:
/disk/btrfs/filesystem/balance-cancel
定期快照
快照可用于按固定间隔保存文件的变更。当你有一个可靠的数据复制间隔时,快照最为有用,这样你总能将数据还原到之前的状态。下面是一个可直接使用的脚本,用于创建定期快照:
/system/scheduler
add interval=1d name=BraidSnapshotStartCall on-event=BraidSnapshotStart policy=ftp,read,write,policy,test,sniff start-date=1970-01-01 start-time=23:15:00
add interval=1d name=BraidSnapshotCleanUpStartCall on-event=BraidSnapshotCleanUpStart policy=ftp,read,write,policy,test,sniff start-date=1970-01-01 start-time=23:00:00
add interval=3m name=SystemBackupStartCall on-event=SystemBackupStart policy=ftp,read,write,policy,test,sniff start-time=startup
/system/script
add dont-require-permissions=no name=SystemBackupStart owner=admin policy=ftp,read,write,policy,test,sniff source=":global systembackupstatuscheck;\
\n:global systembackupdirectoryname; \
\n:local sysadmin;\
\n\
\n:set \$sysadmin ( \$sysadmin \"servername@domain.tld\" );\
\n:set \$systembackupdirectoryname (\$systembackupdirectoryname \"Braid17-20/@system-backup/\");\
\n\
\n if (\$systembackupstatuscheck != \"started\") do={\
\n :set \$systembackupstatuscheck (\$systembackupstatuscheck \"started\");\
\n :local datentime ([/system/clock/get date].\"-\".[/system/clock/get time]);\
\n :local servername ([/system/identity/get name]);\
\n /system/backup/save name=\"\$systembackupdirectoryname\$servername-\$datentime\";\
\n\
\n :set \$systembackupstatuscheck (\$systembackupstatuscheck \"done\");\
\n} else={\
\n /log/info message=\"ERROR: Cannot create \$systembackupdirectoryname\$servername-\$datentime. Set manually :set systembackupstatuscheck (systembackupstatuscheck \\\"done\\\");\";\
\n}\
\n"
add dont-require-permissions=no name=BraidSnapshotStart owner=admin policy=ftp,read,write,policy,test,sniff source=":global btrfssnapshotstatuscheck;\
\n:global snapshotdirectoryname; \
\n:local maxusedspace;\
\n:local sysadmin;\
\n\
\n:set \$maxusedspace ( \$maxusedspace 80 );\
\n:set \$sysadmin ( \$sysadmin \"<servername@domain.tld>\" );\
\n:set \$snapshotdirectoryname (\$snapshotdirectoryname \"@snapshots\");\
\n\
\n if (\$btrfssnapshotstatuscheck != \"started\") do={\
\n :set \$btrfssnapshotstatuscheck (\$btrfssnapshotstatuscheck \"started\");\
\n foreach i in=[/disk/btrfs/filesystem/find] do={ \
\n :local temp [ /disk/btrfs/filesystem/get value-name=label \$i;]\
\n :local valueofusedspace [/disk/print count-only where use>=\$maxusedspace and fs-label=\$temp];\
\n if ( \$valueofusedspace=0) do={\
\n foreach j in=[/disk/btrfs/subvolume/find where fs=\$temp and top-level!=\$snapshotdirectoryname and fullname!=\$snapshotdirectoryname ] do={\
\n :local parentvar [ /disk/btrfs/subvolume/get value-name=name \$j; ];\
\n :local datentime ([/system/clock/get date].\"-\".[/system/clock/get time]);\
\n /disk/btrfs/subvolume/add read-only=yes fs=\"\$temp\" parent=\"\$parentvar\" name=\"\$snapshotdirectoryname/\$temp-\$parentvar-\$datentime\";\
\n /log/info message=\"INFO: Braid snapshot created for \$temp subvolume \$parentvar snapshotname \$snapshotdirectoryname/\$temp-\$parentvar-\$datentime\";\
\n :delay 1;\
\n }\
\n } else={\
\n /log/info message=\"ERROR: Snapshot was not created for safety reason. Braid array \$temp used space exceeded \$maxusedspace %. Add more disks or cleanup storage.\"; \
\n /tool/e-mail/send to= \$sysadmin subject=([/system/identity/get name].\" ERROR: Braid snapshot was not created \") body=(\"Snapshot was not created for safety reason. Braid array \" .\$temp. \" used space exceeded \" .\$max\
usedspace. \" % Add more disks or cleanup storage. \" );\
\n }\
\n\
\n :delay 3; \
\n }\
\n :set \$btrfssnapshotstatuscheck (\$btrfssnapshotstatuscheck \"done\");\
\n}\
\n"
add dont-require-permissions=no name=BraidSnapshotCleanUpStart owner=admin policy=ftp,read,write,policy,test,sniff source=":global btrfssnapshotcleanupstatuscheck;\
\n:global snapshotdirectoryname; \
\n:local maxsnapshotstokeep;\
\n:local maxdaysoldsnapshotstokeep;\
\n:local sysadmin;\
\n\
\n:set \$maxsnapshotstokeep ( \$maxsnapshotstokeep 10);\
\n:set \$maxdaysoldsnapshotstokeep (\$maxdaysoldsnapshotstokeep \"10d\");\
\n:set \$sysadmin ( \$sysadmin \"<servername@domain.tld>\" );\
\n:set \$snapshotdirectoryname (\$snapshotdirectoryname \"@snapshots\");\
\n\
\n if (\$btrfssnapshotcleanupstatuscheck != \"started\") do={\
\n :set \$btrfssnapshotcleanupstatuscheck (\$btrfssnapshotcleanupstatuscheck \"started\");\
\n foreach i in=[/disk/btrfs/filesystem/find] do={ \
\n :local temp [ /disk/btrfs/filesystem/get value-name=label \$i;]\
\n :local currenttimestamp; :set \$currenttimestamp ( \$currenttimestamp [/system/clock/get date ] );\
\n :set \$currenttimestamp ( \$currenttimestamp -\$maxdaysoldsnapshotstokeep);\
\n foreach j in=[/disk/btrfs/subvolume/find where fs=\$temp and top-level=\$snapshotdirectoryname ] do={\
\n :local parentname [ /disk/btrfs/subvolume/get value-name=name \$j;];\
\n :local parentsubvol [ /disk/btrfs/subvolume/get value-name=parent \$j; ];\
\n :local creationtimeofsnapshot; :set \$creationtimeofsnapshot (\$creationtimeofsnapshot [/disk/btrfs/subvolume/get value-name=creation-time \$j; ]);\
\n :local countparentsnapshots; :set \$countparentsnapshots (\$countparentsnapshots [/disk/btrfs/subvolume/print count-only where fs=\$temp and top-level=\$snapshotdirectoryname and parent=\$parentsubvol]);\
\n if ([:len \$parentsubvol]=0) do={\
\n :local parentfullname [ /disk/btrfs/subvolume/get value-name=fullname \$j;];\
\n /log/info message=\"INFO: SnapshotCleanup found snapshot of completely deleted subvolume. Location of snapshot \$temp/\$snapshotdirectoryname/\$parentname. This can only be removed manually.\";\
\n } else={\
\n if (\$currenttimestamp>=\$creationtimeofsnapshot or \$countparentsnapshots>\$maxsnapshotstokeep ) do={\
\n /log/info message=\"INFO: Braid snapshot \$snapshotdirectoryname/\$parentname deleted. SnapshotCleanUp keeps \$maxsnapshotstokeep snapshots or snapshots not older than \$maxdaysoldsnapshotstokeep days.\";\
\n /disk/btrfs/subvolume/remove \$parentname;\
\n :delay 1;\
\n }\
\n }\
\n }\
\n :delay 3; \
\n }\
\n :set \$btrfssnapshotcleanupstatuscheck (\$btrfssnapshotcleanupstatuscheck \"done\");\
\n}\
\n"
可用空间
在 Btrfs 中,由于数据以 chunk 方式存储,因此确保有足够的可用空间非常重要,这不仅关系到常规维护任务能否正常进行,也关系到文件系统性能能否达到最优。为确保你的 Btrfs 文件系统正常工作,请考虑检查 Btrfs 文件系统上是否有足够的可用空间。可用空间的理想值为 10%,但你不应让 Btrfs 文件系统填满到只剩 5% 可用空间。
- 概述:不要让 Btrfs 文件系统写满。
- 建议的可用空间:5-10%。
示例命令
/disk/btrfs/filesystem/print
提示
如果你需要更多空间,请考虑将磁盘添加到一个包含一个或多个磁盘的 Btrfs RAID 阵列中。