当前位置: 首页 > news >正文

FastAPI 性能扩展 Redis 缓存、Celery 异步任务与容器部署

任务详情接口被频繁刷新时,数据库其实在重复回答同一个问题。把所有耗时工作都塞进 FastAPI 请求里也会出事,用户点一次导出,浏览器就一直转圈。这一篇给任务 API 加两条分流,Redis 负责短暂记忆,Celery 负责把耗时工作交给 worker。

配套代码已经放在 fastapi-task-api,文章中的完整实现以main分支为准。

Redis 不是越早接越好

缓存会带来失效问题,所以项目只缓存一个最容易定义边界的对象,任务详情。列表带分页和筛选条件,缓存键会迅速膨胀,先不碰它。

defcache_key(owner_id:uuid.UUID,task_id:uuid.UUID)->str:returnf"task:{owner_id}:{task_id}"@router.get("/{task_id}",response_model=TaskRead)asyncdefread_task(task_id:uuid.UUID,session=Depends(get_db_session),redis=Depends(get_redis)):key=cache_key(current_user.id,task_id)cached=awaitredis.get(key)ifcached:returnTaskRead.model_validate_json(cached)task=awaitowned_task(session,task_id,current_user.id)result=TaskRead.model_validate(task)awaitredis.set(key,result.model_dump_json(),ex=300)# 缓存五分钟returnresult

键里必须有用户 ID。即使任务 UUID 已经很难猜,隔离条件也不能依赖运气。更新和删除任务后立刻删键,下一次读取自动回源数据库。创建接口没有对应缓存,因此不需要做任何操作。

awaitsession.commit()awaitredis.delete(cache_key(current_user.id,task_id))

缓存的正确性来自失效策略,不来自缓存命中率。这就是为什么这里只放详情,不拿 Redis 去替代数据库。

BackgroundTasks 和 Celery 各干什么

FastAPI 的BackgroundTasks适合短小、允许跟 Web 进程同生共死的事情,例如记录一条审计日志。它不需要单独部署 worker。

Celery 则把任务投给 broker,由独立 worker 消费。导出 CSV、批量发邮件、调用慢速第三方接口都更适合这个路径。worker 可独立扩容,也能配置重试。任务 API 用 Redis 同时充当 broker 和结果后端。

场景选择
写一条轻量审计日志BackgroundTasks
导出任务 CSVCelery
批量处理、失败重试Celery
需要立即返回计算结果普通async接口

把导出变成异步工作

提交导出时,接口立即返回202task_id。客户端再用这个 ID 查询状态。为了避免任何登录用户猜到 ID 后读取结果,项目把任务所有者短暂记录在 Redis 里。

@router.post("/exports/tasks",status_code=202)asyncdefqueue_export(redis=Depends(get_redis),current_user=Depends(get_current_user)):result=export_user_tasks.delay(str(current_user.id))awaitredis.set(f"export-owner:{result.id}",str(current_user.id),ex=3600)return{"task_id":result.id,"status":"PENDING"}

worker 内部重新开数据库会话,读取该用户的任务,再生成 UTF-8 CSV 字符串。不要把 HTTP 请求里的 SQLAlchemy session 传给 Celery,它无法跨进程序列化。

@celery_app.task(bind=True,autoretry_for=(Exception,),retry_backoff=True,max_retries=3)defexport_user_tasks(self,user_id:str)->str:returnasyncio.run(build_csv(uuid.UUID(user_id)))

autoretry_for只适合可重试的临时失败,例如数据库短暂不可用。CSV 格式错误或无效用户这类确定性错误,重试三次也不会变好。大文件也不该塞进结果后端,真实项目应该上传对象存储,结果只返回下载地址。

Celery WorkerRedisFastAPIClientCelery WorkerRedisFastAPIClientPOST 导出投递任务和保存所有者202 task_idworker 消费任务写入结果状态GET 导出状态PENDING 或 SUCCESS

