Home
avatar

Nax

一次诡异的 Rclone 硬盘空间暴增事件:从日志爆炸到最终真相

今天用rclone复制文件到挂载的云盘的时候发现一件奇怪的事儿:在 Linux 服务器上使用 Rclone 将文件同步到云盘时,明明只是一个上传操作,服务器的本地硬盘空间却像着了魔一样持续增加 进行了漫长而曲折的排查后,我终于找到了隐藏在层层迷雾之下的最终真相。这篇文章记录了我们从错误的猜测到找到问题根源的全过程,希望能为遇到同样困扰的你提供一份详细的排查指南和一劳永逸的解决方案。

一、问题的初始现象

我的应用场景很简单:使用一台安装了 Docker 和 qBittorrent 的 VPS 服务器下载文件,然后通过 Rclone 将下载好的文件归档到 Google Drive。

当我执行 rclone copy 命令时,怪事发生了:

  1. 硬盘空间持续增加: 通过 df -h 命令监控,我发现服务器的根分区 / 已用空间在 Rclone 运行期间不断上涨。
  2. 中断后部分空间释放: 当我用 Ctrl+C 中断 Rclone 后,硬盘空间会立刻减少一部分(例如10GB),但总体上仍然比任务开始前多出了几十 GB。
  3. 重启服务无效: 无论是重启 Rclone 还是重启 Docker 容器,这些多出来的几十 GB 空间都不会被释放。

二、可能的方向排查

错误猜测1:Rclone Mount 的 VFS 缓存

  • 理论: 如果使用 rclone mount 挂载云盘,再往挂载点写入文件,确实会因为 VFS 缓存机制消耗本地空间。
  • 事实: 我使用的是 rclone copy 命令,并未直接向挂载点写入,此路不通。

错误猜测2:服务器被攻击导致 qBittorrent 日志爆炸

  • 理论: 查看 qBittorrent 的日志,发现大量来自公网的扫描和攻击请求。这些海量请求可能导致 Docker 的日志文件飞速增长,从而占满硬盘。
  • 事实: 经过 docker inspect 定位并检查后,发现容器的日志文件本身只有几十KB,远不足以解释几十GB的空间占用。(但这个发现依然很有价值,它提醒我必须关闭 qBittorrent 的公网端口以保证安全!)

错误猜测3:Docker Overlay2 的“写时复制 (Copy-on-Write)”

  • 理论: 这是一个非常底层的猜测。当 Rclone 读取由 Docker Volume 管理的文件时,可能会触发 overlay2 存储驱动的“写时复制”机制,导致 Docker 在后台将文件完整复制一份,消耗空间。
  • 事实: 这个理论虽然听起来很完美,但它无法解释为什么我“昨天复制时没问题,今天才有问题”。CoW 机制不应如此随机。

错误猜测4:Rclone 遗留的临时文件

  • 理论: Rclone 在处理大文件或网络不稳时,可能会在 /tmp~/.cache/rclone 目录下创建临时缓冲文件,并在中断时没来得及清理。
  • 事实: 使用 find 命令对全盘进行大文件扫描后,并未在这些常见的临时目录里发现任何“孤儿文件”。所有的大文件都位于源目录和目标目录中

三、最后终于找到了原因:Rclone 挂载点写入触发了 VFS 缓存

真的无语的了啊,一开始就完全没有想到,浪费了这么多时间。

仔细看 find 命令的输出

/opt/1panel/apps/qbittorrent/qbittorrent/data/some_file.mkv
/gdrive/data/some_file.mkv

find 的结果显示,我的大文件同时存在于源目录 /opt/... 和目标目录 /gdrive/...。而 /gdrive 正是我之前用 rclone mount 命令创建的云盘挂载点

终于他喵的找到了问题: 我执行的命令是 rclone copy /opt/1panel/... /gdrive/data。这个命令的目标路径 /gdrive/data 是一个由另一个 rclone mount 进程所管理的虚拟目录。 这个操作的完整工作流是:

  1. rclone copy 进程开始将文件写入 /gdrive/data
  2. 这个“写入”操作被后台的 rclone mount 进程捕获。
  3. 为了保证稳定性和性能,mount 进程启用了默认的 VFS 文件缓存 (--vfs-cache-mode full)。
  4. mount 进程将 copy 进程发来的文件,先完整地写入到服务器本地的一个缓存目录(默认为 ~/.cache/rclone/vfs/...)中。这正是导致我服务器硬盘空间暴增的直接原因!
  5. 当文件完整写入本地缓存后,copy 进程的任务就结束了。然后 mount 进程才开始在后台将这个本地缓存文件上传到云端。
  6. 当我中断 copy 进程时,那些已经写入本地缓存、但还未被 mount 进程成功上传的文件,就全部被遗留在了硬盘上,造成了几十GB的空间永久占用。

四、解决方案其实很简单

我们必须彻底绕开本地挂载和 VFS 缓存机制,让数据直接从源目录流向云端。

  1. 清理环境(可选但推荐):

    • 停止所有在后台运行的 rclone mount 进程 (kill <pid>)。
    • 手动删除之前遗留的 VFS 缓存目录,释放空间 (rm -rf ~/.cache/rclone)。
  2. 使用正确的命令格式: 核心在于,命令的目标路径不应是本地的挂载点,而应是 Rclone 的“远程名称”

   # 错误命令:
   rclone copy /path/to/source /local/mount/point

   # 正确命令:
   rclone [command] /path/to/source <remote_name>:<path_on_cloud>
  1. 最终推荐命令:使用 rclone move 实现自动化归档 对于我这种“下载->归档”的场景,rclone move 是比 copy 更优秀的选择。它能在文件成功上传后自动删除源文件,从而实现空间自动释放和流程自动化。

    最终,我采用的、能完美解决所有问题的命令是:

   rclone move --progress /opt/1panel/apps/qbittorrent/qbittorrent/data gd:backup
*   `gd:` 是我在 Rclone 中为 Google Drive 配置的远程名称。
*   `backup` 是我希望在云盘根目录下存放这些文件的文件夹。
*   注意copy也可以,都一样

为了保证任务在 SSH 断开后依然运行,我将此命令放入了一个 `screen` 会话中。
   # 1. 创建并进入 screen 会话
   screen -S rclone_task

   # 2. 在新会话中运行 move 命令
   rclone move --progress /opt/1panel/apps/qbittorrent/qbittorrent/data gd:backup

   # 3. 分离会话,让它去后台运行
   按下 Ctrl+A, 再按 D
   
   # 4. 重新进入会话
   screen -r rclone_task
rclone copy drive 挂载