FastAPI缓存提速实战:手把手教你用Redis为接口注入“记忆”

你的FastAPI接口是不是在高并发下越来越慢,数据库频频告警?

一个案例,一个核心查询接口,在日活仅5万时,平均响应时间就飙升到了1.2秒。排查后发现,超过80%的请求都在重复查询数据库里那几条几乎不变的热点数据。在引入Redis缓存后,这个接口的平均响应时间直接降到了0.2秒以内,数据库负载下降了70%。这,就是缓存的魔力。

今天,我们就来聊聊如何为你FastAPI项目装上Redis这个“高速缓存”,让它拥有“记忆”,不再每次都傻傻地重复劳动。

📖 本文你将学到:

🎯 1. Redis是什么?为什么它是缓存的首选?

🎯 2. 如何快速安装、配置Redis。

🎯 3. 必须掌握的Redis核心命令。

🎯 4. 编写一个通用的FastAPI缓存装饰器,一劳永逸。


🔧 第一部分:问题与背景 - 为什么需要缓存?

想象一下,你是餐厅(你的Web服务)的服务员(API接口)。每次客人(客户端)点一份“今日特色菜”(热门数据),你都非得跑回后厨(数据库)问厨师一遍,尽管这道菜一天都不会变。结果就是,你累趴了,后厨也被你问烦了,客人还嫌上菜慢。

缓存,就像是你在前厅放了个小本子(Redis)。第一次有客人点“今日特色菜”,你去后厨问了,然后把菜名和价格记在本子上。接下来再有客人点,你直接看一眼本子就告诉他,速度快了十倍。只有当特色菜更换了(数据变更),你才需要去更新小本子。

在技术层面,缓存主要解决两个问题:1. 提升数据读取速度(内存远快于磁盘/网络);2. 减轻后端数据库压力

⚙️ 第二部分:Redis核心与安装配置

🎯 Redis是什么?

Redis是一个开源、基于内存、可持久化的键值对(Key-Value)存储系统。它支持多种数据结构(字符串、哈希、列表、集合等),性能极高,常被用作数据库、缓存和消息中间件。对于缓存场景,我们主要看中它:内存存储速度极快数据结构丰富支持设置过期时间

🎯 安装Redis(各平台通用步骤)

1. macOS (使用Homebrew):

- 打开终端,执行:brew install redis

- 启动服务:brew services start redis

2. Linux (以Ubuntu为例):

- 更新包管理器:sudo apt update

- 安装Redis:sudo apt install redis-server

- 启动服务:sudo systemctl start redis

3. Windows:

官方不支持Windows原生安装,但可以通过:

- 使用WSL2(推荐,在WSL的Ubuntu中按Linux方法安装)。

- 或下载微软维护的旧版本Windows移植版(不推荐用于生产)。

安装完成后,在终端输入redis-cli ping,如果返回PONG,恭喜你,Redis服务已成功运行!

🎯 你必须掌握的5个Redis缓存核心命令

1. SET: 设置键值对

/* by 01022.hk - online tools website : 01022.hk/zh/pinyin.html */ SET user:1001 '{"name": "Alice", "age": 30}' EX 60 # 键:user:1001, 值:JSON字符串, EX 60表示60秒后过期

2. GET: 获取键对应的值

/* by 01022.hk - online tools website : 01022.hk/zh/pinyin.html */ GET user:1001

3. EXISTS: 检查键是否存在

EXISTS user:1001 # 返回1(存在)或0(不存在)

4. DEL: 删除一个或多个键

DEL user:1001 user:1002

5. TTL: 查看键的剩余生存时间(秒)

TTL user:1001 # 返回剩余秒数,-1表示永不过期,-2表示键不存在

🚀 第三部分:FastAPI整合Redis实战演示

理论说再多,不如一行代码。让我们开始实战,构建一个带缓存的FastAPI应用。

🎯 第一步:安装依赖

pip install fastapi uvicorn redis python-dotenv

🎯 第二步:项目结构与配置

your_project/ ├── main.py ├── cache.py ├── .env └── requirements.txt

.env文件中配置Redis连接:

REDIS_HOST=localhost REDIS_PORT=6379 REDIS_DB=0 REDIS_PASSWORD= # 默认无密码,生产环境一定要设! CACHE_DEFAULT_TTL=3600 # 默认缓存过期时间1小时

🎯 第三步:创建Redis连接与缓存工具类 (cache.py)

