三周精通FastAPI:42 手动运行服务器 - Uvicorn & Gunicorn with Uvicorn

官方文档:Server Workers - Gunicorn with Uvicorn - FastAPI

使用 fastapi 运行命令

可以直接使用fastapi run命令来启动FastAPI应用:

复制代码
fastapi run main.py

如创建openapi.py文件:

python 复制代码
from fastapi import FastAPI

app = FastAPI(openapi_url="/api/v1/openapi.json")


@app.get("/items/")
async def read_items():
    return [{"name": "Foo"}]

然后执行:

复制代码
fastapi run openapi.py

启动后显示:

复制代码
INFO     Using path openapi.py                                     
INFO     Resolved absolute path                                    
         /Users/skywalk/work/fastapi/openapi.py                    
INFO     Searching for package file structure from directories with
         __init__.py files                                         
INFO     Importing from /Users/skywalk/work/fastapi                
                                                                   
 ╭─ Python module file ─╮                                          
 │                      │                                          
 │  🐍 openapi.py       │                                          
 │                      │                                          
 ╰──────────────────────╯                                          
                                                                   
INFO     Importing module openapi                                  
INFO     Found importable FastAPI app                              
                                                                   
 ╭─ Importable FastAPI app ──╮                                     
 │                           │                                     
 │  from openapi import app  │                                     
 │                           │                                     
 ╰───────────────────────────╯                                     
                                                                   
INFO     Using import string openapi:app                           
                                                                   
 ╭─────────── FastAPI CLI - Production mode ───────────╮           
 │                                                     │           
 │  Serving at: http://0.0.0.0:8000                    │           
 │                                                     │           
 │  API docs: http://0.0.0.0:8000/docs                 │           
 │                                                     │           
 │  Running in production mode, for development use:   │           
 │                                                     │           
 │  fastapi dev                                        │           
 │                                                     │           
 ╰─────────────────────────────────────────────────────╯           
                                                                   
INFO:     Started server process [82331]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)

这时候在浏览器中浏览http://192.168.0.101:8000/items/ ,会返回信息:

复制代码
[{"name":"Foo"}]

这将适用于大多数情况。😎

例如,您可以使用该命令在容器、服务器等中启动FastAPI应用程序。

手动运行服务器 - Uvicorn

在远程服务器计算机上运行 FastAPI 应用程序所需的主要东西是 ASGI 服务器程序,例如 Uvicorn

有 3 个主要可选方案:

  • Uvicorn:高性能 ASGI 服务器。
  • Hypercorn:与 HTTP/2 和 Trio 等兼容的 ASGI 服务器。
  • Daphne:为 Django Channels 构建的 ASGI 服务器。

服务器主机和服务器程序

关于名称,有一个小细节需要记住。 💡

"服务器"一词通常用于指远程/云计算机(物理机或虚拟机)以及在该计算机上运行的程序(例如 Uvicorn)。

请记住,当您一般读到"服务器"这个名词时,它可能指的是这两者之一。

当提到远程主机时,通常将其称为服务器 ,但也称为机器 (machine)、VM (虚拟机)、节点。 这些都是指某种类型的远程计算机,通常运行 Linux,您可以在其中运行程序。

安装服务器程序

您可以使用以下命令安装 ASGI 兼容服务器:

UvicornHypercorn

  • Uvicorn,一个快如闪电 ASGI 服务器,基于 uvloop 和 httptools 构建。
bash 复制代码
pip install "uvicorn[standard]"
  • Hypercorn,一个也与 HTTP/2 兼容的 ASGI 服务器。
bash 复制代码
pip install hypercorn

Tip

通过添加standard,Uvicorn 将安装并使用一些推荐的额外依赖项。

其中包括uvloop,它是asyncio的高性能替代品,它提供了巨大的并发性能提升。

运行服务器程序

您可以按照之前教程中的相同方式运行应用程序,但不使用--reload选项,例如:

Uvicorn

bash 复制代码
uvicorn main:app --host 0.0.0.0 --port 80

Hypercorn

bash 复制代码
hypercorn main:app --bind 0.0.0.0:80

Warning

如果您正在使用--reload选项,请记住删除它。

--reload 选项消耗更多资源,并且更不稳定。

它在开发 期间有很大帮助,但您不应该生产环境中使用它。

Hypercorn with Trio

Starlette 和 FastAPI 基于 AnyIO, 所以它们才能同时与 Python 的标准库 asyncioTrio 兼容。

尽管如此,Uvicorn 目前仅与 asyncio 兼容,并且通常使用 uvloop, 它是asyncio的高性能替代品。

但如果你想直接使用Trio ,那么你可以使用Hypercorn,因为它支持它。 ✨

安装具有 Trio 的 Hypercorn

首先,您需要安装具有 Trio 支持的 Hypercorn:

bash 复制代码
pip install "hypercorn[trio]"

Run with Trio

然后你可以传递值trio给命令行选项--worker-class:

bash 复制代码
hypercorn main:app --worker-class trio

这将通过您的应用程序启动 Hypercorn,并使用 Trio 作为后端。

现在您可以在应用程序内部使用 Trio。 或者更好的是,您可以使用 AnyIO,使您的代码与 Trio 和 asyncio 兼容。 🎉

部署概念

这些示例运行服务器程序(例如 Uvicorn),启动单个进程 ,在所有 IP(0.0.0.0)上监听预定义端口(例如80)。

这是基本思路。 但您可能需要处理一些其他事情,例如:

  • 安全性 - HTTPS
  • 启动时运行
  • 重新启动
  • Replication(运行的进程数)
  • 内存
  • 开始前的步骤

在接下来的章节中,我将向您详细介绍每个概念、如何思考它们,以及一些具体示例以及处理它们的策略。 🚀

Server Workers - Gunicorn with Uvicorn

让我们回顾一下之前的部署概念:

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

到目前为止,通过文档中的所有教程,您可能已经在单个进程 上运行了像 Uvicorn 这样的服务器程序

部署应用程序时,您可能希望进行一些进程复制 ,以利用多核并能够处理更多请求。

正如您在上一章有关部署概念中看到的,您可以使用多种策略。

在这里我将向您展示如何将 GunicornUvicorn worker 进程 一起使用。

Info

如果您正在使用容器,例如 Docker 或 Kubernetes,我将在下一章中告诉您更多相关信息:容器中的 FastAPI - Docker

特别是,当在 Kubernetes 上运行时,您可能不想 使用 Gunicorn,而是运行 每个容器一个 Uvicorn 进程,但我将在本章后面告诉您这一点。

Gunicorn with Uvicorn Workers

Gunicorn 主要是一个使用WSGI标准 的应用服务器。 这意味着 Gunicorn 可以为 Flask 和 Django 等应用程序提供服务。 Gunicorn 本身与 FastAPI 不兼容,因为 FastAPI 使用最新的 ASGI 标准

但 Gunicorn 支持充当 进程管理器 并允许用户告诉它要使用哪个特定的 worker类 。 然后 Gunicorn 将使用该类启动一个或多个 worker进程

Uvicorn 有一个 Gunicorn 兼容的worker类。

使用这种组合,Gunicorn 将充当 进程管理器 ,监听 端口IP 。 它会将通信传输 到运行Uvicorn类的worker进程。

然后与Gunicorn兼容的Uvicorn worker类将负责将Gunicorn发送的数据转换为ASGI标准以供FastAPI使用。

安装 Gunicorn 和 Uvicorn

bash 复制代码
pip install "uvicorn[standard]" gunicorn

这将安装带有standard扩展包(以获得高性能)的 Uvicorn 和 Gunicorn。

Run Gunicorn with Uvicorn Workers

接下来你可以通过以下命令运行Gunicorn:

