FastAPI 入门:一位架构师的后端开发实战笔记

雪崩预防员
2025-06-28 13:34
阅读 1506

开篇 · 为什么我要写这篇文章

开篇 · 为什么我要写这篇文章

我是一名后端架构师,过去几年一直在使用 Python 构建各类中小型服务。最初用的是 Flask,后来也尝试过 Tornado、Django REST Framework,直到去年在一个新项目中第一次引入了 FastAPI

说实话,第一眼看到 FastAPI 的时候并没有太在意,觉得不过又是一个“轮子”。但随着项目的推进,它带来的生产力提升让我彻底改观。这次我想以一个开发者兼架构师的身份,把我在实际项目中使用 FastAPI 的经验分享出来,希望能帮到那些刚准备入门或还在犹豫要不要尝试 FastAPI 的朋友。


项目背景 · 新产品上线倒计时

项目背景 · 新产品上线倒计时

去年公司决定启动一个新产品线,目标是为内部系统构建一套统一的数据接口服务,供多个前端应用(Web + App)调用。这个服务要具备高并发支撑能力,同时要求开发效率快、代码结构清晰、后期易于扩展。

当时我们在技术选型上讨论了很久,最后敲定了:

  • 后端框架:FastAPI
  • 数据库:PostgreSQL
  • ORM:SQLAlchemy(配合 asyncpg)
  • 身份认证:JWT + OAuth2
  • 部署方式:Docker + Gunicorn + Uvicorn Worker
  • 日志监控:ELK + Sentry
  • 测试框架:pytest

选择 FastAPI 主要有几个原因:

  1. 支持异步编程模型,这对处理高并发请求非常关键;
  2. 自带类型提示和 OpenAPI 文档生成,对前后端协作非常友好;
  3. 社区活跃度高,生态逐渐完善;
  4. 我们希望用现代的语法风格来构建项目,减少 boilerplate 代码。

初期挑战 · 帧率不稳的开发节奏

初期挑战 · 帧率不稳的开发节奏

缓存策略对比-2

虽然 FastAPI 官方文档很全,但真正上手的时候还是遇到了一些坑,特别是在早期架构设计阶段。

问题一:如何组织项目结构?

在初期,我们按照传统的 Flask 风格来组织代码——main.py 里直接写路由,逻辑函数分散在各个模块里。结果没多久就发现:

  • 路由混乱,查找接口难;
  • 同样功能的视图分散在不同文件里;
  • 模块依赖复杂,测试困难;
  • 无法很好地支持依赖注入和中间件复用。

解决方法:采用模块化+分层架构

我们参考了 Django 和 NestJS 的结构理念,重新调整了项目结构如下:

app/
├── main.py
├── config/                  # 配置文件
├── core/                    # 核心逻辑(权限、日志、异常处理)
├── models/                  # SQLAlchemy Models
├── schemas/                 # Pydantic Schemas
├── services/                # 业务逻辑封装
├── routers/                 # 每个模块一个 router 文件
├── repositories/            # 数据操作封装
└── utils/                   # 工具类函数

通过这种结构,可以做到:

  • 接口职责分明;
  • 业务逻辑与数据访问分离;
  • 更容易做单元测试;
  • 中间件、依赖项便于复用。

问题二:数据库查询性能差,响应慢

我们的 API 会频繁访问 PostgreSQL,某些聚合查询响应时间超过了预期,甚至在压力测试时出现了阻塞现象。

解决方案一:引入异步数据库连接

我们使用 asyncpg 作为 Postgres 的驱动,并将 SQLAlchemy 设置为异步模式(基于 SQLAlchemy 2.0 + async session)。这样就能在 FastAPI 的异步路由中使用 await 查询数据库了:

from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
from sqlalchemy.orm import sessionmaker

engine = create_async_engine(DATABASE_URL)
async_session = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)

async def get_db():
    async with async_session() as session:
        yield session

在路由中这样调用:

@app.get("/users/{user_id}")
async def get_user(user_id: int, db: AsyncSession = Depends(get_db)):
    result = await db.execute(select(User).where(User.id == user_id))
    user = result.scalars().first()
    return user

缓存策略对比-1

这一步优化后,平均响应时间降低了 30%以上。

解决方案二:加入缓存机制

对于一些低频更新但高频读取的数据(如配置表、状态字典等),我们引入了 Redis 缓存。使用的是 redis-py 的异步客户端,并结合 FastAPI 的依赖注入:

from fastapi import Depends
from redis import asyncio as aioredis

def get_redis():
    return aioredis.from_url("redis://localhost")

在需要缓存的方法中注入 redis 实例即可实现快速读取。


持久化设计 · 真实场景中的数据库考量

持久化设计 · 真实场景中的数据库考量

FastAPI 并没有自带 ORM,所以我们选择了 SQLAlchemy(异步版)。下面是一些我们在实际使用中的实践经验:

1. 明确 Schema 分层结构

我们通常定义两套 Schema:

  • Request Schema(Pydantic Model):用于请求参数校验;
  • Response Schema(Pydantic Model):用于控制返回字段;
  • Database Model(SQLAlchemy ORM Class):映射到数据库。

例如:

class UserCreate(BaseModel):
    name: str
    email: EmailStr

class UserOut(BaseModel):
    id: int
    name: str
    email: EmailStr
    created_at: datetime

class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True)
    name = Column(String)
    email = Column(String)
    created_at = Column(DateTime)

