1707 字
9 分钟
部署

在部署 Fastapi 或者其他的 Web APId 的时候,有几个概念值得了解.

  • https
  • 启动试运行
  • 重新启动
  • 复制
  • 内存
  • 开始前的先前步骤

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

  • Traefik
    • 自动处理证书更新 ✨
  • Caddy
    • 自动处理证书更新 ✨
  • Nginx
    • 使用 Certbot 等外部组件进行证书更新
  • HAProxy
    • 使用 Certbot 等外部组件进行证书更新
  • 带有 Ingress Controller(如 Nginx) 的 Kubernetes
    • 使用诸如 cert-manager 之类的外部组件来进行证书更新
  • 由云服务商内部处理,作为其服务的一部分

我们的最终目标是以安全的方式为 api 客户提供服务,同时避免服务中断,并尽可能利用计算资源

HTTPS#

人们很容易认为 https 只是某种启动或者未启动的东西,但实际情况比这复杂的多

从开发人员的角度,我们需要注意以下几点:

  • 使用 https 的时候,服务器需要有第三方生成的证书

  • 证书有生命周期,过期后需要再次从第三方获取

  • 链接的加密只在 tcp 层,因此证书和加密处理是在 HTTP 之前完成的

  • TCP 只知道 IP 不知道域名

  • 获得安全连接后,通信协议仍然是 HTTP

    • 内容是 加密过的,即使它们是通过 HTTP 协议 发送的。
  • 默认情况下一个 IP 只有一个 HTTPS 证书,但是可以用 TLS 协议的扩展 SNI 来允许一个服务器有多个 HTTPS 证书 通常是把服务器上运行一个程序并管理所有的 HTTPS 部分: 接收加密的 HTTPS 请求,然后把解密的 HTTP 发搜到一个实际的 HTTP 应用程序中,从程序中获取 HTTP 性欲,再使用 HTTPS 证书加密返回客户端.这个服务器通常叫做 TLS 终止代理. 你可以用作 TLS 终止代理的一些选项包括:

  • Traefik(也可以处理证书更新)

  • Caddy(也可以处理证书更新)

  • Nginx

  • HAProxy

加密!#

面向开发者的 HTTPS#

域名#

首先我们要获取一些域名,然后在 DNS 服务器中配置他们.我也许会有一个云服务器??并且他会有一个固定的公共 IP,在 DNS 服务器中配置一个域名指向我的公共 IP 地址.这个操作一般只需要在最开始执行一次。

现在让我们正式关注 HTTPS

首先浏览器通过 DNS 服务器查询 IP 是什么,DNS 服务器告诉浏览器 IP 地址.然后浏览器通过在 443 端口 (浏览器端口) 与该 IP 进行通信,通信的第一步是建立客户端和服务器之间的链接并且决定使用的秘钥.

服务器中只有一个进程可以监听特定 IP 地址的特定端口.可能有其他进程在同一 ip 的其他端口监听,但每个 IP 和端口的组合只有一个进程.

TLS 的默认端口为 443,这就是我们需要的端口,由于只有一个进程可以监听这个端口,这个进程将是 TLS 终止代理,他可以访问一个或多个 TLS 证书.SNI 扩展可以检查用于该链接的可用 TLS 证书,并使用与客户端域名匹配的证书.通过使用证书,客户端和 TLS 终止代理决定如何加密这个 TCP 通信的其余部分,这就完成了 TLS 握手.握手后就有了加秘的 TCP 链接,让后就可用 HTTP 通信了.HTTPS 只是 TLS 安全链接内的普通 HTTP

运行服务器#

我们可以使用相同的方式来运行我们的服务器,但是不要使用 --relod 选项,比如

uvicorn main:app --host 0.0.0.0 --port 80
INFO: Uvicorn running on http://0.0.0.0:80 (Press CTRL+C to quit)
WARNING

如果使用 —reload,应该删除他,他会消耗更多的资源,并且更不稳定,reload 在开发中很有用,但是在生产环境中应该删除

复制 - 进程和内存#

对于 FastAPI,比如使用像 Uvicorn 这样的服务器程序,在一个进程中就昆虫为多个客服端提供服务,但许多情况下会希望使用多个进程.

多进程 -Works#

如果客户端数目远远多余单个进程可以处理的数量,并且服务器的 CPU 有多个核心,那么可以让多个进程同时处理一个应用程序,并在他们之间分发所有请求.当运行同一 API 程序的多个进程的时候,他们通常叫做 workers

还记得我们上面的一个端口只有一个进程可以监听吗?现在还是对的 (),当然为了可以同时拥有多个进程,必须有一个单个进程监听端口,然后用某种方式将通信传输到每个工作进程.

使用gunicorn部署的推荐公式为 进程数=(2*cpu核心数)+1

gunicorn main:app --workers 4 --worker-class uvicorn.workers.UvicornWorker --bind 0.0.0.0:80

每个进程的内存#

现在,当程序把内容加载到内存后,比如把模型加载到变量,都会消耗一定的 RAM,多个进程通常不共享内存,每个进程将消耗等额的内存.例如,如果您的代码加载 1 GB 大小的机器学习模型,则当您使用 API 运行一个进程时,它将至少消耗 1 GB RAM。 如果您启动 4 个进程(4 个工作进程),每个进程将消耗 1 GB RAM。 因此,您的 API 总共将消耗 4 GB RAM

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

复制工具盒策略#

要考虑的限制是有一个单一的组件来控制公共 ip 的端口,然后用一种方法把通信传输给复制的进程

  • Gunicorn 管理 Uvicorn workers
    • Gunicorn 将是监听 IP 和 端口 的 进程管理器,复制将通过 多个 Uvicorn 工作进程 进行
  • Uvicorn 管理 Uvicorn workers
    • 一个 Uvicorn 进程管理器 将监听 IP 和 端口,并且它将启动 多个 Uvicorn 工作进程
  • Kubernetes 和其他分布式 容器系统
    • Kubernetes 层中的某些东西将侦听 IP 和 端口。 复制将通过拥有多个容器,每个容器运行一个 Uvicorn 进程
  • 云服务 为您处理此问题
    • 云服务可能为您处理复制。 它可能会让您定义 要运行的进程,或要使用的 容器映像,在任何情况下,它很可能是 单个 Uvicorn 进程,并且云服务将负责复制它。