FastAPI真香?一个Java转Python小厂后端的实战手记

502守望者
2025-12-24 04:22
阅读 372

去年双11前夜,我们老板突然在钉钉群里@我:“小王,下个月我们要上线一个数据聚合平台,你用Python搞个后端,别整那些花里胡哨的,快点就行。”我盯着消息愣了三秒——我可是写了五年Java的“老码农”,Spring Boot 都能闭眼写,现在让我切 Python?而且 deadline 只有四周?

更离谱的是,产品经理还加了一句:“对了,要支持爬虫结果的实时查询和导出。”我差点把咖啡杯捏碎。但没办法,小厂没人权,只能硬着头皮上。

一番调研后,我放弃了 Django(太重)和 Flask(异步支持弱),最终锁定了 FastAPI。没想到,这一试,还真有点上头。


为啥选 FastAPI?不只是因为“快”

说实话,一开始我对 Python Web 框架的印象还停留在“玩具级”——直到看到 FastAPI 的官方 benchmark。它基于 Starlette(ASGI)和 Pydantic,天生支持异步,性能直逼 Go 和 Node.js,甚至在某些场景下比我们老项目里的 Spring Boot 还快(别告诉 Java 组的老李,他正为 GC 调优掉头发)。

更重要的是,自动生成 OpenAPI 文档这个功能,直接拯救了我和前端同事的关系。以前每次改接口都要手动写 Swagger 注解,现在只要定义好 Pydantic 模型,文档自动同步,前端再也不用追着我问“字段是不是 string 啊?”。


爬虫数据接入:从阻塞到异步的血泪教训

我们的核心需求之一是接入内部爬虫系统抓取的商品价格数据。最初我图省事,直接在接口里调用 requests.get()

@app.get("/price/{item_id}")
def get_price(item_id: str):
    resp = requests.get(f"http://crawler-service/api/price/{item_id}")
    return resp.json()

结果压力一上来,整个服务直接卡死。为啥?requests 是同步阻塞的!一个请求卡住,其他全排队。这在 Java 里我们早用 CompletableFuture 或 WebFlux 解决了,但在 Python 世界,得换 async。

于是赶紧重构,换成 httpx(支持 async):

import httpx

@app.get("/price/{item_id}")
async def get_price(item_id: str):
    async with httpx.AsyncClient() as client:
        resp = await client.get(f"http://crawler-service/api/price/{item_id}")
        return resp.json()

加上 async/await 后,单机 QPS 从 80 直接飙到 1200+(本地压测数据)。小厂服务器就两台,这波优化省了至少一台机器的钱——老板看我的眼神都温柔了。


模型验证:Pydantic 是真的强

以前在 Java 里,校验参数得靠 Hibernate Validator,写一堆 @NotNull@Min(0),烦死了。FastAPI 用 Pydantic 定义模型,验证逻辑天然集成:

from pydantic import BaseModel, validator

class PriceQuery(BaseModel):
    item_ids: List[str]
    source: str = "default"

    @validator("item_ids")
    def check_item_ids(cls, v):
        if len(v) > 100:
            raise ValueError("最多查询100个商品")
        return v

然后在接口里直接用:

@app.post("/batch_price")
async def batch_price(query: PriceQuery):
    # 自动校验 + 类型转换
    ...

非法请求直接返回 422 错误,连 try-catch 都省了。测试同学第一次跑自动化就过了,感动得请我喝了杯瑞幸。


部署上线:小厂运维的“极限操作”

我们没 K8s,没 Helm,只有两台 CentOS 物理机。FastAPI 推荐用 Uvicorn + Gunicorn 部署:

gunicorn -k uvicorn.workers.UvicornWorker main:app -w 4 -b 0.0.0.0:8000 --timeout 120

但这里有个坑:默认 worker 数是 CPU 核数。我们服务器是 8 核,但跑着 MySQL、Redis 和爬虫调度器,实际给 FastAPI 分 4 个 worker 刚好。多了反而因上下文切换拖慢性能。

另外,超时时间一定要调大!因为爬虫服务偶尔会慢(网络抖动 or 对方反爬),默认 30 秒不够用。线上第一次挂就是因为 timeout,半夜被 PagerDuty 叫醒,真是栓Q。


性能对比:FastAPI vs 我们的 Java 服务

出于好奇,我拿同一个接口(查商品价格)做了对比测试(4核8G,同机房):

框架 平均延迟 (ms) P99 延迟 (ms) 最大 QPS
Spring Boot 2.7 45 180 950
FastAPI + Uvicorn 28 110 1320

当然,Java 服务做了很多业务逻辑(权限校验、日志审计等),而 FastAPI 版本相对轻量。但即便如此,FastAPI 在 I/O 密集型场景(比如调爬虫、查 DB)的优势非常明显。


给 Java 转 Python 后端的建议

如果你像我一样,是从 Java 转过来的,记住几点:

  1. 别用同步库:任何可能阻塞的操作(HTTP、DB、文件读写)都找 async 替代品。比如数据库用 asyncpgSQLAlchemy 1.4+ async
  2. 类型注解不是可选项:FastAPI 重度依赖类型提示做序列化和文档生成,不写等于自断一臂。
  3. 别迷信“Python 慢”:在 I/O 密集型服务中,Python + async 的吞吐完全不输 Java,甚至更省资源。

尾声:通勤路上的思考

现在每天坐地铁回家(北京回龙观→国贸,1小时起步),我都会想:技术栈真的有高低吗?FastAPI 让我两周搞定原本要一个月的活,还顺手把爬虫数据 API 化了,测试覆盖率从 30% 提到 80%。而隔壁组还在为 Spring Cloud Config 的刷新问题吵架。

小厂资源有限,能快速交付、稳定运行、便于维护的技术,就是好技术。FastAPI 不是银弹,但它确实让我这个“Java 老兵”重新爱上了写后端。

下次如果产品再说“加个简单接口”,我可能会笑着回答:“行,今晚就能上线——只要别再提爬虫。”

(完)

附:我的 VSCode 插件清单(Python 开发必备)

  • Python(官方)
  • Pylance(智能提示)
  • autoDocstring(自动生成文档字符串)
  • REST Client(直接在编辑器里测 API)
  • Error Lens(错误高亮,救我狗命)

装完这些,写 FastAPI 真的像开了挂。

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