花拾录
← 返回知识库

重启后下载任务全变「文件丢失」:服务比数据盘挂载先启动了

云计算 / 运维导入2026/09/220 阅读0 评论

你在一台机器上跑一个下载工具,数据目录放在一块单独的数据盘上。平时一切正常。某天机器重启后,你打开 Web 面板,发现所有已经下完的任务,全都变成了"文件丢失 + 进度 0%"。你吓得去文件系统里翻,文件好端端地摆在那里,一个都没少。手动重启一下服务,又全恢复了。

现象

重启后,下载工具里:

  • 每个任务的进度都归零,状态标记成"文件丢失""missing"或类似的字眼;
  • 文件检查时,明明文件就在 数据盘/下载目录/ 下,工具却说找不到;
  • 只要手动 systemctl restart <下载工具>,一切立刻恢复正常——文件"回来了",进度也回来了。

这个"手动重启就好"的特征,是整条线索里最重要的信号。

根因

问题出在开机时的启动顺序上:服务比数据盘的挂载,先启动了。

开机流程是这样排队的(大致):

  1. 内核启动,探测硬件;
  2. systemd 拉起各类服务,其中就包括你的下载工具;
  3. 挂载各类文件系统,其中就包括那块数据盘。

如果第 2 步没等第 3 步,那么在下载工具启动的那一刻,数据盘还没挂上。这时 /数据盘/下载目录/ 这个路径是什么?是根分区上的一个空目录(mount point 本身,内容为空)。

于是下载工具启动时扫描所有任务的文件,发现在它以为的路径下一个文件都没有,就尽职尽责地把这些任务全部标记成"文件丢失"。等它标记完、过一会儿数据盘才挂上来,文件其实已经在了——但工具已经认定"丢了",不会再自动回头复查。

这就是为什么手动重启能修好:那时数据盘已经挂上了,工具重新扫描时看到了真实文件。

有人会说"我明明加了 After=network-online.target 啊"——不够。网络就绪和文件系统挂载是两件不相干的事,等网络不等于等挂载。

解决

在服务的 systemd 单元里,声明"等这个挂载点就绪":

[Unit]
Description=Download tool
After=network-online.target
Wants=network-online.target

# 关键:告诉 systemd,本服务依赖这个挂载点
RequiresMountsFor=/数据盘/下载目录

RequiresMountsFor= 的语义正是"我要用到这个路径,启动前请确保它对应的文件系统已挂载"。systemd 会据此把它排到挂载完成之后。

改完:

systemctl daemon-reload
systemctl restart <下载工具>

然后真的重启一次机器来验证,别只 restart 服务:

systemctl reboot
# 起来后:
systemctl status <下载工具>

确认任务不再变"文件丢失",才算修好。

另外,如果这块盘是写在 /etc/fstab 里的,建议给它加上 nofail 选项:

UUID=xxxx-xxxx  /数据盘  ext4  defaults,nofail  0  2

nofail 的意思是"如果这块盘挂不上,也照常开机,别卡进紧急模式"。它和 RequiresMountsFor 配合很合适:盘在就正常等,盘真的坏了也不会把整台机器拖在启动阶段。

延伸与预防

这条坑的教训可以推广到所有"服务依赖外部资源就绪"的场景:数据库文件在某个盘上、日志写到某个挂载点、配置读自某个网络共享……只要那个资源是"后到的",服务启动太早就会看到错误的世界。

正确的做法是用依赖表达出来,而不是靠运气:

  • 依赖挂载点 → RequiresMountsFor=
  • 依赖数据库 → After=postgresql.service + Requires=
  • 依赖网络真的能通 → network-online.target
  • 依赖某个一次性任务完成 → 那个任务自己的 .service + After=

养成一个习惯:每当一个服务"手动重启就好、开机启动就坏",第一反应就是查它的启动顺序依赖。这个特征几乎能直接锁定病因,也几乎总是能用 systemd 的依赖语法修好。

评论(0)

  • 还没有评论,来抢沙发~

相关文章