bash 复制代码
gunicorn main:app --workers 4 --worker-class uvicorn.workers.UvicornWorker --bind 0.0.0.0:80

输出:

bash 复制代码
[19499] [INFO] Starting gunicorn 20.1.0
[19499] [INFO] Listening at: http://0.0.0.0:80 (19499)
[19499] [INFO] Using worker: uvicorn.workers.UvicornWorker
[19511] [INFO] Booting worker with pid: 19511
[19513] [INFO] Booting worker with pid: 19513
[19514] [INFO] Booting worker with pid: 19514
[19515] [INFO] Booting worker with pid: 19515
[19511] [INFO] Started server process [19511]
[19511] [INFO] Waiting for application startup.
[19511] [INFO] Application startup complete.
[19513] [INFO] Started server process [19513]
[19513] [INFO] Waiting for application startup.
[19513] [INFO] Application startup complete.
[19514] [INFO] Started server process [19514]
[19514] [INFO] Waiting for application startup.
[19514] [INFO] Application startup complete.
[19515] [INFO] Started server process [19515]
[19515] [INFO] Waiting for application startup.
[19515] [INFO] Application startup complete.

让我们看看每个选项的含义:

  • main:app:这与 Uvicorn 使用的语法相同,main 表示名为"main"的 Python 模块,因此是文件 main.pyappFastAPI 应用程序的变量名称。

    • 你可以想象 main:app 相当于一个 Python import 语句,例如:

      复制代码

      from main import app

    • 因此,main:app 中的冒号相当于 from main import app 中的 Python import 部分。

  • --workers:要使用的worker进程数量,每个进程将运行一个 Uvicorn worker进程,在本例中为 4 个worker进程。

  • --worker-class:在worker进程中使用的与 Gunicorn 兼容的工作类。

    • 这里我们传递了 Gunicorn 可以导入和使用的类:

      复制代码
      import uvicorn.workers.UvicornWorker
  • --bind:这告诉 Gunicorn 要监听的 IP 和端口,使用冒号 (:) 分隔 IP 和端口。

    • 如果您直接运行 Uvicorn,则可以使用--host 0.0.0.0--port 80,而不是--bind 0.0.0.0:80(Gunicorn 选项)。

在输出中,您可以看到它显示了每个进程的 PID(进程 ID)(它只是一个数字)。

你可以看到:

  • Gunicorn 进程管理器 以 PID 19499 开头(在您的情况下,它将是一个不同的数字)。
  • 然后它开始Listening at: http://0.0.0.0:80
  • 然后它检测到它必须使用 uvicorn.workers.UvicornWorker 处的worker类。
  • 然后它启动4个worker ,每个都有自己的PID:19511195131951419515

Gunicorn 还将负责管理死进程重新启动 新进程(如果需要保持worker数量)。 因此,这在一定程度上有助于上面列表中重启的概念。

尽管如此,您可能还希望有一些外部的东西,以确保在必要时重新启动 Gunicorn ,并且在启动时运行它等。

Uvicorn with Workers

Uvicorn 也有一个选项可以启动和运行多个 worker进程

然而,到目前为止,Uvicorn 处理worker进程的能力比 Gunicorn 更有限。 因此,如果您想拥有这个级别(Python 级别)的进程管理器,那么最好尝试使用 Gunicorn 作为进程管理器。

无论如何,您都可以像这样运行它:

bash 复制代码
uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4
复制代码
输出:
bash 复制代码
INFO:     Uvicorn running on http://0.0.0.0:8080 (Press CTRL+C to quit)
INFO:     Started parent process [27365]
INFO:     Started server process [27368]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Started server process [27369]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Started server process [27370]
INFO:     Waiting for application startup.
INFO:     Application startup complete.
INFO:     Started server process [27367]
INFO:     Waiting for application startup.
INFO:     Application startup complete.

这里唯一的新选项是 --workers 告诉 Uvicorn 启动 4 个工作进程。

