三周精通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;
}
相关推荐
运维&陈同学2 小时前
【Elasticsearch05】企业级日志分析系统ELK之集群工作原理
运维·开发语言·后端·python·elasticsearch·自动化·jenkins·哈希算法
ZVAyIVqt0UFji5 小时前
go-zero负载均衡实现原理
运维·开发语言·后端·golang·负载均衡
小屁不止是运维7 小时前
麒麟操作系统服务架构保姆级教程(二)ssh远程连接
linux·运维·服务器·学习·架构·ssh
gavin_gxh9 小时前
SAP PP ECN CSAP_MAT_BOM_MAINTAIN
运维·经验分享·其他
黑客K-ing9 小时前
网络安全防范
linux·服务器·web安全
老大白菜10 小时前
FastAPI vs Go 性能对比分析
开发语言·golang·fastapi
这题怎么做?!?10 小时前
ARP协议及其具体过程
运维·服务器·网络
Lay_鑫辰10 小时前
禾川HCQ1系列PAC脉冲控制步进驱动器
运维·人工智能·单片机·嵌入式硬件·自动化
卡卡大怪兽10 小时前
fastAPI接口的请求与响应——基础
服务器·网络·fastapi
路飞雪吖~10 小时前
【Linux】进程控制
linux·运维·服务器