跳到内容

部署概念

部署 **FastAPI** 应用程序,或者实际上,任何类型的 Web API 时,您可能都会关心一些概念。利用这些概念,您可以找到**最合适**的**应用程序部署**方式。

一些重要的概念包括

  • 安全性 - HTTPS
  • 启动时运行
  • 重启
  • 复制(运行的进程数)
  • 内存
  • 启动前的准备步骤

我们将了解它们如何影响**部署**。

最终目标是能够以**安全**的方式**服务您的 API 客户端**,**避免中断**,并尽可能高效地利用**计算资源**(例如远程服务器/虚拟机)。🚀

我将在这里为您详细介绍这些**概念**,希望这能为您提供所需的**直觉**,以便您决定如何在非常不同的环境中部署 API,甚至可能包括**未来**尚不存在的环境。

通过考虑这些概念,您将能够**评估和设计**部署**您自己的 API** 的最佳方式。

在接下来的章节中,我将为您提供更多**具体的方法**来部署 FastAPI 应用程序。

但现在,让我们先看看这些重要的**概念性思想**。这些概念也适用于任何其他类型的 Web API。💡

安全 - HTTPS

上一章关于 HTTPS 的内容中,我们了解了 HTTPS 如何为您的 API 提供加密。

我们还看到,HTTPS 通常由应用程序服务器**外部**的一个组件提供,即 **TLS 终止代理**。

并且必须有负责**续订 HTTPS 证书**的组件,它可能是同一个组件,也可能是不同的组件。

HTTPS 工具示例

您可以作为 TLS 终止代理使用的一些工具包括

  • Traefik
    • 自动处理证书续订 ✨
  • Caddy
    • 自动处理证书续订 ✨
  • Nginx
    • 与 Certbot 等外部组件配合使用以续订证书
  • HAProxy
    • 与 Certbot 等外部组件配合使用以续订证书
  • 带有 Nginx 等 Ingress Controller 的 Kubernetes
    • 与 cert-manager 等外部组件配合使用以续订证书
  • 由云提供商作为其服务的一部分在内部处理(见下文 👇)

另一个选择是使用**云服务**,它可以完成更多工作,包括设置 HTTPS。它可能会有一些限制或收取更多费用等。但在那种情况下,您就不必自己设置 TLS 终止代理了。

我将在接下来的章节中向您展示一些具体的例子。


接下来要考虑的概念都与运行实际 API 的程序(例如 Uvicorn)有关。

程序和进程

我们将大量讨论正在运行的“**进程**”,因此弄清楚它的含义以及与“**程序**”这个词的区别是很有用的。

什么是程序

**程序**这个词通常用于描述许多事物

  • 您编写的**代码**,**Python 文件**。
  • 可以由操作系统**执行**的**文件**,例如:pythonpython.exeuvicorn
  • 在操作系统上**运行**时,使用 CPU 并将内容存储在内存中的特定程序。这也称为**进程**。

什么是进程

**进程**这个词通常以更具体的方式使用,仅指在操作系统中运行的事物(如上一点所述)

  • 在操作系统上**运行**的特定程序。
    • 这不指文件,也不指代码,它**特指**正在由操作系统**执行**和管理的事物。
  • 任何程序,任何代码,只有在**执行**时才能**做事情**。所以,只有当有**进程在运行**时。
  • 进程可以由您或操作系统**终止**(或“杀死”)。此时,它会停止运行/执行,并且**不再能做事情**。
  • 您计算机上运行的每个应用程序都有一个进程在其背后,每个运行的程序、每个窗口等。通常在计算机开机时,有许多进程**同时**运行。
  • 可以有**同一程序**的**多个进程**同时运行。

如果您查看操作系统中的“任务管理器”或“系统监视器”(或类似工具),您将能够看到许多正在运行的进程。

例如,您可能会看到有多个进程正在运行相同的浏览器程序(Firefox、Chrome、Edge 等)。它们通常为每个选项卡运行一个进程,另外还有一些额外的进程。


现在我们已经了解了**进程**和**程序**这两个术语之间的区别,让我们继续讨论部署。

随启动运行

在大多数情况下,当您创建 Web API 时,您希望它**始终运行**,不中断,以便您的客户端可以随时访问它。当然,除非您有特定的理由希望它仅在某些情况下运行,但大多数时候您希望它持续运行并**可用**。

在远程服务器上

当您设置远程服务器(云服务器、虚拟机等)时,最简单的方法是手动使用 fastapi run(它使用 Uvicorn)或类似命令,就像您在本地开发时一样。

它会工作,并且**在开发过程中**会很有用。

但是,如果您的服务器连接丢失,正在**运行的进程**很可能会终止。

如果服务器重启(例如在更新后,或云提供商进行迁移后),您可能**不会注意到**。因此,您甚至不会知道您必须手动重启进程。这样,您的 API 就会一直处于停止状态。😱

开机自动运行

通常,您可能希望服务器程序(例如 Uvicorn)在服务器启动时自动启动,并且无需任何**人工干预**,以便有一个进程始终运行您的 API(例如 Uvicorn 运行您的 FastAPI 应用程序)。

