部署概念

之前部署Web应用程序时总是只知道一些工具,比如Docker,Supervisor,Nginx之类的,按照网上教程拼拼凑凑部署完成,对其中完整的概念知之甚少,没做到“知其然知其所以然”,在FastAPI官网看到了一些关于部署概念的文字,太棒了!所以翻译把它搬运过来。

在部署FastAPI应用程序时,或者实际上,任何类型的Web API,有几个概念是你可能关心的,利用它们可以找到最合适的方法来部署你的应用程序。

一些重要的概念:

  • Security - HTTPS
  • Running on startup
  • Restarts
  • Replication (the number of processes running)
  • Memory
  • Previous Steps Before Starting

我们将看到它们会如何影响部署。

当然,最终的目标是能够以一种安全的方式为你的API客户提供服务,避免中断,并尽可能高效地使用计算资源(例如远程服务器/虚拟机)🚀

我将在这里告诉你更多关于这些概念的信息,希望这将给你一个直觉,让你决定如何在非常不同的环境中部署API,甚至可能在未来还不存在的环境中部署。

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

在接下来的章节中,我将给你更多部署FastAPI应用程序的具体方法。

但现在,让我们检查一下这些重要的概念性想法。这些概念也适用于任何其他类型的Web API。💡

1. 安全 - HTTPS

我们了解到HTTPS如何为你的API提供加密。

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

而且必须有一个负责更新HTTPS证书的东西,它可能是同一个组件,也可能是不同的东西。

1.1 用于HTTPS的工具实例

你可以用作TLS终端代理的一些工具包括:

  • Traefik

    自动处理证书续订 ✨

  • Caddy

    自动处理证书续订 ✨

  • Nginx

    使用像Certbot这样的外部组件进行证书续订

  • HAProxy

    使用像Certbot这样的外部组件进行证书续订。

  • Kubernetes with an Ingress Controller like Nginx

    具有用于证书续订的外部组件,如证书管理器。

  • Handled internally by a cloud provider as part of their services (read below👇)

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

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

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

2. 程序和进程

我们将经常谈论运行中的 “进程”,因此,明确它的含义,以及与 “程序 “一词的区别是很有帮助的。

2.1 什么是程序?

程序这个词通常被用来描述很多东西。

  • 你写的代码,Python文件。
  • 可以被操作系统执行的文件,例如:python、python.exe或uvicorn。
  • 一个特定的程序,当它在操作系统上运行时,使用CPU,并在内存上存储东西。这也被称为一个进程

2.2 什么是进程

进程这个词通常用得比较具体,它具体指的是操作系统正在执行和管理的东西(如上面最后一点)。

  • 在操作系统上运行的特定程序

    这不是指文件,也不是指代码,而是特指正在被操作系统执行和管理的东西。

  • 任何程序,任何代码,只有在它被执行时才能做事情。因此,当有一个进程在运行时。

    这个进程可以被你终止(或 “杀死”),也可以被操作系统终止。一旦停止运行/被执行,进程就不能再做事情了。

  • 你在电脑上运行的每一个应用程序背后都有一些进程,每个正在运行的程序,每个窗口,等等。而且,当一台电脑开机时,通常有许多进程在同时运行。

  • 同一程序可能有多个进程在同时运行。

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

而且你可能会看到有多个进程在运行同一个浏览器程序(Firefox、Chrome、Edge等)。它们通常在每个标签上运行一个进程,再加上一些其他的额外进程。

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

3. 在启动时运行

在大多数情况下,当你创建Web API时,你希望它始终运行、不被中断,这样你的客户就可以一直访问它。当然,除非你有特定的理由,希望它只在某些情况下运行,但大多数情况下,你希望它能一直运行,并且可用。

3.1 在一个远程服务器中

当使用一个远程服务器(云服务器,虚拟机等)时,你可以做的最简单的事情是手动运行Uvicorn(或类似的),就像在本地开发时一样。

但是,如果你与服务器的连接丢失,运行中的进程可能会死亡。