这样做有几个好处:

  • 隔离了数据库模型和 API 模型,解耦更彻底;
  • 提升可维护性(改数据库字段不影响外部 API);
  • 更方便进行数据脱敏、权限控制等操作。

2. 复杂查询尽量交给数据库处理

有些同事习惯在 Python 层做一些 join 或 aggregate 操作,但这样很容易引起性能问题。我们在 Review Code 时强调:

“能写成 SQL 的,不要在 Python 里 filter。”

我们鼓励团队优先编写高效 SQL,并利用 SQLAlchemy 的表达式构造查询。比如一个复杂的多表查询:

query = select(Order).join(Order.user).where(User.status == 'active')

这种方式不仅性能好,还更容易被数据库优化器识别。


安全性与接口设计 · 保护你的每一寸边界

FastAPI 在安全方面的设计非常出色,提供了很多开箱即用的支持。我们主要做了以下几件事:

1. 强制输入校验

借助 Pydantic,我们在所有入口都加上了类型和格式检查:

class CreateUserRequest(BaseModel):
    name: str
    email: EmailStr
    age: Optional[int] = Field(None, ge=0, le=150)

FastAPI 会自动进行校验并返回错误码,极大地提升了安全性。

2. 权限控制体系

我们采用了 JWT Token + OAuth2 的方案:

  • 用户登录后获取 Token;
  • 每个接口根据角色判断是否有权限;
  • Token 使用加密签名防止篡改。

这部分我们用了 python-jose 库来做 JWT 加解密,结合 FastAPI 的依赖注入机制实现:

from fastapi.security import OAuth2PasswordBearer

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

async def get_current_user(token: str = Depends(oauth2_scheme)):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        user_id: int = payload.get("sub")
        if user_id is None:
            raise credentials_exception
        token_data = TokenData(user_id=user_id)
    except PyJWTError:
        raise credentials_exception
    user = get_user_by_id(db, user_id=token_data.user_id)
    if user is None:
        raise credentials_exception
    return user

再在接口中这样使用:

@app.get("/me")
async def read_users_me(current_user: User = Depends(get_current_user)):
    return current_user

上线后的表现与运维经验

我们这套服务最终部署在 AWS ECS 上,使用 Docker + Gunicorn + Uvicorn Worker 组合,共启用了 4 个 worker 进程(每个 worker 使用异步事件循环)。

性能表现

在压测过程中,单节点(t3.medium)QPS 可达 3k~4k,TP99 控制在 200ms 以内。对比之前使用 Flask 的项目(同样部署配置下),性能提升了约 2.8 倍。

日常运维

我们使用了以下几个关键工具来保障稳定性:

  • Sentry:捕获未处理异常,追踪堆栈;
  • Prometheus + Grafana:监控 QPS、延迟、错误率等指标;
  • ELK Stack:统一日志管理;
  • Fluent Bit:收集容器日志转发至 Kafka;
  • 定期 DBVacuum:避免 Postgres 表膨胀。

特别要注意的一点是:FastAPI 默认的 debug 模式要关闭生产环境,否则容易暴露敏感信息。

另外,在部署时如果发现接口响应变慢,可以先排查是否因为同步 IO 阻塞了 event loop,特别是使用第三方库时要注意是否支持 async。


总结 · FastAPI 究竟适合什么项目?

FastAPI 是一种“现代化”的 Web 框架,它的设计理念非常贴近现代软件工程的最佳实践:

  • 类型安全;
  • 异步编程;
  • 快速原型;
  • 易于维护;
  • 自动生成 OpenAPI 文档;
  • 社区活跃,生态丰富。

如果你的项目满足以下条件之一,FastAPI 都值得尝试:

  • 需要高性能异步处理(高并发场景);
  • 团队注重类型安全(Type Hints 成员较多);
  • 希望建立良好的 API 文档规范;
  • 不想重复造轮子(自动生成接口文档、验证逻辑);
  • 想提升后端开发效率。

当然,也不是说 FastAPI 就完美无缺。对于超大规模系统来说,Python + FastAPI 可能还不够硬核;但对于中小型系统、创业团队、微服务场景,它确实是一个非常好的选择。


给新手的一些建议

作为一个从其他框架转过来的老兵,我想给刚开始学 FastAPI 的朋友几点建议:

  1. 别一开始就追求速度:先把结构理清楚,后面写起来才顺;
  2. 认真对待类型注解:这是 FastAPI 的灵魂所在;
  3. 多用依赖注入:这是 FastAPI 最强大的设计之一;
  4. 重视测试:尤其是异步函数测试,一定要熟练掌握 pytest-asyncio;
  5. 合理设计数据库模型:避免反范式设计导致后期难以维护;
  6. 善用官方文档:虽然英文为主,但结构清晰、示例丰富;
  7. 参与社区学习交流:FastAPI 的中文资料还不算特别多,多看看 GitHub Issues、StackOverflow 上的真实案例很有帮助。

最后一句

FastAPI 真的让我在项目中感受到了“开发幸福感”,那种接口定义完就能跑通、文档自动生成、逻辑清晰可维护的感觉,是你亲手试过之后才会理解的。

如果你正准备开始一个后端项目,或者想换换口味体验一下新东西,不妨试试 FastAPI。它不会让你失望。

祝大家 coding 快乐! 🚀

评论 0

最热最新
暂无评论
雪崩预防员Lv.1
0
影响力
0
文章
0
粉丝