Uvicorn 从入门到生产,手把手教你玩转Python异步服务器

2 阅读7分钟

一篇真正“保姆级”的Uvicorn操作指南,涵盖从零基础安装、各种启动方式、后台运行、与框架结合、生产环境部署、性能优化、常见问题排错等,一本随时可查的手册。

后台启动、多进程、Gunicorn+Uvicorn、systemd守护、Docker部署… 你想要的全都有

很多 Python 开发者对异步服务器的认知停留在“很厉害但不会用”。
今天这篇文章,我将用最详细的步骤,带你彻底搞懂 Uvicorn——这个让 Python 接口性能起飞的核心工具。

本文涵盖:

  • ✅ 什么是 Uvicorn,为什么它这么快
  • ✅ 安装与基础启动(包括热重载)
  • ✅ 后台启动的三种方式(nohup、screen、systemd)
  • ✅ 与 FastAPI / Starlette 结合的最佳实践
  • ✅ 生产环境部署:Gunicorn + Uvicorn、多进程、日志配置
  • ✅ Docker 容器化部署
  • ✅ 性能调优与常见问题排查

建议收藏,以后无论开发还是部署,随时可以查阅。

01 认识 Uvicorn:Python 异步服务器界的“闪电侠”

1.1 Uvicorn 是什么?

Uvicorn 是一个基于 ASGI(异步服务器网关接口) 的高性能 Python Web 服务器。
它使用 uvloop(基于 libuv 的事件循环)和 httptools(Node.js 同款 HTTP 解析器),性能远超传统的 WSGI 服务器(如 Gunicorn 的同步工作模式)。

核心优势:

  • 异步支持:可以处理 WebSocket、HTTP/2 等长连接,并发能力极强。
  • 闪电速度:基准测试中,Uvicorn 是 Python 最快的服务器之一。
  • 生态融合:是 FastAPI、Starlette 等现代异步框架的官方推荐服务器。

1.2 同步 vs 异步,一张图看懂

模式处理方式并发能力适用场景
WSGI(同步)一个请求占一个线程,等待 I/O 时线程阻塞受线程数限制,高并发下资源消耗大简单 CRUD 应用
ASGI(异步)一个线程可处理多个请求,I/O 等待时切换任务极高,单线程可处理成千上万并发高并发 API、WebSocket、实时服务

02 安装 Uvicorn

2.1 基础安装

pip install uvicorn

2.2 安装标准版(推荐)

标准版包含了 uvloophttptools,性能更佳:

pip install 'uvicorn[standard]'

2.3 验证安装

uvicorn --version

输出类似 uvicorn, version 0.24.0 即成功。

03 第一个 Uvicorn 应用

3.1 最简 ASGI 应用

新建文件 app.py

# app.py
async def app(scope, receive, send):
    assert scope['type'] == 'http'
    await send({
        'type': 'http.response.start',
        'status': 200,
        'headers': [(b'content-type', b'text/plain')],
    })
    await send({
        'type': 'http.response.body',
        'body': b'Hello, Uvicorn!',
    })

3.2 启动服务

uvicorn app:app

参数说明:app:app 表示 文件名:应用实例名
访问 http://127.0.0.1:8000 即可看到输出。

3.3 开发模式(热重载)

uvicorn app:app --reload

代码修改后自动重启,极大提升开发效率。

3.4 指定端口和主机

uvicorn app:app --host 0.0.0.0 --port 8080

0.0.0.0 表示监听所有网络接口,允许外部访问。

04 后台启动 Uvicorn(三种方式)

生产环境中,我们通常需要让 Uvicorn 在后台运行,即使关闭终端也不中断。这里提供三种常用方法。

4.1 方式一:nohup(最简单)

nohup uvicorn app:app --host 0.0.0.0 --port 8000 > uvicorn.log 2>&1 &
  • nohup:忽略挂断信号
  • > uvicorn.log:标准输出重定向到日志文件
  • 2>&1:错误输出也重定向到同一文件
  • &:后台运行

查看进程:

ps aux | grep uvicorn

停止进程:

kill <PID>

4.2 方式二:使用 screen(可随时恢复)

# 安装 screen(如果未安装)
sudo apt install screen   # Ubuntu/Debian
# 或 yum install screen   # CentOS

# 创建一个名为 uvicorn 的会话
screen -S uvicorn

# 在 screen 中启动服务
uvicorn app:app --host 0.0.0.0 --port 8000

# 按 Ctrl+A 再按 D 分离会话(detach)

恢复会话:

screen -r uvicorn

停止:进入会话后按 Ctrl+C 停止进程,然后 exit 退出会话。

4.3 方式三:systemd 服务(生产级推荐)

创建 systemd 服务文件 /etc/systemd/system/uvicorn.service

[Unit]
Description=Uvicorn ASGI server
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/path/to/your/app
Environment="PATH=/path/to/venv/bin"
ExecStart=/path/to/venv/bin/uvicorn app:app --host 0.0.0.0 --port 8000
Restart=always

[Install]
WantedBy=multi-user.target
  • User/Group:指定运行的用户组,不要用 root
  • WorkingDirectory:项目根目录
  • Environment:虚拟环境路径
  • Restart=always:进程退出后自动重启

启用并启动服务:

sudo systemctl daemon-reload
sudo systemctl enable uvicorn
sudo systemctl start uvicorn

查看状态:

sudo systemctl status uvicorn

查看日志:

sudo journalctl -u uvicorn -f

05 与 FastAPI / Starlette 结合

实际开发中,我们几乎不会直接写 ASGI 应用,而是使用 FastAPI 或 Starlette 框架。

5.1 安装 FastAPI