用 Docker Compose 把四个服务放到一起

本地起 API 还不难,真正容易遗漏的是 worker、PostgreSQL 和 Redis 的连接配置。docker-compose.yml定义四个服务,PostgreSQL 和 Redis 有健康检查,API 等数据库健康后先执行alembic upgrade head再启动。

Copy-Item.env.example.env docker compose up--build

.env中的DATABASE_URL主机名是postgresREDIS_URL主机名是redis,它们来自 Compose 服务名。启动成功后打开/docs,先注册、登录,复制 Bearer 令牌,再创建任务和提交导出。

这一套配置不是高可用方案。生产环境还要接日志、指标、备份、密钥管理和外部对象存储。但 API、数据库、缓存和 worker 已经各自有了明确位置,后续扩展不会全挤在 Web 进程里。

本篇收口

  • Redis 只缓存任务详情,更新和删除时精确失效
  • Celery 处理可延迟的 CSV 导出,并返回可查询的任务 ID
  • 导出任务的所有者映射阻止其他用户读取结果
  • Docker Compose 统一启动 API、PostgreSQL、Redis 与 worker
http://www.jsqmd.com/news/1356535/

相关文章:

  • AI Agent的“缰绳”:高效实现Agent Harness工程化
  • 动物横穿马路数据集969张VOC+YOLO格式
  • 洛谷P8816 [CSP-J 2022] 上升点列一题的题解
  • 脊髓横断面图像处理实战:从解剖结构到Python代码实现
  • 2026年8月呼和浩特市移动1000M宽带怎么选不踩坑 - 找卡家园
  • 拯救者工具箱终极指南:如何解锁联想游戏本隐藏性能与电池寿命
  • OpenRGB终极指南:一个免费软件统一控制所有RGB设备,告别厂商软件混乱
  • 深入解析-O3优化:从-O2升级的实战指南与性能陷阱
  • 第一次混沌演练把生产打挂 23 分钟:稳态定错、半径失控,4 个换来的规矩
  • 实时 AI 语伴如何切换大模型而不重做语音链路:统一适配、灰度路由与故障回退实战
  • 山海万灵 HarmonyOS 文化知识实战(19):MySQL、Redis、OpenSearch 与 MinIO 的内容发布同步
  • 基于User-Agent识别的Markdown数据接口爬虫实践与合规指南
  • Unity开发中Cursor编辑器代码提示失效的通用解决方案
  • 【单片机毕业设计推荐】基于 STM32 的室内环境空气质量监测与智能通风控制系统设计,基于 STM32 的多参数室内环境监测及联动报警系统设计(010106)
  • Python文本特征分析:从NLP基础到笔迹鉴定辅助系统构建
  • Claude Opus 4.7国内稳定接入全攻略:API调用、成本控制与IDE插件实战
  • VisualCppRedist AIO:一站式解决Windows C++运行库依赖的终极方案
  • 从明文泄漏到高价值漏洞的实战侦察与防御
  • AMD Ryzen处理器终极优化指南:RyzenAdj免费工具完整教程
  • 中文数字转阿拉伯数字:从“第一千三百六十四弹”解析到工程实践
  • 我在CSDN踩过的10个技术坑:血泪经验与避坑指南
  • A2A-Agent安全实战:从API Key到mTLS的认证鉴权指南
  • 本地部署AI图像生成模型:从Stable Diffusion环境搭建到API集成实践
  • 2026年8月杭州市移动500M宽带怎么选_新手避坑指南 - 找卡家园
  • ​现如今市场行情下:性价比高的证书有哪些?
  • Xss-labs-master 第10关
  • 如何用MediaCrawler一站式采集5大社交媒体数据:终极指南
  • 5分钟掌握PPTTimer:Windows上最智能的PPT演讲计时器终极指南
  • Docker构建低版本glibc编译环境:解决CentOS 7兼容性难题
  • NetLogo环境建模:社会网络仿真在生态研究中的应用