> For the complete documentation index, see [llms.txt](https://ayakaleaf-pro.ayaka.space/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ayakaleaf-pro.ayaka.space/on-premises/zh-cn/zhi-chi/support-guides/v5.5.7-migration-binary-files-migration.md).

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

## 二进制文件迁移

即将发布的重大版本 `6.0` Server Pro 和 Community Edition 将使二进制文件的存储使用量减半。版本中包含一次在线迁移 `5.5.7` ，作为升级的一部分，可将停机时间降到最低。

自 Server Pro `4.x`以来，二进制文件会存储两份：一份在“filestore”的活动文件存储中，另一份在完整项目历史系统中。今后，每个文件只会在完整项目历史系统中存储一份副本。

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

阶段：

* `OVERLEAF_FILESTORE_MIGRATION_LEVEL=0` （默认），文件会从 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 用户对历史存储桶中 blobs 的读取权限 `OVERLEAF_HISTORY_PROJECT_BLOBS_BUCKET` 。今后，filestore 服务将从编译器服务中提供读取。

{% hint style="warning" %}
强烈建议先在非生产/沙盒环境中执行二进制文件迁移。
{% endhint %}

{% hint style="success" %}
标准 Server Pro 许可证允许你在生产环境以及一个非生产/沙盒环境中运行应用程序；强烈建议你预置一个非生产环境用于测试。
{% endhint %}

{% hint style="info" %}
如果你升级到 Server Pro/CE 版本 `6.0` ，后来又决定降级到更早的版本，那么你应该从完整系统备份中恢复。
{% endhint %}

### 迁移流程

{% stepper %}
{% step %}

#### 创建备份

创建完整 [备份](https://docs.overleaf.com/on-premises/maintenance/data-and-backups#performing-a-consistent-backup) 对你的实例进行一致性快照的 **mongo**, **redis** 和 **sharelatex** 目录。
{% endstep %}

{% step %}

#### 更新

**工具包：** 使用 `$ bin/upgrade` 用于升级 **工具包** 到最新版本的脚本。当提示时，不要 **不要** 确认提示 **升级** 镜像？——相反，请手动编辑 **config/version** 文件并将值设置为 `5.5.7`.

**旧版 docker-compose.yml：** 更新 `sharelatex` 服务到 `5.5.7`.
{% endstep %}

{% step %}

#### 估算受影响项目的数量

{% code overflow="wrap" %}

```bash
# Overleaf Toolkit 用户：
$ 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"

# 旧版 docker-compose.yml 用户：
$ 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"
```

{% endcode %}

示例输出：

{% code fullWidth="false" %}

```
当前状态：
- 项目总数：10
- 已删除项目总数：5
抽样 1000 个项目以估算进度...
项目抽样统计：
- 抽样项目：9（占所有项目的 90%）
- 所有哈希都存在的抽样项目：5
- 需要回填哈希的项目百分比：44%（估算）
- 抽样项目有 11 个文件需要与完整项目历史系统进行比对。
- 抽样项目有 3 个文件需要上传到完整项目历史系统（估算占所有文件的 27%）。
已删除项目的抽样统计：
- 抽样已删除项目：4（占所有已删除项目的 80%）
- 所有哈希都存在的抽样已删除项目：3
- 需要回填哈希的已删除项目百分比：25%（估算）
- 抽样已删除项目有 2 个文件需要与完整项目历史系统进行比对。
- 抽样已删除项目有 1 个文件需要上传到完整项目历史系统（估算占所有文件的 50%）。
```

{% endcode %}
{% endstep %}

{% step %}

#### 刷新项目历史队列

{% code overflow="wrap" %}

```bash
# Overleaf Toolkit 用户：
$ bin/docker-compose exec sharelatex /overleaf/bin/flush-history-queues

# 旧版 docker-compose.yml 用户：
$ docker compose exec sharelatex /overleaf/bin/flush-history-queues
```

{% endcode %}

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

```
找到项目 {"project_ids":0,"limit":100000,"ts":"2025-09-01T10:35:33.353Z"}
总计 {"succeededProjects":0,"failedProjects":0}
```

{% hint style="danger" %}
如果 "failedProjects" 不为零，请联系支持并不要继续进行二进制文件迁移。
{% endhint %}
{% endstep %}

{% step %}

#### 将迁移阶段推进到 1

工具包：设置 `OVERLEAF_FILESTORE_MIGRATION_LEVEL=1` 在 `config/variables.env`.

旧版 docker-compose.yml：设置 `OVERLEAF_FILESTORE_MIGRATION_LEVEL: '1'` 设置在 `环境` 部分中的 `sharelatex` 服务。
{% endstep %}

{% step %}

#### 应用配置更改并启动实例

工具包： `bin/up -d`

旧版 docker-compose.yml： `docker compose up -d`
{% endstep %}

{% step %}

#### 验证对二进制文件的访问

在浏览器中的 Overleaf 编辑器里打开一个项目，并选择一个二进制文件，例如图片。
{% endstep %}

{% step %}

#### 运行迁移脚本

{% code overflow="wrap" %}

```bash
# Overleaf Toolkit 用户：
$ 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"

# 旧版 docker-compose.yml 用户：
$ 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"
```

{% endcode %}

{% hint style="danger" %}
如果你 [持续记录日志](https://docs.overleaf.com/on-premises/configuration/overleaf-toolkit/logging#persisting-logs) 文件在外部 **sharelatex** 容器，请确保日志目录所有者设置为 `www-data` 用户（uid=33），以便写入输出的日志文件。
{% endhint %}

输出应如下所示：

```bash
设置 UV_THREADPOOL_SIZE=16
{"name":"default","hostname":"c25e9faaeb53","pid":971,"level":30,"backend":"fs","msg":"加载后端","time":"2025-07-25T15:00:58.166Z","v":0}
将日志写入 /var/log/overleaf/file-migration-2025-07-25T15_00_58_199Z.log
开始备份项目文件...
已加载全局 blobs：0
正在处理未删除的项目...
已处理 1 个项目，耗时 0 秒
已完成更新活动项目
正在处理已删除的项目...
集合 deletedProjects 似乎为空。

已完成更新已删除项目
完成。

```

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

```bash
完成。
```

日志文件会是这样的（请使用脚本打印出的路径）：

{% code overflow="wrap" %}

```bash
$ 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":"实际已完成批处理","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}
```

{% endcode %}
{% endstep %}

{% step %}

#### 停止实例

工具包： `bin/stop sharelatex`

旧版 docker-compose.yml： `docker compose stop sharelatex`
{% endstep %}

{% step %}

#### 使旧文件对应用程序不可访问

你现在可以将旧文件移动到次级存储。我们建议先把这些文件保留一段时间，以防后续出现问题。

{% code overflow="wrap" %}

```bash
# 工具包用户：
$ bin/docker-compose run --rm --entrypoint mv sharelatex --no-clobber --verbose /var/lib/overleaf/data/user_files /var/lib/overleaf/data/old_user_files

# 旧版 docker-compose.yml 用户：
# 我们假设你使用的是 /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
# 如果你使用的是选择性绑定挂载，你可以直接移除容器内 /var/lib/overleaf/data/user_files 的绑定挂载。
```

{% endcode %}
{% endstep %}

{% step %}

#### 将迁移阶段推进到 2

工具包：设置 `OVERLEAF_FILESTORE_MIGRATION_LEVEL=2` 在 `config/variables.env`.

旧版 docker-compose.yml：设置 `OVERLEAF_FILESTORE_MIGRATION_LEVEL: '2'` 设置在 `环境` 部分中的 `sharelatex` 服务。
{% endstep %}

{% step %}

#### 应用配置更改并启动实例

工具包： `bin/up -d`

旧版 docker-compose.yml： `docker compose up -d`
{% endstep %}

{% step %}

#### 验证对二进制文件的访问

在浏览器中的 Overleaf 编辑器里打开一个项目，并选择一个二进制文件，例如图片。
{% endstep %}
{% endstepper %}

#### 离线迁移

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

* 使用管理员账户登录你的 Overleaf 实例
* 点击 **管理员** 按钮并选择 **管理站点**
* 点击 **打开/关闭编辑器** 选项卡
* 点击 **关闭编辑器** 按钮
* 点击 **断开所有用户连接** 按钮

完成后，如果有用户已登录，他们将被重定向到维护页面，而任何访问登录页面的新用户将看到维护页面并 **不能** 登录。

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

#### 在线迁移

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

* 迁移过程 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)，并附上以下详细信息：

主题：二进制文件迁移问题

正文：

* 实例类型：CE 或 Server Pro（按实际情况删除）
* 安装类型：Overleaf Toolkit 或 `docker-compose.yml` 或其他（按实际情况删除）
* 版本：5.5.x（工具包： `$ cat config/version`)
* 迁移脚本输出（应位于容器中的 `/var/log/overleaf`)
* 报告：（运行迁移脚本时使用 `--report`)
* 已处理项目：（根据脚本上一次运行结果）
* 迁移持续时间：
* `bin/doctor` 输出（使用 Toolkit 时）
* Toolkit 版本： `$ git rev-parse HEAD` （使用 Toolkit 时）

建议附上以下日志文件： `filestore` 服务发送到电子邮件。你可以在 `/var/log/overleaf/filestore.log` 位于 `sharelatex` 容器中，并按如下方式导出：

```bash
$ docker cp sharelatex:/var/log/overleaf/filestore.log .
# 用脚本打印出的时间戳替换 <timestamp>
$ docker cp sharelatex:/var/log/overleaf/file-migration-<timestamp>.log .
```

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

#### 缺失文件

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

如果缺失文件数量较少，建议手动审查这些情况，并在浏览器中的编辑器里将它们删除。

如果缺失文件数量较多，建议联系支持，请参见上面的邮件模板。

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

对于具有畸形文件树的项目，迁移可能会失败（例如，文件名为空的情况）。你可以使用 `find_malformed_filetrees` 脚本来找出这些问题，该脚本会检查数据库中的所有项目：

{% code overflow="wrap" %}

```bash
$ 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"
```

{% endcode %}

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

{% code overflow="wrap" %}

```bash
$ 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"
```

{% endcode %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://ayakaleaf-pro.ayaka.space/on-premises/zh-cn/zhi-chi/support-guides/v5.5.7-migration-binary-files-migration.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