如果服务器被重新启动(例如在更新或从云提供商迁移之后),你可能不会注意到它。正因为如此,你甚至不知道你必须手动重启这个进程。所以,你的API就会一直死机。😱

3.2 启动时自动运行

一般来说,你可能希望服务器程序(如Uvicorn)在服务器启动时自动启动,并且不需要任何人工干预,让一个进程始终与你的API一起运行(如Uvicorn运行你的FastAPI应用程序)。

3.3 独立的程序

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

3.4 一些工具示例

  • Docker
  • Kubernetes
  • Docker Compose
  • Docker in Swarm Mode
  • Systemd
  • Supervisor
  • Handled internally by a cloud provider as part of their services
  • Others…

我将在接下来的章节中给你更具体的例子。

4. 重启

与确保你的应用程序在启动时运行类似,你可能也想确保它在失败后被重新启动。

4.1 我们会犯错

作为人类,我们一直在犯错。软件几乎总是有隐藏在不同地方的错误。🐛

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

4.2 自动处理的小错误

当使用FastAPI构建Web API时,如果我们的代码中有错误,FastAPI通常会将其包含到触发错误的单个请求中。🛡。

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

4.3 更大的错误 - 崩溃

尽管如此,我们可能会在某些情况下编写一些代码,使整个应用程序崩溃,从而导致Uvicorn和Python崩溃。💥

然而,你肯定不希望应用程序因为某个地方的错误而一直死机,而是希望它至少在其他没有中断的路由操作中继续运行。

4.4 崩溃后重新启动

但是,在那些有非常严重的错误导致运行进程崩溃的情况下,你会希望有一个外部组件负责重启进程,至少重启几次……

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

所以,让我们把注意力集中在主要的情况上,在未来的一些特定情况下,它可能完全崩溃,而重启它仍然是有意义的。

你可能想让负责重启你的应用程序的东西作为一个外部组件,因为到那时,带有Uvicorn和Python的同一个应用程序已经崩溃了,它们除了趴下没有什么可以做的了。

4.5 一些工具示例

在大多数情况下,用于启动时运行程序的工具也被用来处理自动重新启动。 例如,这可以通过以下方式处理:

  • Docker
  • Kubernetes
  • Docker Compose
  • Docker in Swarm Mode
  • Systemd
  • Supervisor
  • Handled internally by a cloud provider as part of their services
  • Others…

5. 复制 - 进程和内存

对于一个FastAPI应用程序,使用像Uvicorn这样的服务器程序,在一个进程中运行一次就可以同时为多个客户端提供服务。

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

5.1 多个进程–Workers

如果你的客户端多于单个进程所能处理的数量(例如,如果虚拟机不太大),并且服务器的CPU中有多个核心,那么你可以让多个进程同时运行相同的应用程序,并在它们之间分配所有请求。

当你运行同一个API程序的多个进程时,它们通常被称为Workers。

5.2 工作进程和端口

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

这仍然是事实。

因此,为了能够在同一时间有多个进程,必须有一个单一的进程在一个端口上监听,然后以某种方式将通信传输给其他每个工作进程。

5.3 每个进程的内存

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

而多个进程通常不共享任何内存。这意味着,每个运行中的进程都有自己的东西、变量和内存。而如果你的代码中消耗了大量的内存,每个进程都会消耗等量的内存。

5.4 服务器内存

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

而如果你的远程服务器或虚拟机只有3GB的内存,试图加载超过4GB的内存将导致问题。🚨

5.5 多进程的一个例子

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

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

这些工作进程将运行你的应用程序,它们将执行主要计算以接收请求并返回响应,并且将加载所有变量到RAM中。

deployments_concepts

当然,在同一台机器上,除了你的应用程序外,可能还有其他进程在运行。

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

如果你有一个API,每次都做相当数量的计算,而且你有很多客户端请求,那么CPU的利用率也可能是稳定的(而不是不断地快速上升和下降)。

5.6 一些工具示例