您还可以看到它显示了每个进程的 PID ,父进程(这是 进程管理器 )的 PID 为27365,每个工作进程的 PID 为:27368273692737027367

部署概念

在这里,您了解了如何使用 Gunicorn (或 Uvicorn)管理 Uvicorn 工作进程并行 应用程序的执行,利用 CPU 中的 多核 ,并 能够满足更多请求

从上面的部署概念列表来看,使用worker主要有助于复制 部分,并对重新启动有一点帮助,但您仍然需要照顾其他部分:

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

容器和 Docker

在关于 容器中的 FastAPI - Docker 的下一章中,我将介绍一些可用于处理其他 部署概念 的策略。

我还将向您展示 官方 Docker 镜像 ,其中包括 Gunicorn 和 Uvicorn worker 以及一些对简单情况有用的默认配置。

在那里,我还将向您展示如何 从头开始构建自己的镜像 以运行单个 Uvicorn 进程(没有 Gunicorn)。 这是一个简单的过程,并且可能是您在使用像 Kubernetes 这样的分布式容器管理系统时想要做的事情。

回顾

您可以使用Gunicorn (或Uvicorn)作为Uvicorn工作进程的进程管理器,以利用多核CPU并行运行多个进程

如果您要设置自己的部署系统,同时自己处理其他部署概念,则可以使用这些工具和想法。

请查看下一章,了解带有容器(例如 Docker 和 Kubernetes)的 FastAPI 。 您将看到这些工具也有简单的方法来解决其他部署概念。 ✨

实践

使用嗯Gunicorn启动Uvicorn workers

安装库

安装fastapi库

bash 复制代码
pip install fastapi[standard]

安装uvicorn和gunicorn库

bash 复制代码
pip install "uvicorn[standard]" gunicorn

启动服务

将下面代码写入myapp.py文件

bash 复制代码
import uvicorn
from fastapi import FastAPI

app = FastAPI()


@app.get("/")
def root():
    a = "a"
    b = "b" + a
    return {"hello world": b}


if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)

接下来你可以通过以下命令运行Gunicorn:

bash 复制代码
gunicorn myapp:app --workers 4 --worker-class uvicorn.workers.UvicornWorker --bind 0.0.0.0:80

注意,因为是绑定80端口,所以需要使用管理员权限,因为可能需要使用sudo命令:

bash 复制代码
sudo gunicorn myapp:app --workers 4 --worker-class uvicorn.workers.UvicornWorker --bind 0.0.0.0:80

启动后显示:

bash 复制代码
[2024-11-14 11:00:26 +0800] [7942] [INFO] Starting gunicorn 23.0.0
[2024-11-14 11:00:26 +0800] [7942] [INFO] Listening at: http://0.0.0.0:80 (7942)
[2024-11-14 11:00:26 +0800] [7942] [INFO] Using worker: uvicorn.workers.UvicornWorker
[2024-11-14 11:00:26 +0800] [7943] [INFO] Booting worker with pid: 7943
[2024-11-14 11:00:26 +0800] [7944] [INFO] Booting worker with pid: 7944
[2024-11-14 11:00:26 +0800] [7945] [INFO] Booting worker with pid: 7945
[2024-11-14 11:00:26 +0800] [7946] [INFO] Booting worker with pid: 7946
[2024-11-14 11:00:27 +0800] [7943] [INFO] Started server process [7943]
[2024-11-14 11:00:27 +0800] [7943] [INFO] Waiting for application startup.
[2024-11-14 11:00:27 +0800] [7943] [INFO] Application startup complete.
[2024-11-14 11:00:27 +0800] [7945] [INFO] Started server process [7945]
[2024-11-14 11:00:27 +0800] [7945] [INFO] Waiting for application startup.
[2024-11-14 11:00:27 +0800] [7945] [INFO] Application startup complete.
[2024-11-14 11:00:27 +0800] [7944] [INFO] Started server process [7944]
[2024-11-14 11:00:27 +0800] [7944] [INFO] Waiting for application startup.
[2024-11-14 11:00:27 +0800] [7944] [INFO] Application startup complete.
[2024-11-14 11:00:27 +0800] [7946] [INFO] Started server process [7946]
[2024-11-14 11:00:27 +0800] [7946] [INFO] Waiting for application startup.
[2024-11-14 11:00:27 +0800] [7946] [INFO] Application startup complete.
[2024-11-14 11:01:22 +0800] [7942] [INFO] Handling signal: winch

