> 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/ru-men/microservices.md).

# 微服务

推荐部署和管理 Overleaf Server CE 和 Overleaf Pro 实例的方式是使用 Toolkit。

Toolkit 通过使用一些自定义脚本来简化 Overleaf 实例的创建，这些脚本抽象掉了所需微服务的编排工作。只需运行随附的初始化脚本，提供一些配置选项（如持久存储路径），Toolkit 就会负责为构成你的 Overleaf Server CE 或 Pro 实例的微服务进行配置和连接。

这样你就可以专注于定制用户体验，并实现构成你的本地实例的特定功能。Toolkit 在幕后处理所有复杂性，从而让你的 Overleaf 实例部署更加简化。

{% hint style="info" %}
出于历史兼容原因，主 Overleaf 容器称为 `sharelatex`，并基于 `sharelatex/sharelatex` Docker 镜像。这是因为该技术基于 ShareLaTeX 代码库，而该代码库已并入 Overleaf。参见 [这篇博客文章arrow-up-right](https://www.overleaf.com/blog/518-exciting-news-sharelatex-is-joining-overleaf) 了解更多详情。未来某个时候，这将被重命名以符合 Overleaf 的命名方案。
{% endhint %}

#### 架构

在 Overleaf 容器内部，软件作为一组微服务运行，由 `runit`管理。容器内一些更有意思的文件有：

* `/etc/service/`：用于各个微服务的初始化文件。
* `/var/log/overleaf/`：各个微服务的日志。
* `/overleaf/services/`：各个微服务的代码。
* `/var/lib/overleaf/`：持久数据的挂载点（对应于主机上的 `文件中，或者在` 目录）。

#### MongoDB 和 Redis 容器

Overleaf 依赖两个外部数据库：MongoDB 和 Redis。默认情况下，Toolkit 会为这两个数据库各自预配一个容器，此外还会预配 Overleaf 容器，总共三个 Docker 容器。

{% hint style="info" %}
如果你更希望连接到现有的 MongoDB 或 Redis 实例，可以在 [overleaf.rc](https://ayakaleaf-pro.ayaka.space/on-premises/zh-cn/ru-men/pages/57fa8bf4c3166efa8ac717e47bc26acf1370c610#the-overleaf.rc-file) 配置文件中设置相应的配置项。
{% endhint %}

#### 编辑器和编译流程

本节概述文档处理和编译流程。

{% hint style="info" %}
本页面描述了仅在 Overleaf Pro 中提供的 Sandboxed Compiles 下的编译流程。在 Server CE 中，编译流程使用简单的子进程——将引用一个 **容器内启动 shell** 替换为一个单一项 **在子进程中运行编译**.
{% endhint %}

组件 / 参与者：

* `用户` — 应用程序的用户
* `编辑器` — 在浏览器中运行的客户端应用程序
* `clsi` — 用于编译 PDF 的微服务
* `document-updater` — 用于处理文档更新的微服务
* `filestore` — 用于处理二进制文件的微服务
* `real-time` — 用于处理 WebSocket 的微服务
* `web` — 用于处理 API 请求的（不那么）微服务

**Redis 缓存**

* **用户**：加载编辑器页面
* **编辑器**：打开 WebSocket
* **编辑器**：通过 WebSocket 发送打开文档的请求
  * **real-time** -> **document-updater**：文档从 MongoDB 加载到 Redis
* **编辑器**：通过 WebSocket 发送文档更新
  * **real-time** -> **document-updater**：文档在 Redis 中更新
* **编辑器**：发送更多编译请求
  * 自上次刷新以来已过去 5 分钟（按文档）：
    * **document-updater**：将文档从 Redis 刷新到 MongoDB
* **编辑器**：发送更多更新
  * 每 100 次更新（按文档）：
    * **document-updater**：将文档历史从 Redis 刷新到 MongoDB
* **用户**：离开编辑器/关闭浏览器标签页
  * 5 分钟后
    * **real-time**：检查是否有其他协作者，如果没有：
      * **real-time** -> **document-updater**：将文档从 Redis 刷新到 MongoDB

**从 MongoDB 读取到 Redis**

* **document-updater** -> **web** -> **docstore**：从 MongoDB 读取

**从 Redis 刷新到 MongoDB**

* **document-updater** -> **web** -> **docstore**：写入 MongoDB

**编译 — “full”同步模式**

* **编辑器**：发送 sync-mode 设置为“full”的编译请求
* **web** -> **document-updater**：任何文档都会从 Redis 刷新到 MongoDB
* **web** -> **docstore**：所有文档都会从 MongoDB 下载
* **web** -> **clsi**：编译请求发送到 `clsi`，包括：
  * sync-mode
  * 文件树的哈希值 -> “项目状态”
  * 所有文档及其内容 -> 受 7MB 请求体限制
  * 用于单独下载的二进制文件 URL
* **clsi**：使用 sync-mode 和“项目状态”检查磁盘上的状态
  * 这是一次完整同步，因此可以忽略之前的磁盘状态
* **clsi**：清理编译目录
* **clsi**：将所有文档写入编译目录
* **clsi**：将所有二进制文件写入编译目录
  * `clsi` 从按项目划分的本地缓存中复制文件
  * 缓存未命中时：
    * **clsi** -> **filestore**：下载文件
* **clsi**：写入“项目状态”
* **clsi**：确保存在具有所需配置的 Docker 容器
  * 构建容器选项，包括 texlive 版本
  * 对选项进行哈希处理
  * 容器名称： `project-<project-id>-<user-id>-<hash>`
* **clsi**：启动容器并将 stdout/stderr 流式写入内存 -> 限制为 2MB
* **clsi**：保留已停止的容器 -> 24 小时后清理
* **clsi**：将 stdout/stderr 写入磁盘
* **clsi**：将输出文件复制到唯一的输出目录
  * build-id 由 8 个随机字节加上毫秒精度时间戳组成
  * 删除除最后 3 个（匿名用户）/最后 1 个（已登录用户）构建文件夹之外的所有文件夹
* **clsi**：编译失败/超时
  * 删除编译缓存——其中可能包含部分文件/损坏的缓存
* **编辑器**：下载 output.log 和 output.pdf

**编译 — “incremental”同步模式**

* **编辑器**：发送 sync-mode 设置为“incremental”的编译请求
* **web** -> **document-updater**：从 Redis 获取任何文档
  * “项目状态”哈希也存储在 Redis 中
  * **web** 将文件树的哈希发送到 `document-updater` 和 `document-updater` 在不匹配时可将增量编译转换为完整编译
    * 参见编辑器请求“full”编译时执行的编译流程
* **web** -> **clsi**：编译请求发送到 `clsi`，包括：
  * sync-mode
  * 文件树的哈希值 -> “项目状态”
  * 来自 Redis 的所有文档及其内容 -> 受 7MB 请求体限制
  * 不包含二进制文件
* **clsi**：使用 sync-mode 和“项目状态”检查磁盘上的状态
  * 这是一次增量同步，因此“项目状态”必须匹配
  * 不匹配时：返回 409，让 Web 重试“full”同步
    * 参见编辑器请求“full”编译时执行的编译流程
* **clsi**：将更新后的文档写入编译目录
* **clsi**：确保存在具有所需配置的 Docker 容器
  * 构建容器选项，包括 texlive 版本
  * 对选项进行哈希处理
  * 容器名称： `project-<project-id>-<user-id>-<hash>`
* **clsi**：启动容器并将 stdout/stderr 流式写入内存 -> 限制为 2MB
* **clsi**：保留已停止的容器 -> 24 小时后清理
* **clsi**：将 stdout/stderr 写入磁盘
* **clsi**：将输出文件复制到唯一的输出目录
  * build-id 由 8 个随机字节加上毫秒精度时间戳组成
  * 删除除最后 3 个（匿名用户）/最后 1 个（已登录用户）构建文件夹之外的所有文件夹
* **clsi**：编译失败/超时
  * 删除编译缓存——其中可能包含部分文件/损坏的缓存
* **编辑器**：下载 output.log 和 output.pdf

**编译 — 在模式之间切换**

* **编辑器**：检测到编译失败，下一次编译是“full”编译
* **编辑器**：检测到编译成功，下一次编译是“incremental”编译


---

# 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/ru-men/microservices.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.