pip install fastapi

5.2 编写 FastAPI 应用

新建 main.py

from fastapi import FastAPI
import uvicorn

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Hello Uvicorn"}

@app.get("/items/{item_id}")
async def read_item(item_id: int, q: str = None):
    return {"item_id": item_id, "q": q}

# 脚本直接运行
if __name__ == "__main__":
    uvicorn.run(
        "main:app",
        host="0.0.0.0",
        port=8000,
        reload=True,          # 开发模式
        log_level="debug"
    )

5.3 启动

命令行方式:

uvicorn main:app --reload

脚本方式:

python main.py

06 生产环境部署(Gunicorn + Uvicorn)

在生产环境,我们通常使用 Gunicorn 作为进程管理器,通过 uvicorn.workers.UvicornWorker 来运行 Uvicorn,这样既能利用 Gunicorn 的健壮进程管理,又能享受 Uvicorn 的异步性能。

6.1 安装依赖

pip install gunicorn uvicorn[standard]

6.2 启动命令

gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000
  • -w 4:工作进程数,通常设为 CPU 核心数 × 2 + 1
  • -k uvicorn.workers.UvicornWorker:指定使用 Uvicorn 的工作类
  • --bind:绑定地址和端口

6.3 配合 systemd

创建服务文件 /etc/systemd/system/gunicorn.service

[Unit]
Description=Gunicorn + Uvicorn
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/path/to/your/app
Environment="PATH=/path/to/venv/bin"
ExecStart=/path/to/venv/bin/gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000
Restart=always

[Install]
WantedBy=multi-user.target

启动同之前 systemd 操作。

07 日志配置

默认日志比较简单,生产环境需要更详细的日志(访问日志、错误日志等)。

7.1 命令行配置

uvicorn main:app --log-level info --access-log
  • --log-level:可选 debuginfowarningerrorcritical
  • --access-log:开启访问日志

7.2 通过配置文件

创建 log_config.yaml

version: 1
disable_existing_loggers: False
formatters:
  default:
    format: "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
  access:
    format: "%(asctime)s - %(levelname)s - %(message)s"
handlers:
  console:
    class: logging.StreamHandler
    formatter: default
    stream: ext://sys.stdout
  access_console:
    class: logging.StreamHandler
    formatter: access
    stream: ext://sys.stdout
loggers:
  uvicorn:
    handlers: [console]
    level: INFO
  uvicorn.error:
    level: INFO
  uvicorn.access:
    handlers: [access_console]
    level: INFO
    propagate: False

启动时指定:

uvicorn main:app --log-config log_config.yaml

08 Docker 部署 Uvicorn

8.1 编写 Dockerfile

FROM python:3.11-slim

WORKDIR /app

# 安装依赖
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 复制代码
COPY . .

# 暴露端口
EXPOSE 8000

# 启动命令(注意使用 CMD 而不是 RUN)
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

8.2 requirements.txt

fastapi
uvicorn[standard]

8.3 构建并运行

# 构建镜像
docker build -t my-uvicorn-app .

# 运行容器(前台)
docker run -p 8000:8000 my-uvicorn-app

# 后台运行
docker run -d -p 8000:8000 --name myapp my-uvicorn-app

8.4 使用 docker-compose(生产级)

创建 docker-compose.yml

version: '3.8'
services:
  web:
    build: .
    ports:
      - "8000:8000"
    environment:
      - ENVIRONMENT=production
    restart: always
    command: uvicorn main:app --host 0.0.0.0 --port 8000

启动:

docker-compose up -d

09 性能调优与注意事项

9.1 工作进程数

对于 Gunicorn+Uvicorn,-w 参数建议为 (2 * CPU核心数) + 1
如果使用 Uvicorn 直接多进程(--workers),同样遵循此规则。

9.2 内存与连接限制

Uvicorn 默认不限制并发连接数,在高流量场景下建议设置:

uvicorn main:app --limit-concurrency 1000

每个工作进程的最大并发连接数。

9.3 禁用自动重载(生产环境)

--reload 会降低性能,生产环境必须移除。

9.4 使用 Nginx 作为反向代理

Nginx 可以处理静态文件、负载均衡和 SSL 终结。
示例 Nginx 配置:

server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

9.5 避免在异步代码中使用阻塞调用

如果在异步视图函数中使用了 time.sleep()requests.get() 等阻塞操作,会阻塞事件循环。应使用 asyncio.sleep()httpx.AsyncClient

10 常见问题排查

Q1:端口被占用

错误信息:[Errno 98] Address already in use
解决:换端口,或 kill 占用端口的进程:

sudo lsof -i :8000
sudo kill -9 <PID>

Q2:应用无法访问

  • 检查防火墙:sudo ufw allow 8000
  • 确保绑定 0.0.0.0 而不是 127.0.0.1

Q3:日志没有输出

  • 确认 --log-level 设置正确
  • 检查日志配置文件路径是否正确

Q4:内存不断增长

  • 可能是代码中存在内存泄漏(例如全局变量不断累积)

  • 使用 --limit-max-requests 定期重启工作进程:

    uvicorn main:app --limit-max-requests 1000
    

Q5:WebSocket 连接失败

  • 确保 Nginx 配置支持 WebSocket:

    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    

结语

从零基础到生产部署,Uvicorn 的每一个细节我都尽力写全了。
无论你是个人开发者,还是在团队中负责后端架构,这份手册都能帮你少踩无数坑。

如果你觉得这篇文章对你有帮助,欢迎点赞、在看、转发,让更多人用上 Python 的异步力量。
如果还有未覆盖到的场景,欢迎评论区留言,我会持续更新。