部署概念¶
在部署 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 进行证书续订
- Kubernetes 与 Ingress Controller(如 Nginx)
- 使用外部组件如 cert-manager 进行证书续订
- 由云提供商内部处理,作为其服务的一部分(阅读下文👇)
另一种选择是使用 云服务,它可以完成更多工作,包括设置 HTTPS。它可能有一些限制或向你收取更多费用等。但在这种情况下,你不需要自己设置 TLS 终止代理。
我将在接下来的章节中给你一些具体的例子。
然后要考虑的下一个概念都是关于运行你的实际 API 的程序(例如 Uvicorn)。
程序和进程¶
我们将大量讨论运行的“进程”,因此清楚了解它的含义以及与“程序”一词的区别是很有用的。
什么是程序¶
程序 一词通常用于描述许多事物:
- 你编写的 代码,Python 文件。
- 可以被操作系统 执行 的 文件,例如:
python、python.exe或uvicorn。 - 在操作系统上 运行 的特定程序,使用 CPU,并将内容存储在内存中。这也称为 进程。
什么是进程¶
进程 一词通常以更具体的方式使用,仅指在操作系统中运行的事物(如上述最后一点):
- 在操作系统上 运行 的特定程序。
- 这不指文件,也不指代码,它 专门 指被操作系统 执行 和管理的事物。
- 任何程序、任何代码,只有在被 执行 时才能做事。所以,当有一个 进程在运行 时。
- 进程可以被你或操作系统 终止(或“杀死”)。此时,它停止运行/执行,并且 不再能做事。
- 你在计算机上运行的每个应用程序背后都有一些进程,每个运行的程序,每个窗口等。并且计算机开机时通常有许多进程 同时 运行。
- 同一个程序 可以有 多个进程 同时运行。
如果你在操作系统中查看“任务管理器”或“系统监视器”(或类似工具),你将能够看到许多正在运行的进程。
例如,你可能会看到有多个进程运行同一个浏览器程序(Firefox、Chrome、Edge 等)。它们通常每个标签页运行一个进程,再加上一些其他额外的进程。

