> ## Documentation Index
> Fetch the complete documentation index at: https://ayakaleaf-pro.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# （v5.5.7 迁移）二进制文件迁移

## 二进制文件迁移

即将发布的 Server Pro 和社区版主版本 `6.0` 将把二进制文件的存储占用减少一半。`5.5.7` 版本中包含一个在线迁移，可在升级过程中将停机时间降至最低。

自 Server Pro `4.x` 起，二进制文件会被存储两次：一次在"filestore"的活动文件存储中，另一次在完整项目历史系统中。今后，每个文件将只在完整项目历史系统中存储一份。

迁移到统一存储系统包含两个部分：一个用于控制迁移阶段的新标志，以及一个处理所有活动项目和软删除项目的脚本。

阶段：

* `OVERLEAF_FILESTORE_MIGRATION_LEVEL=0`（默认），文件从 filestore 读取并写入 filestore。文件会异步写入历史系统。
* `OVERLEAF_FILESTORE_MIGRATION_LEVEL=1`，文件从历史系统读取，并回退到 filestore；写入时同时写入 filestore 和历史系统。可以降级到 `OVERLEAF_FILESTORE_MIGRATION_LEVEL=0`。
* `OVERLEAF_FILESTORE_MIGRATION_LEVEL=2`，文件仅从历史系统读取和写入。无法降级到 `OVERLEAF_FILESTORE_MIGRATION_LEVEL=1`，除非迁移是以"离线"方式执行的。