import redis.asyncio as redis # 使用异步客户端 import json from functools import wraps from typing import Any, Optional import os from dotenv import load_dotenv load_dotenv() class RedisCache: def __init__(self): self.redis_client: Optional[redis.Redis] = None self.default_ttl = int(os.getenv(“CACHE_DEFAULT_TTL”, 3600)) async def connect(self): """连接Redis""" if not self.redis_client: self.redis_client = redis.Redis( host=os.getenv(“REDIS_HOST”, “localhost”), port=int(os.getenv(“REDIS_PORT”, 6379)), db=int(os.getenv(“REDIS_DB”, 0)), password=os.getenv(“REDIS_PASSWORD”), decode_responses=True # 自动解码返回字符串 ) return self.redis_client async def disconnect(self): """关闭连接""" if self.redis_client: await self.redis_client.close() def cache_key(self, func_name: str, *args, **kwargs) -> str: """生成唯一的缓存键""" # 简单示例:将函数名和参数序列化后拼接 arg_str = “_”.join([str(arg) for arg in args]) kwarg_str = “_”.join([f“{k}_{v}” for k, v in sorted(kwargs.items())]) return f“fastapi_cache:{func_name}:{arg_str}:{kwarg_str}”.strip(“:”) async def get(self, key: str) -> Any: """从缓存获取数据""" if not self.redis_client: await self.connect() data = await self.redis_client.get(key) if data: try: return json.loads(data) # 反序列化JSON except json.JSONDecodeError: return data # 如果不是JSON,返回原始字符串 return None async def set(self, key: str, value: Any, ttl: Optional[int] = None) -> bool: """设置缓存""" if not self.redis_client: await self.connect() if isinstance(value, (dict, list)): value = json.dumps(value) # 序列化复杂对象 expire_time = ttl if ttl is not None else self.default_ttl return await self.redis_client.setex(key, expire_time, value) async def delete(self, key: str) -> int: """删除缓存""" if not self.redis_client: await self.connect() return await self.redis_client.delete(key) # 全局缓存实例 cache = RedisCache() def cached(ttl: Optional[int] = None): """缓存装饰器:可复用于任何异步函数""" def decorator(func): @wraps(func) async def wrapper(*args, **kwargs): # 生成缓存键 key = cache.cache_key(func.__name__, *args, **kwargs) # 尝试从缓存获取 cached_result = await cache.get(key) if cached_result is not None: print(f“Cache HIT for key: {key}”) return cached_result # 缓存未命中,执行原函数 print(f“Cache MISS for key: {key}”) result = await func(*args, **kwargs) # 将结果存入缓存 await cache.set(key, result, ttl) return result return wrapper return decorator

🎯 第四步:在FastAPI应用中使用 (main.py)

from fastapi import FastAPI, Depends, HTTPException from cache import cache, cached import asyncio app = FastAPI(title=“FastAPI Redis缓存演示”) # 应用启动和关闭事件 @app.on_event(“startup”) async def startup_event(): await cache.connect() print(“✅ Redis connected”) @app.on_event(“shutdown”) async def shutdown_event(): await cache.disconnect() print(“👋 Redis disconnected”) # --- 模拟一个耗时的数据查询函数 --- async def fetch_user_data_from_db(user_id: int): """模拟从数据库查询用户数据(耗时操作)""" await asyncio.sleep(2) # 模拟2秒的IO延迟 return {“id”: user_id, “name”: f“用户_{user_id}”, “score”: user_id * 10} # --- 应用缓存的接口 --- @app.get(“/user/{user_id}”) @cached(ttl=30) # 为此接口单独设置30秒缓存 async def get_user(user_id: int): """获取用户信息(带缓存)""" data = await fetch_user_data_from_db(user_id) return {“source”: “database (cached later)”, “data”: data} @app.get(“/user/{user_id}/fresh”) async def get_user_fresh(user_id: int): """获取用户信息(强制查数据库,不缓存)""" data = await fetch_user_data_from_db(user_id) return {“source”: “database (fresh)”, “data”: data} @app.delete(“/cache/user/{user_id}”) async def delete_user_cache(user_id: int): """手动删除某个用户的缓存""" # 注意:这里需要模拟生成和接口一致的缓存键,实战中可能需要更复杂的键管理 key_pattern = f“fastapi_cache:get_user:{user_id}” deleted = await cache.delete(key_pattern) if deleted: return {“message”: f”Cache for user {user_id} deleted.”} raise HTTPException(status_code=404, detail=“Cache key not found”) if __name__ == “__main__”: import uvicorn uvicorn.run(“main:app”, host=“0.0.0.0”, port=8000, reload=True)

现在,运行python main.py并访问http://localhost:8000/docs查看自动生成的API文档。

测试效果:

- 首次访问/user/1,会等待约2秒,返回来源为database

-30秒内再次访问/user/1,瞬间返回,来源数据来自缓存,控制台会打印Cache HIT

- 访问/user/1/fresh则总是访问“数据库”。

- 调用DELETE /cache/user/1可以手动清除缓存。

