跳到内容

部署概念

在部署 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
  • Swarm 模式下的 Docker
  • Systemd
  • Supervisor
  • 由云提供商作为其服务的一部分在内部处理
  • 其他...

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

重启

类似于确保您的应用程序在启动时运行,您可能还希望确保它在失败后 重新启动

我们都会犯错

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

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

自动处理小错误

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

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

大错误 - 崩溃

尽管如此,也可能出现我们编写的代码 导致整个应用程序崩溃,从而使 Uvicorn 和 Python 崩溃的情况。💥

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

崩溃后重启

但在那些发生严重错误导致运行中的 进程 崩溃的情况下,您会需要一个外部组件来负责 重启 进程,至少几次……

提示

……尽管如果整个应用程序只是 立即崩溃,那么一直重启它可能没有意义。但在这些情况下,您可能会在开发过程中,或至少在部署后立即注意到它。

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

您可能希望将负责重启应用程序的组件作为一个 外部组件,因为到那时,Uvicorn 和 Python 的应用程序本身已经崩溃,因此应用程序的相同代码中没有任何东西可以处理它。

自动重启的示例工具

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

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

  • Docker
  • Kubernetes
  • Docker Compose
  • Swarm 模式下的 Docker
  • 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 中的 端口。然后,它必须有一种方式将通信 传输 到复制的 进程/工作器

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

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

提示

如果其中一些关于 容器、Docker 或 Kubernetes 的项目目前还不太理解,请不必担心。

我将在未来的章节中向您介绍更多关于容器镜像、Docker、Kubernetes 等内容:FastAPI in Containers - Docker

启动前的准备步骤

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

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

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

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

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

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

提示

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

在这种情况下,您无需担心任何这些。🤷

准备步骤策略示例

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

以下是一些可能的想法

  • Kubernetes 中的“Init Container”,在您的应用程序容器之前运行
  • 一个 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
  • 启动时运行
  • 重启
  • 复制(运行的进程数量)
  • 内存
  • 启动前的准备步骤

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

在接下来的部分中,我将为您提供更多具体的策略示例。🚀