VPS磁盘健康监控:为什么SMART无法读取?
VPS环境下的虚拟磁盘无法直接调用SMART数据。本文解析为何smartctl命令会失败,并提供四种可行的监控方案,包括内核I/O错误检测、文件系统只读状态监控及延迟预警,帮助你在磁盘故障前及时发现隐患。
VPS 磁盘健康监控的实际可见范围
VPS 的磁盘健康监控始于一个大多数指南都会回避的事实:磁盘并不属于你。你的客户机看到的只是一个虚拟块设备。物理驱动器及其上存储的每一个计数器都属于宿主机。smartctl /dev/vda 命令失败并非因为你输入错误,而是因为该设备背后的底层硬件无法响应查询。
SMART(自监测、分析及报告技术)是驱动器自身维护的一张计数器表,包含重分配扇区、待处理扇区、通电时间及介质错误等信息。读取该表需要一条能够将 ATA 或 NVMe (non-volatile memory express) 指令传达至真实硬件的路径。半虚拟化磁盘不提供此路径,因此客户机获取的存储设备已剥离了遥测数据。
租户监控的是影响而非硬件。从客户机内部可以看到四个信号:内核日志中的 I/O (input/output) 错误、文件系统被重新挂载为只读模式、延迟逐渐升高以及磁盘空间耗尽。这四项指标均可设置告警,且都会在用户察觉异常前显现。请优先配置这些监控。责任划分应在最后考虑,因为它决定了你应当将精力投入何处。
验证服务器实际暴露的设备
不要预设你所处的情况。请先观察,再阅读对应章节。
sudo apt update && sudo apt install -y smartmontools nvme-cli
lsblk -o NAME,TYPE,SIZE,MODEL,TRAN
sudo smartctl -a /dev/vdavirtio-blk,常见的 KVM(基于内核的虚拟机)磁盘。 设备为 /dev/vda,smartctl 在发送任何指令前就会停止:
/dev/vda: Unable to detect device type
Please specify device type with the -d option.virtio-blk 是一种半虚拟化传输方式,其后端没有 ATA 或 SCSI 指令集,因此没有通道可以承载 SMART 请求。-d sat 和 -d scsi 会以同样的方式失败,因为问题在于传输层,而非标志位。
模拟的 SATA 或 SCSI 磁盘。 设备为 /dev/sda,smartctl 可以运行到识别阶段。型号行显示为 QEMU HARDDISK。该字符串本身就回答了问题:你正在读取一个由模拟器生成的设备,它不报告任何可用的 SMART 能力。
NVMe 命名空间。 sudo nvme smart-log /dev/nvme0n1 会返回完整的日志,这往往会误导用户。请先使用 sudo nvme id-ctrl /dev/nvme0 | grep -E '^(mn|sn)' 检查控制器标识。如果型号名称中包含网络存储产品,说明该控制器是软件模拟的,因此 percentage_used 和 media_errors 描述的是该模拟层,而非你数据底层的闪存。如果你想了解存储设备的真实情况,请 在 Linux 上验证 NVMe 磁盘,而不要盲目信任方案描述。
容器,例如 LXC(Linux 容器)或 OpenVZ。 你没有自己的块设备。lsblk 会显示宿主机的设备或什么都不显示,且 smartctl 会被拒绝,因为容器不持有 CAP_SYS_RAWIO:
Smartctl open device: /dev/sda failed: Permission denied关于它能正常工作的情况,有一点需要警告。如果 VPS 上的 smartctl 返回了完整的属性表,请在采取行动前先查看序列号。部分主机商会暴露直通设备节点,这些计数器属于该物理机上所有租户共享的硬件。如果其中的 Reallocated_Sector_Ct 数值上升,请提交工单。这并不代表你的数据存在问题。
信号 1:内核日志中的 I/O 错误
这是租户所能获取的最高价值信号,且无需安装任何代理。
sudo journalctl -k -p err -b
sudo journalctl -k --since "7 days ago" | grep -iE 'i/o error|remount|ext4-fs error|buffer i/o'来自虚拟磁盘的失败请求如下所示:
blk_update_request: I/O error, dev vda, sector 2101248 op 0x1:(WRITE) flags 0x800 phys_seg 1 prio class 0块层向宿主机发起写入请求,但宿主机返回了失败。在 VPS 上,这极少是因为闪存单元损坏。通常这是宿主机存储层或通往网络附加存储(NAS)的网络路径故障,因此属于服务商侧的事件。请将时间戳、设备名称和扇区信息复制到工单中,存储团队需要这些信息来与他们的日志进行比对。
最关键的 ext4 序列是这一对:
EXT4-fs error (device vda1): ext4_journal_check_start:83: comm cron: Detected aborted journal
EXT4-fs (vda1): Remounting filesystem read-only第二行是造成损害的关键,因为此时机器并未宕机。它能响应 ping 和 SSH,但所有写入操作均会失败。普通的 HTTP 健康检查会持续通过,而您的应用在处理每个请求时都会报错。
XFS 则会直接关闭文件系统:
XFS (vda1): metadata I/O error in "xfs_trans_read_buf_map+0x1c0/0x2e0" at daddr 0x2 len 1 error 5
XFS (vda1): I/O Error Detected. Shutting down filesystemjournalctl -k 默认仅读取当前启动周期的日志,除非日志存储在磁盘上;许多镜像提供的易失性日志仅存在于内存中。请开启持久化,否则在故障排查过程中重启机器时,证据会随之消失。
sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald
journalctl --list-boots在下次重启后,journalctl --list-boots 应该能列出多个启动周期的日志。即使开启了持久化,一旦文件系统变为只读,也无法记录后续发生的事件,这就是将日志发送到远程服务器的有力依据。
信号 2:捕获只读重新挂载
在尝试检测故障之前,先让故障变得明显。
findmnt -no SOURCE,FSTYPE,OPTIONS /检查 errors=remount-ro 选项。Ubuntu 和 Debian 云镜像在 /etc/fstab 中设置了此项,因此元数据错误会导致文件系统变为只读,而不是在损坏的情况下继续运行。如果缺少该选项,请将其添加到 /etc/fstab 中的根目录条目,或使用 sudo tune2fs -e remount-ro /dev/vda1 在超级块中进行设置。明确的停止比静默的损坏更好。
挂载标志不能作为证明。通过写入操作进行探测:
touch /var/tmp/.disk-probe在只读根文件系统上,该命令会准确输出:
touch: cannot touch '/var/tmp/.disk-probe': Read-only file system使用 /var/tmp,不要使用 /tmp。在大多数镜像中,/tmp 是驻留在内存中的 tmpfs,因此在该位置写入成功无法证明磁盘状态。
将写入测试与空间检查结合起来,仅在所有检查通过时发送心跳:
sudo tee /usr/local/sbin/disk-probe >/dev/null <<'EOF'
#!/bin/sh
set -eu
probe=/var/tmp/.disk-probe
echo ok > "$probe"
test "$(cat "$probe")" = ok
rm -f "$probe"
used=$(df --output=pcent / | tail -n1 | tr -dc '0-9')
test "$used" -lt 90
inodes=$(df --output=ipcent / | tail -n1 | tr -dc '0-9')
test "$inodes" -lt 90
curl -fsS --max-time 10 "https://status.example.com/api/push/REPLACE_TOKEN?status=up&msg=OK" >/dev/null
EOF
sudo chmod 755 /usr/local/sbin/disk-probe
sudo /usr/local/sbin/disk-probe && echo probe-ok最后一行中的 probe-ok 表示整个链条运行正常。set -eu 确保任何检查失败都会导致进程以非零状态退出,从而不会执行 curl 行,也就不会发送心跳。这种反转正是目的所在:监控器因未收到信号而变红;无法写入的服务器无法被信任去描述自身的问题。只读文件系统仍支持读取,因此脚本本身可以启动。
使用 systemd 定时器运行它。
# /etc/systemd/system/disk-probe.service
[Unit]
Description=Disk writability and space probe
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/disk-probe# /etc/systemd/system/disk-probe.timer
[Unit]
Description=Run the disk probe every five minutes
[Timer]
OnBootSec=2min
OnUnitActiveSec=5min
[Install]
WantedBy=timers.targetsudo systemctl daemon-reload
sudo systemctl enable --now disk-probe.timer
systemctl list-timers disk-probe.timer
journalctl -u disk-probe.service -n 20 --no-pagersystemctl list-timers 应显示该单元,且 NEXT 时间应在五分钟之内。运行失败会显示在 journalctl -u disk-probe.service 中,并带有 shell 自身的错误文本,因此无需登录即可区分文件系统是只读还是已满。
该推送 URL 是 Uptime Kuma 的推送监控器。创建一个 Push 类型的监控器,将其令牌复制到脚本中,并将监控器的心跳间隔设置得比定时器间隔稍长,这样单次运行缓慢不会导致你在凌晨 03:00 被报警。如果你还没有状态页面,自托管的 Uptime Kuma 实例 是放置此检查最经济的地方。
有两个客观限制。该探测仅确认写入已被接受,不能确认字节已到达持久存储,因为回读可能来自页面缓存。此外,它在被监控的机器上运行,因此完全卡死的服务器会保持静默,而不是报告诊断结果。
当根文件系统已经变为只读时该怎么办
- 确认状态。
findmnt -no OPTIONS /的输出以ro开头。 - 先将证据捕获到内存中:
journalctl -k -b > /dev/shm/kernel.log,然后从你的笔记本电脑通过scp user@server:/dev/shm/kernel.log .将其从服务器拉取出来。 - 不要仅仅运行
mount -o remount,rw /然后继续工作。如果 ext4 终止了日志,重新挂载会立即再次失败;如果成功了,你也在覆盖无人检查过的损坏数据。 - 重启进入服务商的救援模式,并在卸载状态下检查文件系统:ext4 使用
e2fsck -fy /dev/vda1,XFS 使用xfs_repair /dev/vda1。 - 将带有时间戳和扇区信息的
blk_update_request行发送给服务商。 - 从备份恢复并进行对比,因为需要修复的文件系统可能已经丢失了最近写入的尾部数据。
信号 3:延迟与吞吐量趋势
sudo apt install -y sysstat
iostat -xdz 5 3首先阅读 r_await 和 w_await。它们表示读或写操作的平均耗时(以毫秒为单位),包含在队列中的等待时间。接着查看 aqu-sz,即正在处理的平均请求数。对于虚拟磁盘,请忽略 %util:它仅表示队列非空;对于能够并行处理多个请求的设备,即使负载接近 100%,也远未达到其性能极限。await 才是衡量用户实际体验的指标。
绝对数值的重要性不及您自身的基准线,因此请记录并保留系统空闲时的基准数据。如果您倾向于自行收集计数器,/proc/diskstats 是原始数据源。
进行主动测量:
sudo apt install -y fio
fio --name=readlat --filename=/var/tmp/fio.probe --size=512M --rw=randread --bs=4k --iodepth=1 --direct=1 --runtime=30 --time_based --group_reporting
rm -f /var/tmp/fio.probe阅读 clat percentiles 数据块,重点关注第 99 百分位数值。--direct=1 会跳过您的页面缓存。它不会跳过宿主机的缓存,因此结果反映了从您的进程到平台存储的完整路径。请在服务器空闲时运行此测试,因为它会与您的实际工作负载竞争资源。
如果 await 数值上升且内核日志中没有错误,通常不是驱动器故障。这是宿主机上的资源争用,即存储层面的 来自邻居干扰的 CPU 窃取时间。如果这种情况每天在同一时间出现,且工单反馈系统正常,解决方案是采用 I/O 不会被共享的方案,例如在工作负载受限于磁盘时,选择 存储型 VPS 而非普通 VPS。
信号 4:可在挂载状态下运行的文件系统检查
ext4 会在超级块(superblock)中保留一个错误计数器,即使日志丢失,该计数器在重启后依然有效。
sudo dumpe2fs -h /dev/vda1 2>/dev/null | grep -iE 'filesystem state|error count|first error|last error'健康的文件系统会输出 Filesystem state: clean 和 FS Error count: 0。如果出现 clean with errors 且计数值不为 0,说明内核在某个时间点遇到了元数据错误,即使当时无人察觉且日志已被轮转覆盖。该命令应纳入每周检查计划。
你无法对已挂载的根文件系统运行 fsck,而在运行中的文件系统上执行 e2fsck -n 只会报告因数据实时变动产生的虚假问题。若要强制进行真实检查,请通过服务商提供的控制台,在内核启动参数中添加 fsck.mode=force fsck.repair=yes 并重启一次。systemd-fsck 会在根文件系统以读写模式挂载前执行检查。
XFS 不支持在线检查。xfs_repair -n /dev/vda1 拒绝在已挂载的文件系统上运行,因此必须在救援模式下执行。XFS 的补偿机制是报错非常直接:一旦发生元数据错误,它会直接关闭文件系统,而不是继续运行。
对于 Btrfs,计数器是内置且持久化的。
sudo btrfs device stats /
sudo btrfs scrub start -B /如果 write_io_errs 或 corruption_errs 大于 0,则说明发生了真实事件;计数器会在重启后保留数值,直到你手动重置。scrub 会重新读取每个数据块并验证其校验和,这是虚拟磁盘上最接近介质测试的方法。该操作会产生大量 I/O,请安排在业务低谷期执行。
信号 5:磁盘空间,包括 df 隐藏的部分
磁盘空间耗尽导致服务器故障的方式与磁盘损坏相同,且发生频率更高。
df -h /
df -i /
sudo du -xh --max-depth=1 / | sort -h | tail -n 20如果 No space left on device 显示有剩余空间,但 df -h 显示已满,说明是 inode 耗尽而非字节耗尽,此时 df -i 会显示 IUse% 已达到 100%。缓存目录或邮件池中存在数百万个小文件会导致此问题,删除大文件无法解决。
删除文件后空间未释放,通常是因为该文件仍被运行中的进程占用。sudo lsof +L1 可以列出链接计数已降为 0 的文件。重启占用文件的进程即可释放空间。
systemd journal 是常见的隐形空间占用者。journalctl --disk-usage 可以查看其占用的空间大小。在 /etc/systemd/journald.conf 中使用 SystemMaxUse=200M 限制其大小,随后执行 sudo systemctl restart systemd-journald,并使用 sudo journalctl --vacuum-size=200M 立即回收空间。
有一种情况看似故障,实则不然。在精简置备(thin provisioned)的宿主机存储上,宿主机的存储池可能已满,而您的 df 仍显示有剩余空间。此时写入操作会失败,内核日志中会出现 I/O 错误,但客户机内部没有任何空间不足的警告。如果文件系统未满却出现错误,应立即提交工单处理。
将信号接入指标代理
推送式探针只能回答“是”或“否”。趋势分析需要指标代理,Prometheus node_exporter 无需额外配置即可导出上述所有数据。可基于以下指标名称进行构建:
node_filesystem_readonly在挂载点变为只读时变为 1,这是您的重新挂载告警指标。node_filesystem_avail_bytes和node_filesystem_files_free分别涵盖字节数和 inode 使用情况。node_disk_io_time_seconds_total和node_disk_read_time_seconds_total提供忙碌时间和延迟,作为可绘图的计数器。
以下两条规则可捕获实际触发分页告警的情况:
- alert: FilesystemReadOnly
expr: node_filesystem_readonly{fstype!~"tmpfs|overlay"} == 1
for: 2m
- alert: FilesystemFillingUp
expr: predict_linear(node_filesystem_avail_bytes{mountpoint="/"}[6h], 4*24*3600) < 0
for: 30m第二条规则在当前趋势显示四天内即将耗尽空间时触发,因此您可以在空间占用达到 95%(此时往往只剩几分钟处理时间)之前,提前数天收到预警。
责任划分
服务提供商负责物理硬盘。他们监控 SMART 数据、维护磁盘阵列,并在重分配扇区(reallocated sectors)增加时更换硬盘。通常他们不会通知你,因为阵列会自动处理故障。这就是 VPS 上的 RAID 10 的作用:硬盘损坏会触发重建,而不是导致服务中断。你无法感知这些底层操作,而支付虚拟服务器租金的主要目的之一,就是为了获得这种抽象化管理。
你负责自己的数据,且硬盘遥测数据无法保护数据安全。真正导致租户数据丢失的事件包括:误执行 rm 命令、部署失败、SSH 密钥被入侵者窃取,以及导致整个阵列损坏的平台级事故。SMART 属性无法预测这些风险。
因此,租户真正的保护手段是存放在服务器之外的备份,以及你亲自执行过的恢复操作。服务提供商的快照虽然方便,但它们与受保护对象处于同一平台,这就是 快照与备份是不同保护机制 的原因。请在日历中设定演练计划:每季度将最新备份恢复到一台全新的 VPS 中,启动应用,并记录耗时。这个数字才是你真实的恢复时间。首次演练的耗时通常都比预想的要长。
何时适用 SMART
教授 smartctl 的指南是正确的,且在硬件真正归你所有时即刻生效:
- 专用服务器或裸金属服务器,此时
sudo smartctl -a /dev/sda会返回完整的属性表,且smartd可以在属性发生变化时向你发送邮件。 - 将物理磁盘透传给客户机的存储方案。服务商会明确记录这一点,因为这是其卖点。
- 你拥有的硬件,无论是位于家中还是租用的机架空间内。
- RAID 控制器后的磁盘(可通过
sudo smartctl -a -d megaraid,0 /dev/sda访问),或带有-d sat的 USB 外壳。
在真实的 NVMe 设备上,sudo smartctl -a -d nvme /dev/nvme0 和 sudo nvme smart-log /dev/nvme0n1 会从驱动器本身报告 critical_warning 和 percentage_used。在真实的 SATA 设备上,预测故障的属性为 Reallocated_Sector_Ct (5)、Current_Pending_Sector (197)、Offline_Uncorrectable (198) 和 Reported_Uncorrect (187)。其中任何一个数值偏离零,都意味着需要计划更换。大规模驱动器研究始终指向这份简短的列表,大多数其他属性均为干扰项。
请运行守护进程,而非手动检查。
sudo systemctl enable --now smartd
sudo smartctl -t short /dev/sda
sudo smartctl -l selftest /dev/sda自检日志应显示你刚刚启动的运行项为 Completed without error。Ubuntu 和 Debian 预装了 /etc/smartd.conf,并包含一行 DEVICESCAN(截至 2026 年 8 月为最新),因此守护进程会自动识别它能看到的所有磁盘,并在发生变化时向 root 发送邮件。这些方法在虚拟磁盘上均无效,这也是本指南其余部分存在的原因。
FAQ
为什么 smartctl 在我的 VPS 上无法运行?
因为磁盘是虚拟的。在运行 virtio-blk 的 KVM 虚拟机中,smartctl -a /dev/vda 会输出 /dev/vda: Unable to detect device type,因为半虚拟化磁盘不具备传输 SMART 请求所需的 ATA 或 SCSI 命令通道。在模拟磁盘上,你访问的是型号显示为 QEMU HARDDISK 的设备,其后端没有可用的 SMART 数据。在容器内部,由于缺乏 CAP_SYS_RAWIO,smartctl 会直接被拒绝执行。这些都不是配置错误,也没有任何 -d 标志可以解决。
如何判断我的 VPS 磁盘是否即将损坏?
观察运行表现而非硬件状态。检查 sudo journalctl -k -p err -b 中是否有 blk_update_request: I/O error 行以及是否存在 Remounting filesystem read-only。运行 sudo dumpe2fs -h /dev/vda1 | grep -i 'error count' 以查找日志中已丢失的错误。将 iostat -xdz 5 的 r_await 与系统健康时记录的基准数据进行对比。在 VPS 上,I/O 错误通常意味着宿主机存储存在问题,而非驱动器本身损坏,因此应提交包含时间戳和扇区信息的工单。
我应该针对 VPS 磁盘健康状况设置哪些告警?
四项告警即可覆盖。一是只读挂载,通过 node_filesystem_readonly == 1 或失败的写入探测来检测。二是剩余空间和剩余 inode 趋近于零。三是上一个时间间隔内出现的任何内核 I/O error。四是服务器心跳检测,以便在服务器停止响应时发出告警。忽略任何源自 SMART 的指标,因为在虚拟磁盘上,这些值要么缺失,要么仅描述了宿主机的模拟状态。
为什么我的文件系统被重新挂载为只读?
当 ext4 以 errors=remount-ro 挂载并遇到元数据错误时,它会主动执行此操作:停止写入以防止损坏扩散。触发原因位于重新挂载行上方的内核日志中,通常是底层设备返回 I/O 错误后导致的 EXT4-fs error(日志中止)。在未检查文件系统的情况下直接重新挂载为读写模式只会掩盖症状,而无法解决根本原因。请捕获日志,然后在救援模式下卸载文件系统并使用 e2fsck -fy /dev/vda1 进行检查。
我能在虚拟服务器上读取 SMART 数据吗?
在特定情况下可以。独立服务器和裸金属服务器会提供真实的属性数据。将物理磁盘直通给客户机的存储方案以及你自己拥有的宿主机也可以。某些平台会向客户机呈现 NVMe 控制器,此时 nvme smart-log 会返回日志,因此请先运行 sudo nvme id-ctrl /dev/nvme0:如果型号名称指向网络存储服务,则说明这些计数器来自软件控制器。如果直通节点在共享机器上暴露了真实的计数器,它们描述的也是与其他租户共享的硬件,因此唯一有效的操作是提交工单。