💡 第四部分:注意事项与进阶思考

1. 缓存穿透:查询一个不存在的数据(如user_id=-1),缓存永远不会命中,请求每次都打到数据库。

-解决方案:即使没查到数据,也缓存一个空值或特殊标记(如NULL),并设置一个较短的过期时间。

2. 缓存雪崩:大量缓存键在同一时刻过期,导致所有请求瞬间涌向数据库。

-解决方案:为缓存过期时间添加一个随机值(如基础TTL + random.randint(0, 300)),避免集体失效。

3. 缓存更新策略:数据变更时,如何同步更新缓存?常用“写时删除”(Cache-Aside)。

- 更新数据库后,立即删除对应的缓存键。下次读取时自然回源并重新缓存。

4. 序列化:缓存复杂对象(如Pydantic模型)时,要确保它们能被JSON序列化。可以使用.dict()方法将其转为字典。

5. 键的设计:清晰的键命名空间(如app:entity:id)便于管理和批量操作(使用KEYSSCAN命令,生产环境慎用KEYS)。

6. 最重要的一点:缓存不是万能的,它是一种用空间换时间的权衡。不要缓存频繁变化的数据、极小结果集或已经很快的查询。始终监控缓存命中率,它是衡量缓存效益的关键指标。


---写在最后---
希望这份总结能帮你避开一些坑。如果觉得有用,不妨点个 赞👍 或 收藏⭐ 标记一下,方便随时回顾。也欢迎关注我,后续为你带来更多类似的实战解析。有任何疑问或想法,我们评论区见,一起交流开发中的各种心得与问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1163768.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实现AI智能排版功能,输入杂乱的文本内容,自动调整字体,行距,分段,生成美观的文档。