独立程序

为了实现这一点,您通常会有一个**独立程序**来确保您的应用程序在启动时运行。在许多情况下,它还会确保其他组件或应用程序也运行,例如数据库。

开机运行工具示例

可以完成此工作的一些工具示例包括

  • Docker
  • Kubernetes
  • Docker Compose
  • Docker Swarm 模式
  • Systemd
  • Supervisor
  • 由云提供商作为其服务的一部分在内部处理
  • 其他...

我将在接下来的章节中向您提供更具体的示例。

重启

与确保您的应用程序在启动时运行类似,您可能也希望确保它在故障后**重启**。

我们都会犯错

我们人类**总是**会犯**错误**。软件几乎总是在不同地方隐藏着**错误**。🐛

而我们作为开发者,在发现这些错误并实现新功能时(可能也会增加新错误😅),会不断改进代码。

小错误自动处理

使用 FastAPI 构建 Web API 时,如果我们的代码中出现错误,FastAPI 通常会将错误限制在触发该错误的单个请求上。🛡

客户端将收到该请求的**500 内部服务器错误**,但应用程序将继续处理后续请求,而不会完全崩溃。

更大的错误 - 崩溃

尽管如此,有时我们可能会编写一些代码,导致 **整个应用程序崩溃**,使 Uvicorn 和 Python 也崩溃。💥

即便如此,您可能也不希望应用程序因为某个地方的错误而停止运行,您可能希望它**继续运行**,至少对于那些没有损坏的路径操作

崩溃后重启

但在那些导致运行中**进程**崩溃的严重错误情况下,您会希望有一个外部组件负责**重启**该进程,至少几次...

提示

...尽管如果整个应用程序只是**立即崩溃**,那么永远保持重启可能没有意义。但在这些情况下,您很可能会在开发过程中,或者至少在部署后立即发现它。

所以,让我们关注主要情况,即应用程序在**未来**某些特定情况下可能会完全崩溃,并且重启仍然有意义。

您可能希望将负责重启应用程序的组件作为一个**外部组件**,因为到那时,运行 Uvicorn 和 Python 的应用程序本身已经崩溃,所以应用程序的相同代码中没有什么可以对此做任何事情。

自动重启工具示例

在大多数情况下,用于**在启动时运行程序**的工具也用于处理自动**重启**。

例如,这可以由以下工具处理

  • Docker
  • Kubernetes
  • Docker Compose
  • Docker Swarm 模式
  • Systemd
  • Supervisor
  • 由云提供商作为其服务的一部分在内部处理
  • 其他...

复制 - 进程和内存

对于 FastAPI 应用程序,使用像运行 Uvicorn 的 fastapi 命令这样的服务器程序,将其在**一个进程**中运行一次即可同时服务多个客户端。

但在许多情况下,您会希望同时运行多个工作进程。

多进程 - 工作进程

如果您的客户端数量超出单个进程所能处理的范围(例如,如果虚拟机不太大),并且服务器的 CPU 具有**多个核心**,那么您可以同时运行**多个进程**来处理相同的应用程序,并将所有请求分发给它们。

当您运行同一 API 程序的**多个进程**时,它们通常被称为**工作进程**。

工作进程和端口

还记得 关于 HTTPS 的文档中提到,在服务器上,只有一个进程可以监听一个端口和 IP 地址的组合吗?

这仍然是事实。

因此,为了能够同时拥有**多个进程**,必须有一个**单个进程监听一个端口**,然后以某种方式将通信传输到每个工作进程。

每个进程的内存

现在,当程序将内容加载到内存中时,例如将机器学习模型加载到变量中,或者将大文件内容加载到变量中,所有这些都会**消耗服务器的一部分内存 (RAM)**。

而多个进程通常**不共享任何内存**。这意味着每个运行的进程都有自己的数据、变量和内存。如果您在代码中消耗大量内存,则**每个进程**都将消耗等量的内存。

服务器内存

例如,如果您的代码加载了一个**大小为 1 GB** 的机器学习模型,当您使用 API 运行一个进程时,它将至少消耗 1 GB 的 RAM。如果您启动**4 个进程**(4 个工作进程),每个进程将消耗 1 GB 的 RAM。因此,您的 API 将总共消耗**4 GB 的 RAM**。

如果您的远程服务器或虚拟机只有 3 GB 的 RAM,尝试加载超过 4 GB 的 RAM 将导致问题。🚨

多进程 - 示例

在这个例子中,有一个**管理器进程**启动并控制着两个**工作进程**。

这个管理器进程很可能是监听 IP**端口**的那个。它会将所有通信传输给工作进程。

这些工作进程将运行您的应用程序,它们将执行主要计算以接收**请求**并返回**响应**,并且它们会将您放入变量中的任何内容加载到 RAM 中。

当然,除了您的应用程序之外,同一台机器可能还会运行**其他进程**。

一个有趣的细节是,每个进程**CPU 使用率**的百分比会随时间**变化**很大,但**内存 (RAM)** 通常或多或少保持**稳定**。