可以有几种方法来实现这一点,我会在未来的章节中告诉你更多关于具体的策略,例如在谈论Docker和容器时。

需要考虑的主要制约因素是,必须有一个单一的组件来处理公共IP中的端口。然后,它必须有一种方法将通信传输给复制的进程/工作。

这里有一些可能的组合和策略:

  • Gunicorn managing Uvicorn workers

​ Gunicorn将是监听IP和端口的进程管理器,复制过程将由多个Uvicorn工作进程完成

  • Uvicorn managing Uvicorn workers

​ 一个Uvicorn进程管理器将监听IP和端口,它将启动多个Uvicorn工作进程

  • Kubernetes and other distributed container systems

    Kubernetes层的一些东西会监听IP和端口。复制的方式是有多个容器,每个容器有一个Uvicorn进程在运行

  • Cloud services that handle this for your

    云服务将可能为你处理复制问题。它可能会让你定义一个要运行的进程或要使用的容器镜像,在任何情况下,它很可能是一个单一的Uvicorn进程,而云服务将负责复制它。

6. 开始前的步骤

在很多情况下,你想在启动应用程序之前执行一些步骤。

例如,你可能想运行数据库迁移。

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

所以,你希望在启动应用程序之前,有一个单一的进程来执行之前的那些步骤。

而且你必须确保是一个单一的进程来运行这些先前的步骤,即使之后你为应用程序本身启动了多个进程(多个工人)。如果这些步骤是由多个进程运行的,它们就会通过平行运行来重复工作,如果这些步骤是一些微妙的东西,比如数据库迁移,它们可能会导致彼此冲突。

当然,有些情况下,多次运行前面的步骤是没有问题的,在这种情况下,处理起来就容易多了。

此外,请记住,根据你的设置,在某些情况下,你甚至可能不需要在开始应用之前的任何步骤。

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

6.1 策略示例

这在很大程度上取决于你部署系统的方式,它可能会与你启动程序的方式、处理重启等相联系。

这里有一些可能的想法。

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

7. 资源利用

你的服务器是一种资源,你可以通过你的程序、CPU的计算时间和可用的RAM内存来消耗/利用这些资源。

你想消耗/利用多少系统资源?可能很容易想到 “不多”,但在现实中,你可能想在不崩溃的情况下尽可能多地消耗。

如果你为3台服务器付费,但你只使用了它们的一点点内存和CPU,你可能在浪费钱💸,也可能在浪费服务器的电力🌎,等等。

在这种情况下,如果只有2台服务器,并使用更高比例的资源(CPU、内存、磁盘、网络带宽等)可能会更好。

另一方面,如果你有2台服务器,并且100%使用它们的CPU和内存,在某些时候,一个进程会要求更多的内存,服务器将不得不使用磁盘作为 “内存”(可能慢几千倍),甚至崩溃。或者一个进程可能需要做一些计算,将不得不等待,直到CPU再次空闲。

在这种情况下,最好是多找一台服务器,在上面运行一些进程,以便它们都有足够的内存和CPU时间。

还有一种情况是,由于某种原因,你的API的使用量激增了。也许在网上疯传,或者一些其他服务商或机器人开始使用它。在这些情况下,你可能希望有额外的资源来保证安全。

你可以把一个任意的数字作为目标,例如,资源利用率在50%到90%之间的东西。重点是,这些可能是你需要衡量和调整部署的主要内容。

你可以使用简单的工具,如HTOP来查看你的服务器所使用的CPU和RAM,或者每个进程所使用的数量。或者你可以使用更复杂的监控工具,这些工具可能分布在各个服务器上,等等。

8. 回顾

你已经阅读了一些主要的概念,在决定如何部署你的应用程序时,你可能需要记住这些概念。

  • Security - HTTPS
  • Running on startup
  • Restarts
  • Replication (the number of processes running)
  • Memory
  • Previous steps before starting

理解这些想法以及如何应用它们,会让你在配置和调整你的部署时,有一定的直觉来做出对应的决定。🤓