如果将数据存储在 [S3](https://docs.overleaf.com/on-premises/configuration/overleaf-toolkit/s3) 中，并且为 filestore（`OVERLEAF_FILESTORE_S3_ACCESS_KEY_ID`）和历史系统（`OVERLEAF_HISTORY_S3_ACCESS_KEY_ID`）使用了不同的服务账户：请授予 filestore 用户对 blob 历史存储桶 `OVERLEAF_HISTORY_PROJECT_BLOBS_BUCKET` 的读取权限。今后，filestore 服务将负责处理来自编译服务的读取请求。

<Warning>
  强烈建议先在非生产/沙盒环境中执行二进制文件迁移。
</Warning>

<Check>
  标准 Server Pro 许可证允许你在一个生产环境以及一个非生产/沙盒环境中运行该应用程序；强烈建议你准备一个非生产环境用于测试。
</Check>

<Info>
  如果你升级到 Server Pro/CE `6.0` 版本后又决定降级到更早的版本，则应从完整的系统备份中恢复。
</Info>

### 迁移步骤

<Steps>
  <Step title="创建备份">
    为你的实例创建完整[备份](https://docs.overleaf.com/on-premises/maintenance/data-and-backups#performing-a-consistent-backup)，其中包含 **mongo**、**redis** 和 **sharelatex** 目录的一致性快照。
  </Step>

  <Step title="更新">
    <strong>Toolkit：</strong> 使用 `$ bin/upgrade` 脚本将 **toolkit** 升级到最新版本。当被询问时，**不要**确认 **Upgrade** image? 提示——而是手动编辑 **config/version** 文件，将值设置为 `5.5.7`。

    <strong>旧版 docker-compose.yml：</strong> 将 `sharelatex` 服务的版本更新为 `5.5.7`。
  </Step>

  <Step title="估算受影响的项目数量">
    ```bash wrap theme={null}
    # Overleaf Toolkit users:
    $ bin/docker-compose exec sharelatex /bin/bash -c "source /etc/overleaf/env.sh && source /etc/container_environment.sh && cd /overleaf/services/history-v1 && /sbin/setuser www-data node storage/scripts/back_fill_file_hash.mjs --report"

    # Legacy docker-compose.yml users:
    $ docker compose exec sharelatex /bin/bash -c "source /etc/overleaf/env.sh && source /etc/container_environment.sh && cd /overleaf/services/history-v1 && /sbin/setuser www-data node storage/scripts/back_fill_file_hash.mjs --report"
    ```

    示例输出：

    ```text theme={null}
    Current status:
    - Total number of projects: 10
    - Total number of deleted projects: 5
    Sampling 1000 projects to estimate progress...
    Sampled stats for projects:
    - Sampled projects: 9 (90% of all projects)
    - Sampled projects with all hashes present: 5
    - Percentage of projects that need back-filling hashes: 44% (estimated)
    - Sampled projects have 11 files that need to be checked against the full project history system.
    - Sampled projects have 3 files that need to be uploaded to the full project history system (estimating 27% of all files).
    Sampled stats for deleted projects:
    - Sampled deleted projects: 4 (80% of all deleted projects)
    - Sampled deleted projects with all hashes present: 3
    - Percentage of deleted projects that need back-filling hashes: 25% (estimated)
    - Sampled deleted projects have 2 files that need to be checked against the full project history system.
    - Sampled deleted projects have 1 files that need to be uploaded to the full project history system (estimating 50% of all files).
    ```
  </Step>

  <Step title="刷新项目历史队列">
    ```bash wrap theme={null}
    # Overleaf Toolkit users:
    $ bin/docker-compose exec sharelatex /overleaf/bin/flush-history-queues

    # Legacy docker-compose.yml users:
    $ docker compose exec sharelatex /overleaf/bin/flush-history-queues
    ```

    重复执行刷新，直到所有项目都已刷新（`"project_ids":0`）。

    ```text theme={null}
    found projects {"project_ids":0,"limit":100000,"ts":"2025-09-01T10:35:33.353Z"}
    total {"succeededProjects":0,"failedProjects":0}
    ```

    <Danger>
      如果"failedProjects"不为零，请联系支持团队，不要继续进行二进制文件迁移。
    </Danger>
  </Step>

  <Step title="将迁移阶段推进到 1">
    Toolkit：在 `config/variables.env` 中设置 `OVERLEAF_FILESTORE_MIGRATION_LEVEL=1`。

    旧版 docker-compose.yml：在 `sharelatex` 服务的 `environment` 部分中设置 `OVERLEAF_FILESTORE_MIGRATION_LEVEL: '1'`。
  </Step>

  <Step title="应用配置更改并启动实例">
    Toolkit：`bin/up -d`

    旧版 docker-compose.yml：`docker compose up -d`
  </Step>

  <Step title="验证对二进制文件的访问">
    在浏览器中用 Overleaf 编辑器打开一个项目，并选择一个二进制文件，例如图片。
  </Step>

  <Step title="运行迁移脚本">
    ```bash wrap theme={null}
    # Overleaf Toolkit users:
    $ bin/docker-compose exec sharelatex /bin/bash -c "source /etc/overleaf/env.sh && source /etc/container_environment.sh && cd /overleaf/services/history-v1 && /sbin/setuser www-data node storage/scripts/back_fill_file_hash.mjs --all"

    # Legacy docker-compose.yml users:
    $ docker compose exec sharelatex /bin/bash -c "source /etc/overleaf/env.sh && source /etc/container_environment.sh && cd /overleaf/services/history-v1 && /sbin/setuser www-data node storage/scripts/back_fill_file_hash.mjs --all"
    ```

    <Danger>
      如果你将[日志文件持久化](https://docs.overleaf.com/on-premises/configuration/overleaf-toolkit/logging#persisting-logs)到 **sharelatex** 容器之外，请确保日志目录的所有者设置为 `www-data` 用户（uid=33），以便能够写入输出的日志文件。
    </Danger>

    输出应如下所示：

    ```bash theme={null}
    Set UV_THREADPOOL_SIZE=16
    {"name":"default","hostname":"c25e9faaeb53","pid":971,"level":30,"backend":"fs","msg":"Loading backend","time":"2025-07-25T15:00:58.166Z","v":0}
    Writing logs into /var/log/overleaf/file-migration-2025-07-25T15_00_58_199Z.log
    Starting project file backup...
    Loaded global blobs: 0
    Processing non-deleted projects...
    Processed 1 projects, elapsed time 0s
    Done updating live projects
    Processing deleted projects...
    The collection deletedProjects appears to be empty.

    Done updating deleted projects
    Done.

    ```

    如果迁移成功，你将得到退出码 `0`，并且最后几行显示没有失败：

    ```bash theme={null}
    Done.
    ```

    日志文件内容如下所示（使用脚本打印的路径）：

    ```bash wrap theme={null}
    $ docker cp sharelatex:/var/log/overleaf/file-migration-2025-07-25T15_00_58_199Z.log .
    $ cat file-migration-2025-07-25T15_00_58_199Z.log
    {"name":"file-migration","hostname":"c25e9faaeb53","pid":971,"level":30,"end":"68839a8f577b9f009d947b27 (2025-07-25T14:54:07.000Z)","msg":"actually completed batch","time":"2025-07-25T15:00:58.379Z","v":0}
    {"name":"file-migration","hostname":"c25e9faaeb53","pid":971,"level":30,"time":"2025-07-25T15:00:58.383Z","LOGGING_IDENTIFIER":"4effa2000000000000000000","projects":1,"blobs":6,"filesWithHash":5,"filesWithoutHash":2,"filesDuplicated":0,"filesRetries":0,"filesFailed":0,"fileTreeUpdated":0,"badFileTrees":0,"globalBlobsCount":0,"globalBlobsEgress":0,"projectDeleted":0,"projectHardDeleted":0,"fileHardDeleted":0,"mongoUpdates":1,"readFromGCSCount":7,"readFromGCSIngress":28532,"writeToGCSCount":5,"writeToGCSEgress":300,"readFromGCSThroughputMiBPerSecond":0.14925639825786063,"eventLoop":{"idle":48.277844,"active":381.53244699971054,"utilization":0.8876763888372498},"diff":{"eventLoop":{"idle":48.223536,"active":134.04030200059555,"utilization":0.7354190687027976},"projects":1,"blobs":6,"filesWithHash":5,"filesWithoutHash":2,"filesDuplicated":0,"filesRetries":0,"filesFailed":0,"fileTreeUpdated":0,"badFileTrees":0,"globalBlobsCount":0,"globalBlobsEgress":0,"projectDeleted":0,"projectHardDeleted":0,"fileHardDeleted":0,"mongoUpdates":1,"readFromGCSCount":7,"readFromGCSIngress":28532,"writeToGCSCount":5,"writeToGCSEgress":300,"readFromGCSThroughputMiBPerSecond":0.14925639825786063},"deferredBatches":[],"msg":"file-migration stats","v":0}
    ```
  </Step>

  <Step title="停止实例">
    Toolkit：`bin/stop sharelatex`

    旧版 docker-compose.yml：`docker compose stop sharelatex`
  </Step>

  <Step title="使应用程序无法访问旧文件">
    现在你可以将旧文件移动到二级存储。我们建议将这些文件保留一段时间，以防日后出现问题。

    ```bash wrap theme={null}
    # Toolkit users:
    $ bin/docker-compose run --rm --entrypoint mv sharelatex --no-clobber --verbose /var/lib/overleaf/data/user_files /var/lib/overleaf/data/old_user_files

    # Legacy docker-compose.yml users:
    # We are assuming that you are using the default bind-mount in /var/lib/overleaf
    $ docker compose run --rm --entrypoint mv sharelatex --no-clobber --verbose /var/lib/overleaf/data/user_files /var/lib/overleaf/data/old_user_files
    # In case you are using selective bind-mounts, you can simply remove the bind-mount for /var/lib/overleaf/data/user_files inside the container.
    ```
  </Step>

  <Step title="将迁移阶段推进到 2">
    Toolkit：在 `config/variables.env` 中设置 `OVERLEAF_FILESTORE_MIGRATION_LEVEL=2`。

    旧版 docker-compose.yml：在 `sharelatex` 服务的 `environment` 部分中设置 `OVERLEAF_FILESTORE_MIGRATION_LEVEL: '2'`。
  </Step>

  <Step title="应用配置更改并启动实例">
    Toolkit：`bin/up -d`

    旧版 docker-compose.yml：`docker compose up -d`
  </Step>

  <Step title="验证对二进制文件的访问">
    在浏览器中用 Overleaf 编辑器打开一个项目，并选择一个二进制文件，例如图片。
  </Step>
</Steps>

#### 离线迁移

如果你希望在二进制文件迁移脚本运行期间阻止用户登录，请按以下步骤操作：

* 使用管理员账户登录你的 Overleaf 实例
* 点击 **Admin** 按钮并选择 **Manage Site**
* 点击 **Open/Close Editor** 标签页
* 点击 **Close Editor** 按钮
* 点击 **Disconnect all users** 按钮

完成后，所有已登录的用户都会被重定向到维护页面，任何访问登录页面的新用户都会看到维护页面，并且**无法**登录。

重启实例时，你需要重复这些步骤。要重新开放站点，只需重启实例即可。

#### 在线迁移

可以在应用程序仍在运行时执行迁移脚本。需要考虑以下几点：

* 迁移过程是 IO 密集型的，在脚本运行期间应监控资源使用情况。
* 如果处理并发度较高，`filestore` 服务中的事件循环可能会出现阻塞，从而导致用户体验下降。我们建议从默认值 `--concurrency=10` 和 `--concurrent-batches=1` 开始。
* 你可以随时停止脚本。再次启动时，它会验证之前的项目并跳过已处理的文件。如果你倾向于在不太繁忙的时段（例如夜间）运行迁移，这一点会很有用。

当项目数量少于 1000 个时（参见使用 `--report` 运行迁移脚本的输出），我们建议关闭站点，在维护窗口内以离线方式运行迁移。如果项目数量很多，你可以先运行脚本并监控其进度，再根据具体情况决定继续在线还是离线运行。

#### 清理旧的二进制文件数据

完成迁移并确认项目仍能访问其所有文件后，你可以删除 `/var/lib/overleaf/data/user_files` 中的旧文件存储。我们强烈建议将这些文件保留一段时间——你可以先重命名该文件夹，使应用程序无法访问它们。

### 故障排除

我们将在此处添加故障排除建议。请注意，虽然我们通常只为 Server Pro 客户提供支持，但鉴于此次迁移的特殊性，对于遇到二进制文件迁移相关问题的 CE 用户，我们也会尽力提供支持。

如果二进制文件迁移脚本失败（即以错误退出，或打印出非零的失败项目数），请通过邮件 [support+filestoremigration@overleaf.com](mailto:support+filestoremigration@overleaf.com?subject=Binary%20file%20migration%20problem\&body=Instance%20Type%3A%20CE%20or%20Server%20Pro%20%28delete%20as%20appropriate%29%0A%0AInstallation%20Type%3A%20Overleaf%20toolkit%20or%20docker-compose.yml%20or%20other%20%28delete%20as%20appropriate%29%0A%0AScript%20output%3A%0A%0Abin%2Fdoctor%20output%20%28if%20using%20toolkit%29%3A%0A) 将以下详细信息发送给我们的支持团队：

主题：Binary file migration problem

正文：

* 实例类型：CE 或 Server Pro（删除不适用的选项）
* 安装类型：Overleaf toolkit、`docker-compose.yml` 或其他（删除不适用的选项）
* 版本：5.5.x（toolkit：`$ cat config/version`）
* 迁移脚本输出（应位于容器内的 `/var/log/overleaf` 下）
* 报告：（使用 `--report` 运行迁移脚本）
* 已处理的项目：（根据脚本最后一次运行的结果）
* 迁移耗时：
* `bin/doctor` 输出（使用 toolkit 时）
* Toolkit 版本：`$ git rev-parse HEAD`（使用 Toolkit 时）

建议将 `filestore` 服务的日志文件作为附件添加到邮件中。你可以在 `sharelatex` 容器内的 `/var/log/overleaf/filestore.log` 找到它，并按如下方式导出：

```bash theme={null}
$ docker cp sharelatex:/var/log/overleaf/filestore.log .
# replace <timestamp> with the timestamp as printed by the script
$ docker cp sharelatex:/var/log/overleaf/file-migration-<timestamp>.log .
```

在附加日志文件之前，请删除其中的所有敏感信息。

#### 文件丢失

旧版本的 Server Pro/CE 会在用户上传完成之前就创建文件树条目，因此当上传失败时，文件可能会显示为丢失。在处理所有文件树时，你可能会发现少量此类情况被报告为错误。

如果丢失的文件数量较少，可以考虑手动检查这些情况，并在浏览器的编辑器中将其删除。

如果丢失的文件数量较多，请考虑联系支持团队，参见上面的邮件模板。

#### 查找损坏的文件树

对于文件树格式错误的项目（例如文件名为空），迁移可能会失败。你可以使用 `find_malformed_filetrees` 脚本检查数据库中的所有项目，从而找出这些问题：

```bash wrap theme={null}
$ bin/docker-compose exec sharelatex /bin/bash -c "cd /overleaf/services/web && /sbin/setuser www-data node scripts/find_malformed_filetrees.mjs > /tmp/malformed-file-trees.json"
```

要修复无效路径，请使用 `fix_malformed_filetree` 脚本，对每个错误路径各运行一次该命令：

```bash wrap theme={null}
$ bin/docker-compose exec sharelatex /bin/bash -c "cd /overleaf/services/web && /sbin/setuser www-data node scripts/fix_malformed_filetree.mjs --logs=/tmp/malformed-file-trees.json"
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.