如果您的 API 每次执行的计算量相当,并且您有大量客户端,那么**CPU 利用率**可能也会保持稳定(而不是持续快速波动)。

复制工具和策略示例

实现这一点有几种方法,我将在接下来的章节中向您介绍具体的策略,例如在谈论 Docker 和容器时。

要考虑的主要限制是,必须有一个**单一**组件处理**公共 IP** 中的**端口**。然后它必须有办法将通信**传输**到复制的**进程/工作进程**。

以下是一些可能的组合和策略

  • --workers 参数的 **Uvicorn**
    • 一个 Uvicorn **进程管理器**将监听**IP**和**端口**,并启动**多个 Uvicorn 工作进程**。
  • **Kubernetes** 和其他分布式**容器系统**
    • **Kubernetes** 层中的某个组件将监听**IP**和**端口**。复制将通过拥有**多个容器**来实现,每个容器运行**一个 Uvicorn 进程**。
  • 为您处理此事的**云服务**
    • 云服务可能会**为您处理复制**。它可能会让您定义**要运行的进程**,或要使用的**容器镜像**,无论如何,它很可能是一个**单个 Uvicorn 进程**,并且云服务将负责复制它。

提示

如果其中一些关于**容器**、Docker 或 Kubernetes 的内容目前还不太明白,请不必担心。

我将在未来的章节中详细介绍容器镜像、Docker、Kubernetes 等内容:容器中的 FastAPI - Docker

启动前的准备步骤

在许多情况下,您希望在**启动**应用程序**之前**执行一些步骤。

例如,您可能希望运行**数据库迁移**。

但在大多数情况下,您只会想执行这些步骤**一次**。

因此,您会希望有一个**单个进程**来执行这些**准备步骤**,然后再启动应用程序。

您必须确保只有一个进程来执行这些准备步骤,即使之后您会为应用程序本身启动**多个进程**(多个工作进程)。如果这些步骤由**多个进程**运行,它们会通过**并行**运行而**重复**工作,如果这些步骤是像数据库迁移这样精细的操作,它们可能会相互冲突。

当然,在某些情况下,多次运行准备步骤没有问题,在这种情况下,处理起来会容易得多。

提示

此外,请记住,根据您的设置,在某些情况下,您在启动应用程序之前**甚至可能不需要任何准备步骤**。

在这种情况下,您就不必担心这些了。🤷

准备步骤策略示例

这**将严重依赖**您**部署系统**的方式,并且可能与您启动程序、处理重启等方式相关联。

以下是一些可能的想法

  • Kubernetes 中的“Init 容器”,在您的应用程序容器之前运行
  • 一个 bash 脚本,运行准备步骤,然后启动您的应用程序
    • 您仍然需要一种方法来启动/重启那个 bash 脚本,检测错误等。

提示

我将在未来的章节中提供更多使用容器实现此目的的具体示例:容器中的 FastAPI - Docker

资源利用率

您的服务器是一个**资源**,您可以使用您的程序消耗或**利用** CPU 上的计算时间以及可用的 RAM 内存。

您希望消耗/利用多少系统资源?可能很容易想到“不多”,但实际上,您可能希望在**不崩溃的情况下尽可能多地消耗**。

如果您为 3 台服务器付费,但只使用了它们很少的 RAM 和 CPU,您很可能在**浪费金钱**💸,也可能在**浪费服务器电力**🌎等。

在这种情况下,最好只使用 2 台服务器,并提高其资源(CPU、内存、磁盘、网络带宽等)的利用率。

另一方面,如果您有 2 台服务器,并且**100% 利用了它们的 CPU 和 RAM**,那么在某个时候,一个进程将请求更多内存,服务器将不得不使用磁盘作为“内存”(这可能慢数千倍),甚至**崩溃**。或者一个进程可能需要进行一些计算,并且必须等到 CPU 再次空闲。

在这种情况下,最好再购买**一台服务器**,并在上面运行一些进程,以便它们都拥有**足够的 RAM 和 CPU 时间**。

还有一种情况是,由于某种原因,您的 API 使用量出现**峰值**。也许它走红了,或者其他一些服务或机器人开始使用它。在这种情况下,您可能希望拥有额外的资源以确保安全。

您可以设定一个**任意数字**作为目标,例如,资源利用率在**50% 到 90% 之间**。关键在于,这些可能是您在调整部署时希望测量和使用的主要指标。

您可以使用 htop 等简单工具来查看服务器中 CPU 和 RAM 的使用情况,或每个进程的使用量。或者您可以使用更复杂的监控工具,这些工具可能分布在多台服务器上等。

总结

您在这里读到了一些在决定如何部署应用程序时可能需要牢记的主要概念

  • 安全性 - HTTPS
  • 启动时运行
  • 重启
  • 复制(运行的进程数)
  • 内存
  • 启动前的准备步骤

理解这些思想以及如何应用它们,应该能为您在配置和调整部署时提供必要的直觉。🤓

在接下来的章节中,我将为您提供更多可遵循的具体策略示例。🚀