现在我们知道术语 进程 和 程序 之间的区别了,让我们继续讨论部署。
启动时运行¶
在大多数情况下,当你创建 Web API 时,你希望它 始终运行,不间断,以便你的客户端可以随时访问它。当然,除非你有特定原因希望它只在某些情况下运行,但大多数时候你希望它持续运行并 可用。
在远程服务器中¶
当你设置远程服务器(云服务器、虚拟机等)时,你可以做的最简单的事情是使用 fastapi run(它使用 Uvicorn)或类似的东西,手动操作,就像你在本地开发时一样。
它将在 开发期间 工作并且有用。
但是如果你与服务器的连接丢失,运行的进程 可能会死亡。
并且如果服务器重新启动(例如在更新之后,或云提供商的迁移之后),你可能 不会注意到它。因此,你甚至不会知道必须手动重新启动进程。所以,你的 API 将保持死亡状态。😱
启动时自动运行¶
通常,你可能希望服务器程序(例如 Uvicorn)在服务器启动时自动启动,并且不需要任何 人工干预,以便始终有一个运行你的 API 的进程(例如运行你的 FastAPI 应用程序的 Uvicorn)。
独立程序¶
为了实现这一点,你通常需要一个 独立程序 来确保你的应用程序在启动时运行。在许多情况下,它还会确保其他组件或应用程序也运行,例如数据库。
启动时运行的示例工具¶
一些可以完成这项工作的工具示例包括:
- Docker
- Kubernetes
- Docker Compose
- Swarm 模式下的 Docker
- Systemd
- Supervisor
- 由云提供商内部处理,作为其服务的一部分
- 其他...
我将在接下来的章节中给你更多具体的例子。
重启¶
与确保你的应用程序在启动时运行类似,你可能还希望确保它在故障后 重新启动。
我们会犯错¶
我们作为人类,总是 会犯 错误。软件几乎 总是 在不同的地方隐藏着 错误。🐛
而我们作为开发人员,在发现这些错误和实施新功能时不断改进代码(可能也会添加新的错误😅)。
自动处理小错误¶
在使用 FastAPI 构建 Web API 时,如果我们的代码中有错误,FastAPI 通常会将其限制在触发该错误的单个请求中。🛡
客户端将收到该请求的 500 内部服务器错误,但应用程序将继续处理下一个请求,而不是完全崩溃。
更大的错误 - 崩溃¶
然而,在某些情况下,我们编写的代码可能会 使整个应用程序崩溃,导致 Uvicorn 和 Python 崩溃。💥
而且,你可能仍然不希望应用程序因为一个地方的错误而保持死亡状态,你可能希望它 继续运行,至少对于没有损坏的 路径操作 是如此。
崩溃后重启¶
但在那些出现严重错误导致运行 进程 崩溃的情况下,你会希望有一个外部组件负责 重新启动 进程,至少几次...
Tip
...尽管如果整个应用程序只是 立即崩溃,可能没有必要永远保持重启它。但在那些情况下,你可能在开发期间注意到它,或者至少在部署后立即注意到。
所以让我们关注主要情况,即它可能 在未来 的某些特定情况下完全崩溃,并且重新启动它仍然有意义。
你可能希望将负责重新启动你的应用程序的东西作为一个 外部组件,因为到那时,带有 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 中的 端口。然后它必须有一种方式将通信 传输 到复制的 进程/工作器。
以下是一些可能的组合和策略:
- Uvicorn 与
--workers- 一个 Uvicorn 进程管理器 将在 IP 和 端口 上监听,并且它将启动 多个 Uvicorn 工作器进程。
- Kubernetes 和其他分布式 容器系统
- Kubernetes 层中的某些东西将在 IP 和 端口 上监听。复制将通过拥有 多个容器 来实现,每个容器运行 一个 Uvicorn 进程。
- 云服务 为你处理此事
- 云服务可能会 为你处理复制。它可能会让你定义 要运行的进程,或要使用的 容器镜像,在任何情况下,它很可能是 一个 Uvicorn 进程,而云服务将负责复制它。
Tip
如果关于 容器、Docker 或 Kubernetes 的一些项目还没有多大意义,请不要担心。
我将在未来的章节中告诉你更多关于容器镜像、Docker、Kubernetes 等的信息:容器中的 FastAPI - Docker。
启动前的预备步骤¶
在许多情况下,你希望在启动应用程序之前执行一些步骤。
例如,你可能希望运行 数据库迁移。
但在大多数情况下,你希望只执行这些步骤 一次。
所以,你将希望有一个 单一进程 来执行那些 预备步骤,然后再启动应用程序。
并且你必须确保它是一个运行那些预备步骤的单一进程,即使 之后你为应用程序本身启动 多个进程(多个工作器)。如果这些步骤由 多个进程 运行,它们将通过 并行 运行来 复制 工作,并且如果这些步骤是像数据库迁移这样精细的事情,它们可能会相互冲突。
当然,有些情况下多次运行预备步骤没有问题,在这种情况下,处理起来要容易得多。
Tip
另外,请记住,根据你的设置,在某些情况下你 甚至可能不需要任何预备步骤 来启动你的应用程序。
在这种情况下,你就不必担心任何这些。🤷
预备步骤策略的示例¶
这将 严重依赖 于你 部署系统 的方式,并且它可能与你启动程序、处理重启等的方式相关联。
以下是一些可能的想法:
- Kubernetes 中的一个“Init Container”,它在你的应用程序容器之前运行
- 一个运行预备步骤然后启动你的应用程序的 bash 脚本
- 你仍然需要一种方式来启动/重启 那个 bash 脚本,检测错误等。
Tip
我将在未来的章节中给你更多使用容器执行此操作的具体示例:容器中的 FastAPI - Docker。
资源利用率¶
你的服务器是一种 资源,你可以通过你的程序消耗或 利用 CPU 上的计算时间和可用的 RAM 内存。
你希望消耗/利用多少系统资源?可能很容易想到“不多”,但实际上,你可能希望在不崩溃的情况下消耗 尽可能多。
如果你为 3 台服务器付费,但你只使用了它们的一点 RAM 和 CPU,你可能 在浪费钱 💸,并且可能 浪费服务器电力 🌎 等。
在这种情况下,最好只有 2 台服务器并使用它们更高百分比的资源(CPU、内存、磁盘、网络带宽等)。
另一方面,如果你有 2 台服务器并且你正在使用 它们 100% 的 CPU 和 RAM,在某个时刻一个进程会请求更多内存,服务器将不得不使用磁盘作为“内存”(这可能慢数千倍),甚至 崩溃。或者一个进程可能需要做一些计算,并且必须等待直到 CPU 再次空闲。
在这种情况下,最好 再获取一台服务器 并在其上运行一些进程,以便它们都有 足够的 RAM 和 CPU 时间。
也有可能由于某种原因,你的 API 使用量出现 激增。也许它变得病毒式传播,或者也许其他一些服务或机器人开始使用它。并且你可能希望拥有额外的资源以在这些情况下安全。
你可以设置一个 任意数字 作为目标,例如,资源利用率 在 50% 到 90% 之间。关键是这些可能是你想要测量和用来调整部署的主要东西。
你可以使用简单的工具如 htop 来查看服务器中使用的 CPU 和 RAM 或每个进程使用的量。或者你可以使用更复杂的监控工具,这些工具可能分布在服务器之间等。
回顾¶
你在这里阅读了一些在决定如何部署应用程序时可能需要记住的主要概念:
- 安全性 - HTTPS
- 启动时运行
- 重启
- 复制(运行的进程数量)
- 内存
- 启动前的预备步骤
理解这些想法以及如何应用它们应该给你必要的直觉,以便在配置和调整部署时做出任何决定。🤓
在接下来的部分中,我将给你更多你可以遵循的可能策略的具体示例。🚀