现在一套FastAPI的Web服务就启动了。在生产环境中,我们一般外面会再放一层nginx。

nginx配置

使用Gunicorn启动5000和5001端口的Uvicorn workers

bash 复制代码
gunicorn myapp:app --workers 4 --worker-class uvicorn.workers.UvicornWorker --bind 0.0.0.0:5000
gunicorn myapp:app --workers 4 --worker-class uvicorn.workers.UvicornWorker --bind 0.0.0.0:5001

写example.com域名nginx配置

假设域名是example.com, 那么在nginx的原来默认配置文件里,加上一句include example.com.conf:

bash 复制代码
default_type application/octet-stream;

include example.com.conf;

然后写文件example.com.conf文件:

bash 复制代码
upstream example.com{
    ip_hash;
    server 127.0.0.1:5000;
    server 127.0.0.1:5001;
}
 
server {
    listen 80;
 
    # optional ssl configuration
 
    listen 443 ssl;
    ssl_certificate /path/to/ssl/pem_file;
    ssl_certificate_key /path/to/ssl/certificate_key;
 
    # end of optional ssl configuration
 
    server_name  example.com;
 
    access_log  /var/log/nginx/access.log;
 
    location / {
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Host $host:$server_port;
        proxy_set_header X-Forwarded-Port $server_port;
	proxy_set_header Host $host:$server_port;
        client_max_body_size    10m;
        client_body_buffer_size 128k;
        proxy_connect_timeout   60s;
        proxy_send_timeout      90s;
        proxy_read_timeout      90s;
        proxy_buffering         off;
        proxy_temp_file_write_size 64k;
        proxy_pass http://example.com;
        proxy_redirect          off;
    }
}

这样一台真正的WEB服务器就启动完成了。在升级扩充服务器的时候,只需要再换更好的服务器, gunicorn启动更多的进程即可。如果扩充了更多服务器,则可以启动5002、5003等更多的端口,nginx这里只要再加上更多的流量均衡服务器配置即可。

bash 复制代码
upstream example.com{
    ip_hash;
    server 127.0.0.1:5000;
    server 127.0.0.1:5001;
    server 192.168.1.101:5002;
    server 10.0.0.12:5003;
}
相关推荐
sakoba19 分钟前
Docker学习其二(容器卷,Docker网络,Compose)
运维·网络·学习·docker·容器·基础
A了LONE42 分钟前
cv弹窗,退款确认弹窗
java·服务器·前端
来自于狂人1 小时前
CentOS 镜像源配置与 EOL 后的应对策略
linux·运维·centos
吉凶以情迁2 小时前
window服务相关问题探索 go语言服务开发探索调试
linux·服务器·开发语言·网络·golang
卍郝凝卍2 小时前
云上服务器常见的存储方式和类型
大数据·服务器·数据库
柏木乃一3 小时前
Linux初步认识与指令与权限
linux·运维·服务器·shell·权限
189228048613 小时前
NX947NX955美光固态闪存NX962NX966
大数据·服务器·网络·人工智能·科技
Joemt4 小时前
ubuntu源码编译安装cmake高版本、pybind11安装、crow使用
linux·运维·ubuntu
真智AI4 小时前
打破数据质量瓶颈:用n8n实现30秒专业数据质量报告自动化
大数据·运维·人工智能·python·自动化