下面我将为您提供一个完整的、基于Python的“AI智能排版助手”(SmartFormatter)程序。项目概览:SmartFormatter - AI智能排版助手核心功能:用户提供一个包含杂乱文本的Markdown文件(例如从网页复制过来的内容&#xff…

方差齐性是指各组数据的方差相等

下面内容摘录自《用R探索医药数据科学》专栏文章的部分内容(原文5296字)。 2篇3章5节:认识方差和方差齐性检验(三种方法全覆盖)-CSDN博客 二、方差齐性检验 方差齐性检验在统计分析中占有重要地位,尤其是…

正则表达式入门:快速掌握核心规则,轻松验证邮箱格式

正则表达式是处理文本的利器,掌握它能极大提升工作效率。但许多初学者望而生畏,认为它复杂难懂。实际上,只要理解其核心概念和常见应用场景,就能快速上手并解决实际问题。本文将从几个具体问题出发,帮助你快速理解和使…

收藏必备!小白到专家:AI大模型学习全攻略(附资料)

内容覆盖了五大核心部分: ​ • 什么是 AI:关键术语与发展脉络 ​ • Prompting:提示工程的框架与进阶技巧 ​ • AI Agents:下一代自动化工作系统 ​ • Vibe Coding:AI 协作式编程方法 ​ • 未来趋势:20…

学生工作管理系统如何助力教育管理现代化发展

✅作者简介:合肥自友科技 📌核心产品:智慧校园平台(包括教工管理、学工管理、教务管理、考务管理、后勤管理、德育管理、资产管理、公寓管理、实习管理、就业管理、离校管理、科研平台、档案管理、学生平台等26个子平台) 。公司所有人员均有多…

Wireshark中文版(网络抓包工具)

Wireshark是一款强大的网络分析软件,可以帮助用户抓取、分析、解码网络上的数据包。它被广泛用于网络故障排除、分析、软件和通信协议开发以及教育等领域,支持Windows、macOS和Linux等多种操作系统。 软件功能 数据包捕获:可实时或离线抓取网…

【深度收藏】大模型部署框架对决:Ollama与vLLM谁更适合你?从入门到生产环境全方位解析

引言 🎯 开源 LLM 模型已经成为爱好者、程序员和希望在日常工作中使用生成式 AI 同时保护隐私的用户的热门选择。这些模型性能出色,有时在许多任务上甚至可以媲美像 GPT-4o 或 Claude Sonnet 3.5 这样的大型闭源模型。 虽然它们是开源的,但并…

【建议收藏】RAG技术选型指南:MaxKB还是FastGPT?一文带你读懂企业级知识库构建方案

RAG技术是当前阶段做内部知识库或者智能客服的不二之选。然而目前市面上可用作RAG的开源软件实在是太多了,Coze、Dify、FastGPT、RAGFlow还有MaxKB,当然还有其它,我就不再一一列举了。 今天这篇文章主要探讨在RAG领域,到底是选Max…

橡胶制品:柔性赋能多领域,绿色转型启新程

橡胶,作为一种兼具高弹性、耐磨性与密封性的特殊材料,其制品早已深度融入人类生产生活的方方面面。从驰骋公路的汽车轮胎到精密仪器的密封垫圈,从医疗领域的硅胶导管到日常使用的防滑手套,橡胶制品以其独特的柔性特质,…

Spring IoC是什么意思?3分钟讲清核心原理与作用

对于刚接触Spring框架的开发者来说,IoC(控制反转)是一个绕不开的核心概念。简单来说,它颠覆了传统程序主动创建和管理对象的模式,改由框架来接管这个过程。这不是一个空洞的理论,它直接决定了你如何构建松耦…

setcommmask有什么用?串口编程的事件过滤器详解

在处理Windows串口通信编程时,SetCommMask是一个你必须掌握的核心函数。它本质上是一个“事件过滤器”,用于告诉操作系统你的程序关心串口上发生的哪些异步事件。合理设置事件掩码,可以让你编写的串口通信程序高效且响应迅速,避免…

AI产品经理必看!手把手教你绘制AI智能体架构图

在AI项目从0到1的探索中,你是否遇到过这样的窘境?技术团队说自己“懂了”,却总在实现时出偏差;业务团队抓不住重点,不断变更需求;而管理层更关心的是ROI和交付节奏,却总对技术架构一头雾水。——…

导师推荐!MBA必备10款AI论文软件测评TOP10

导师推荐!MBA必备10款AI论文软件测评TOP10 2026年MBA学术写作工具测评:为何值得关注? 在MBA学习与研究过程中,论文撰写是一项核心任务,而AI论文软件的使用正逐渐成为提升效率、优化内容质量的重要手段。然而&#xff0…

收藏!小白程序员入门大模型必看:别怕零基础,这门热门技术你也能掌握

准备入门大模型?先把“我没基础”“这技术太难”的顾虑抛开!我始终相信,只要你有主动学习的意愿,再配上持续的付出,完全能攻克大模型,甚至能用它搞定各类实际场景中的有意义任务。 当下技术迭代速度飞快&am…

圆角矩形设计优势与前端实现技巧详解

圆角矩形(roundrect)是现代数字界面设计中无处不在的基础元素。它远不止是视觉上的柔和处理,更关乎用户体验的舒适度、信息的层级划分以及品牌调性的传达。从iOS的图标到各类应用按钮,其背后的设计逻辑与实现细节值得每一位设计师…

【深度学习】YOLO 进阶提升之算法改进(新型骨干网络 / 特征融合方法 / 损失函数设计)

YOLO 系列算法的性能瓶颈主要集中在小目标检测精度、复杂场景鲁棒性、边界框回归精度三个维度。通过改进骨干网络、特征融合方法、损失函数三大核心模块,可针对性突破瓶颈,实现精度与速度的二次提升。本文以 YOLOv8/v11 为基础,从改进思路、技…

AI落地实践:2026年十大行业应用全解析 | 程序员学习指南,建议收藏

2026年人工智能从技术探索迈向规模化应用,"AI"上升为国家战略。国产大模型实现突破,深度融入工业制造、医疗健康、科研、金融等十大行业,从单点智能向全域智能转变,形成"技术突破—场景落地—产业升级"的良性…

C++ Win32窗口编程中窗口风格(Window Styles)的使用经验与相关要点总结(附源码)

目录 1、WS_CHILD和WS_POPUP 2、WS_VISIBLE 3、WS_MINIMIZE和WM_MAXIMIZE 4、WS_MINIMIZEBOX和WS_MAXIMIZEBOX 5、WS_BORDER和WS_CAPTION 6、WS_THICKFRAME和WS_SIZEBOX 7、WS_SYSTEMMENU 8、WS_EX_APPWINDOW和WS_EX_TOOLWINDOW 9、WS_EX_TOPMOST 10、WS_EX_LAYEREDW…

索磷布韦维帕他韦Sofosbuvir/velpatasvir治疗丙型肝炎的病毒学治愈周期与泛基因型疗效

丙型肝炎(HCV)作为一种全球性公共卫生挑战,其治疗策略随着直接抗病毒药物(DAA)的发展经历了革命性变革。索磷布韦维帕他韦(Sofosbuvir/velpatasvir)作为首个泛基因型DAA复方制剂,凭借…

收藏!大模型面试必问:为什么有KV-Cache却没有Q-Cache?

在大模型相关的技术面试中,“为什么存在KV-Cache却没有Q-Cache”是高频考点,不少刚入门大模型的程序员和小白都会被这个问题难住。今天这篇文章就从核心原理出发,结合具体生成流程拆解分析,帮你彻底搞懂这个问题,面试遇…