AI Agent 缓存实战:Redis 加速 LLM 调用与向量检索

发布时间:2026/10/6 15:04:20

AI Agent 缓存实战:Redis 加速 LLM 调用与向量检索 1. 为什么 AI Agent 必须认真对待缓存这件事做过 AI Agent 项目的人都有一个共同体会模型调用本身不是最慢的真正拖垮整个系统响应速度的往往是那些看起来不起眼的重复计算和重复查询。一个稍微复杂一点的 Agent一次对话可能触发十几轮工具调用、几十次向量检索、上百次状态读写。如果每一轮都老老实实去查数据库、调接口、重新计算那这个 Agent 的响应时间会从秒级直接飙到分钟级用户体验直接崩盘。我最早做 Agent 项目的时候压根没把缓存当回事觉得 Agent 的核心是推理链路和工具编排缓存这种“基础设施”的东西后面再说。结果上线第一周就被现实教育了同一个用户连续问三个相似问题Agent 每次都重新走一遍完整的检索和推理流程Token 消耗翻了三倍不说响应时间还越来越长。后来加了 Redis 缓存层同样的场景响应时间直接从 8 秒降到 1.2 秒Token 成本砍掉了将近一半。这就是我想聊的核心话题AI Agent 和 Redis 缓存的结合。这不是一个“锦上添花”的优化项而是 Agent 从 Demo 走向生产环境的必修课。这篇文章适合正在搭建 AI Agent 的开发者、正在做 Agent 性能优化的工程师以及任何想让自己的 Agent 跑得更快更稳的人。我会从架构设计、缓存策略、实操步骤、踩坑经验几个维度把这件事讲透。2. AI Agent 的缓存需求到底特殊在哪里2.1 传统缓存和 Agent 缓存的本质区别传统 Web 应用的缓存逻辑相对简单查数据库之前先查 Redis命中就返回没命中就查库然后写回缓存。这套逻辑用了十几年成熟稳定。但 AI Agent 的缓存需求完全是另一个维度的事情。Agent 的运行过程不是一次简单的“请求-响应”而是一个多步骤的推理循环。以典型的 ReAct 架构为例一个完整的 Agent 执行链路包括接收用户输入、理解意图、规划步骤、调用工具、观察结果、反思调整、生成最终回复。这里面每一步都可能产生需要缓存的数据而且不同类型的数据缓存策略完全不同。我拿一个实际场景来说明。假设你做了一个电商客服 Agent用户问“我上周买的那个耳机什么时候到”。这个请求在 Agent 内部会被拆解成识别用户身份、查询订单列表、匹配“上周买的耳机”、查询物流状态、生成自然语言回复。这里面用户身份信息变化频率低可以缓存较长时间订单列表变化频率中等需要设置合理的过期时间物流状态变化频率高缓存时间要短最终回复如果用户问的是完全相同的问题可以直接缓存回复你看光是一个简单场景就涉及四种不同缓存策略。如果全部用同一套 TTL 和淘汰策略要么数据过期导致回答错误要么缓存命中率低得可怜。2.2 Agent 场景下最需要缓存的五类数据根据我自己的项目经验AI Agent 场景下最值得做缓存的五类数据分别是第一类是 LLM 调用结果。这是成本最高、最值得缓存的部分。同样的 prompt 和参数如果短时间内重复调用完全没必要每次都打到模型 API。特别是那些用于意图分类、实体提取、格式转换的“小模型调用”输入输出高度确定缓存命中率可以做到很高。第二类是向量检索结果。RAG 架构的 Agent 每次都要做向量相似度搜索如果同一个 query 反复出现或者多个用户问了语义相近的问题缓存检索结果能省下大量计算。这里要注意的是向量检索的缓存 key 不能直接用原始 query 字符串而应该用 embedding 向量做近似匹配。第三类是工具调用结果。Agent 调用的外部 API、数据库查询、文件读取等操作很多都是幂等的。比如查询天气、查询汇率、读取配置信息这些结果在短时间内不会变化完全可以缓存。第四类是会话状态。Agent 的多轮对话需要维护上下文这些状态数据存在 Redis 里比存在内存里更可靠而且天然支持分布式部署。第五类是中间推理结果。复杂 Agent 的推理链路很长中间步骤的结果如果被缓存可以在重试或分支时直接复用避免重复计算。2.3 缓存能解决 Agent 的哪些核心痛点说到底缓存解决的是三个核心问题延迟、成本和稳定性。延迟方面LLM 调用动辄几百毫秒到几秒向量检索也要几十到几百毫秒。缓存命中后这些操作直接变成 Redis 的一次 GET耗时降到毫秒级。我实测过一个 RAG Agent加了缓存之后 P99 延迟从 6.8 秒降到了 1.9 秒。成本方面每次 LLM 调用都是真金白银。缓存命中意味着这次调用不用花钱。一个日活几千的 Agent 应用如果缓存命中率能做到 30%一个月省下的 API 费用相当可观。稳定性方面Agent 依赖的外部服务可能超时、限流、宕机。缓存层可以作为降级方案当外部服务不可用时返回缓存中的旧数据保证 Agent 至少能给出一个“虽然不最新但可用”的回复。3. Redis 在 Agent 架构中的角色定位与选型考量3.1 为什么是 Redis 而不是其他缓存方案缓存方案有很多选择本地内存缓存如 Caffeine、Memcached、Redis、甚至直接用数据库的物化视图。为什么 Agent 场景下我首推 Redis本地内存缓存的问题是分布式环境下无法共享。你的 Agent 服务可能部署了多个实例用户第一次请求打到实例 A缓存写在了 A 的内存里第二次请求打到实例 B缓存就没了。Agent 的会话状态和缓存数据需要跨实例共享本地缓存做不到。Memcached 虽然也是分布式缓存但它的数据结构太单一只有简单的 key-value。Agent 场景下我们需要存储复杂结构会话上下文是嵌套的 JSON、向量检索结果是列表、工具调用结果可能带元数据。Redis 丰富的数据类型在这里优势明显。Redis 的核心优势在于支持 String、Hash、List、Set、Sorted Set、Stream 等多种数据结构原生支持过期时间支持发布订阅和 Lua 脚本持久化机制成熟生态工具丰富。对于 Agent 场景来说Redis 几乎是一个“全能选手”。3.2 Agent 缓存中 Redis 数据类型的实战选择很多人用 Redis 就是无脑 SET 和 GET把所有东西都序列化成字符串存进去。这在简单场景下没问题但在 Agent 场景下会浪费很多 Redis 的能力。我结合实际项目说说不同数据该用什么类型。String 类型适合存储 LLM 调用结果、最终回复、简单的配置信息。这是最常用的类型没什么好说的。Hash 类型适合存储会话状态。一个会话有多个字段用户 ID、对话历史、当前步骤、临时变量等。用 Hash 存储可以单独更新某个字段不用整体读写。比如HSET session:abc123 user_id u001 current_step tool_call last_active 1700000000 HGET session:abc123 current_stepList 类型适合存储对话历史。对话消息是有序的用 List 的 LPUSH 和 LRANGE 可以方便地实现“保留最近 N 条消息”的逻辑LPUSH chat:abc123 user: 你好 LPUSH chat:abc123 assistant: 你好有什么可以帮你 LTRIM chat:abc123 0 19 # 只保留最近20条Sorted Set 类型适合做缓存优先级管理。比如你想根据访问频率决定哪些缓存优先保留可以用 Sorted Set 记录访问次数淘汰时优先淘汰分数低的。Stream 类型适合做 Agent 的事件日志。Agent 的每一步操作都可以写入 Stream方便后续审计和回放。3.3 缓存 key 的设计规范Key 的设计看起来是小事实际上影响很大。我见过太多项目因为 key 设计混乱导致缓存污染、难以排查问题。我的建议是采用分层命名{业务前缀}:{数据类型}:{唯一标识}。比如agent:llm:hash:{prompt_hash}— LLM 调用结果agent:vec:{query_hash}— 向量检索结果agent:session:{session_id}— 会话状态agent:tool:{tool_name}:{param_hash}— 工具调用结果这样做的好处是可以通过SCAN agent:llm:*快速定位某类缓存可以在 Redis 监控中按前缀统计命中率可以针对不同前缀设置不同的淘汰策略。注意生产环境绝对不要用KEYS *来查找 key这个命令会阻塞 Redis。用SCAN命令代替它采用游标迭代不会阻塞。4. 从零搭建 Agent 缓存层的完整实操4.1 环境准备与 Redis 部署先搞定 Redis 环境。开发环境我建议用 Docker 跑一个单机版简单快捷docker run -d --name redis-agent \ -p 6379:6379 \ -v /data/redis:/data \ redis:7.2-alpine \ redis-server --appendonly yes --maxmemory 512mb --maxmemory-policy allkeys-lru这里几个参数值得说明。--appendonly yes开启 AOF 持久化防止 Redis 重启后缓存全丢虽然缓存丢了也能重建但会话状态丢了影响大。--maxmemory 512mb限制内存使用防止缓存把服务器内存吃光。--maxmemory-policy allkeys-lru设置淘汰策略为“所有 key 中淘汰最近最少使用的”这是 Agent 缓存场景下比较通用的策略。生产环境建议做主从架构至少一主一从配合哨兵做故障转移。如果数据量大可以用 Redis Cluster 做分片。不过对于大多数中小规模的 Agent 应用主从加哨兵已经够用了。Python 环境下安装 redis 客户端pip install redis如果你用的是异步框架比如 FastAPI建议用redis.asyncioimport redis.asyncio as aioredis redis_client aioredis.Redis( hostlocalhost, port6379, db0, decode_responsesTrue, max_connections50, socket_timeout3, socket_connect_timeout3 )连接池参数很关键。max_connections要根据你的并发量设置太小会导致连接等待太大浪费资源。socket_timeout一定要设否则 Redis 卡住时你的 Agent 会一直挂着。4.2 LLM 调用结果的缓存实现这是最核心的缓存场景。思路很简单把 prompt 和模型参数拼在一起做哈希作为缓存 key模型返回结果作为 value。import hashlib import json import redis r redis.Redis(hostlocalhost, port6379, decode_responsesTrue) def cache_key_for_llm(prompt: str, model: str, temperature: float) - str: raw f{model}|{temperature}|{prompt} return fagent:llm:{hashlib.sha256(raw.encode()).hexdigest()[:16]} def call_llm_with_cache(prompt: str, model: str gpt-4, temperature: float 0.0, ttl: int 3600): key cache_key_for_llm(prompt, model, temperature) cached r.get(key) if cached: return json.loads(cached) result actual_llm_call(prompt, model, temperature) r.setex(key, ttl, json.dumps(result, ensure_asciiFalse)) return result这里有几个关键决策点。temperature 必须参与哈希计算因为 temperature0 和 temperature0.7 的输出完全不同不能混用缓存。TTL 设置要合理对于事实性问答可以设长一点比如 1 小时对于时效性内容要设短比如 5 分钟。哈希截取前 16 位是为了控制 key 长度16 位十六进制有 64 位熵碰撞概率极低。实操心得如果你的 Agent 用了 system prompt一定要把 system prompt 也纳入哈希计算。我踩过这个坑改了 system prompt 之后缓存没失效Agent 还在用旧的人格设定回复排查了半天才发现是缓存 key 没包含 system prompt。4.3 向量检索结果的缓存策略向量检索的缓存比 LLM 缓存复杂因为 query 是自然语言同一个意思可以有无数种表达方式。“今天天气怎么样”和“今天天气如何”语义相同但字符串不同用字符串哈希做 key 会导致缓存命中率极低。我的做法是先对 query 做 embedding然后用 embedding 向量的哈希做 key。但这样也有问题——embedding 是浮点数向量直接哈希的话即使语义相同只要有一个浮点数不同哈希就不同。更实用的方案是对 embedding 向量做量化后再哈希。比如把每个维度从 float32 量化到 int8然后拼接哈希import numpy as np def vector_cache_key(embedding: list, precision: int 2) - str: arr np.array(embedding, dtypenp.float32) quantized np.round(arr, precision) raw quantized.tobytes() return fagent:vec:{hashlib.md5(raw).hexdigest()[:16]}precision2表示保留两位小数这样语义相近的 query 有更大概率命中同一个缓存。precision 越小命中率越高但精度损失越大。我一般从 2 开始试根据实际命中率和准确率调整。另一种方案是用 Redis 的向量搜索功能Redis Stack 提供直接做近似最近邻搜索。这个方案更优雅但部署复杂度更高适合对检索质量要求高的场景。4.4 会话状态的 Redis 存储方案Agent 的多轮对话需要维护上下文。我见过有人把上下文存在 Python 进程的内存字典里单机跑没问题一上多实例就出问题——用户第一次请求打到实例 A第二次打到实例 B上下文就丢了。用 Redis Hash 存储会话状态是标准做法import time def save_session(session_id: str, data: dict, ttl: int 1800): key fagent:session:{session_id} pipe r.pipeline() pipe.hset(key, mappingdata) pipe.expire(key, ttl) pipe.execute() def get_session(session_id: str) - dict: key fagent:session:{session_id} data r.hgetall(key) if data: r.expire(key, 1800) # 续期 return data这里用了 pipeline 把 HSET 和 EXPIRE 打包发送减少网络往返。读取时做了“续期”操作用户每次交互都刷新 TTL保证活跃会话不会过期。对话历史用 List 存储配合 LTRIM 控制长度def append_message(session_id: str, role: str, content: str, max_history: int 20): key fagent:chat:{session_id} msg json.dumps({role: role, content: content, ts: time.time()}, ensure_asciiFalse) pipe r.pipeline() pipe.lpush(key, msg) pipe.ltrim(key, 0, max_history - 1) pipe.expire(key, 1800) pipe.execute()max_history20表示只保留最近 20 条消息。这个数字要根据你的模型上下文窗口和 Token 预算来定。保留太多会浪费 Token保留太少会导致 Agent“失忆”。4.5 缓存更新与失效的时机把控缓存最难的不是“怎么存”而是“什么时候删”。Agent 场景下数据源可能随时变化缓存如果不及时失效Agent 就会基于过期信息做决策。我的策略是分场景处理对于 LLM 调用结果基本不需要主动失效靠 TTL 自然过期就行。因为模型本身不会变prompt 不变结果就不变。对于工具调用结果要根据数据源的更新频率设置 TTL。查询天气的 TTL 设 10 分钟查询订单的 TTL 设 1 分钟查询用户资料的 TTL 设 30 分钟。对于会话状态用户主动结束会话时立即删除或者 TTL 到期自动清理。对于向量检索结果当知识库更新时需要主动清除相关缓存。可以用版本号机制知识库每次更新递增一个版本号缓存 key 里带上版本号旧版本的缓存自然失效。def get_kb_version() - str: v r.get(agent:kb:version) return v or 1 def vector_cache_key_with_version(embedding: list) - str: version get_kb_version() base vector_cache_key(embedding) return f{base}:v{version}5. 高并发场景下的缓存治理与性能调优5.1 缓存穿透、击穿、雪崩的应对这三个问题是缓存领域的经典问题Agent 场景下同样会遇到而且因为 Agent 的调用链路长影响会被放大。缓存穿透是指查询一个不存在的数据缓存和数据库都没有每次请求都打到数据库。Agent 场景下的典型表现是用户问了一个知识库里没有的问题每次都要重新做向量检索和 LLM 调用。解决方案是缓存空结果def get_with_null_cache(key: str, fetch_func, ttl: int 300): cached r.get(key) if cached is not None: if cached __NULL__: return None return json.loads(cached) result fetch_func() if result is None: r.setex(key, 60, __NULL__) # 空结果缓存60秒 else: r.setex(key, ttl, json.dumps(result, ensure_asciiFalse)) return result缓存击穿是指某个热点 key 过期瞬间大量请求同时打到后端。Agent 场景下一个热门问题可能被很多用户同时问到。解决方案是用分布式锁保证只有一个请求去回源import uuid def get_with_lock(key: str, fetch_func, ttl: int 3600, lock_timeout: int 10): cached r.get(key) if cached: return json.loads(cached) lock_key flock:{key} lock_value str(uuid.uuid4()) acquired r.set(lock_key, lock_value, nxTrue, exlock_timeout) if acquired: try: result fetch_func() r.setex(key, ttl, json.dumps(result, ensure_asciiFalse)) return result finally: # 用 Lua 脚本保证只删除自己的锁 lua if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end r.eval(lua, 1, lock_key, lock_value) else: # 没抢到锁等待一下再重试 time.sleep(0.1) return get_with_lock(key, fetch_func, ttl, lock_timeout)缓存雪崩是指大量 key 同时过期请求全部打到后端。解决方案是给 TTL 加随机抖动import random def setex_with_jitter(key: str, ttl: int, value: str, jitter: int 300): actual_ttl ttl random.randint(0, jitter) r.setex(key, actual_ttl, value)5.2 缓存命中率监控与调优缓存做了不等于有效必须监控命中率。Redis 自带的INFO stats可以看全局命中率但 Agent 场景下我们更需要按业务维度看命中率。我的做法是在应用层埋点每次缓存查询都记录命中/未命中from collections import defaultdict class CacheMetrics: def __init__(self): self.stats defaultdict(lambda: {hit: 0, miss: 0}) def record(self, category: str, hit: bool): self.stats[category][hit if hit else miss] 1 def hit_rate(self, category: str) - float: s self.stats[category] total s[hit] s[miss] return s[hit] / total if total 0 else 0.0根据我的经验不同类别的合理命中率参考值缓存类别合理命中率低于此值需排查LLM 调用结果25%-40%检查 prompt 是否包含时间戳等变化内容向量检索结果30%-50%检查 embedding 量化精度是否过高工具调用结果40%-60%检查 TTL 是否设置过短会话状态90%检查 session_id 是否稳定命中率低的时候优先排查 key 的设计。我遇到过最隐蔽的一个问题是prompt 里包含了当前时间戳导致每次 key 都不同命中率直接为零。这种问题不看 key 的生成逻辑根本发现不了。5.3 Redis 内存管理与淘汰策略选择Agent 缓存会占用大量内存特别是向量检索结果和 LLM 调用结果单条可能几 KB 到几十 KB。必须设置合理的内存上限和淘汰策略。Redis 提供八种淘汰策略Agent 场景下我推荐这几种allkeys-lru所有 key 中淘汰最近最少使用的。适合缓存内容价值均匀的场景。volatile-lru只淘汰设置了过期时间的 key 中最近最少使用的。适合会话状态需要持久保留、其他缓存可以淘汰的场景。allkeys-lfu淘汰访问频率最低的。适合有明显热点数据的场景。我一般用allkeys-lru简单有效。如果你的会话状态和普通缓存混在同一个 Redis 实例里用volatile-lru更安全保证会话状态不会被淘汰。内存监控用INFO memory查看used_memory_human和used_memory_peak_human。如果内存使用率长期超过 80%要么扩容要么优化缓存内容比如压缩 value、缩短 TTL。5.4 序列化方式的选择与性能对比Redis 存储的是字节Python 对象需要序列化。不同序列化方式的性能和体积差异很大序列化方式速度体积可读性适用场景JSON中等中等好通用场景调试方便Pickle快中等差纯 Python 内部使用MessagePack快小差对体积敏感的场景Protobuf最快最小差高性能、强类型场景我一般用 JSON因为可读性好排查问题方便。如果对性能要求极高可以换 MessagePackimport msgpack def set_msgpack(key: str, value, ttl: int): r.setex(key, ttl, msgpack.packb(value, use_bin_typeTrue)) def get_msgpack(key: str): data r.get(key) if data: return msgpack.unpackb(data, rawFalse) return None注意用 Pickle 序列化有安全风险如果缓存数据可能被外部篡改反序列化时可能执行恶意代码。生产环境建议用 JSON 或 MessagePack。6. 常见问题排查与避坑经验实录6.1 缓存与数据不一致的排查思路这是最让人头疼的问题。Agent 基于过期缓存给出了错误回答用户投诉你查日志发现数据源明明已经更新了。排查步骤我总结为“三步定位法”第一步确认缓存是否真的过期。用TTL key查看剩余过期时间用GET key查看实际值。如果 TTL 是 -1 说明没有设置过期时间是 -2 说明 key 不存在。第二步确认写入时机。检查数据源更新后是否有代码逻辑去删除或更新对应的缓存。很多不一致问题是因为更新数据源时忘了清缓存。第三步确认并发时序。在高并发下可能出现“读请求先查缓存未命中然后去查数据库此时写请求更新了数据库并删除了缓存然后读请求把旧数据写回了缓存”。这种时序问题需要用延迟双删或版本号机制解决。延迟双删的实现def update_with_double_delete(key: str, update_func, delay: float 0.5): r.delete(key) update_func() time.sleep(delay) r.delete(key)6.2 Redis 连接超时与重连处理Agent 服务对 Redis 的依赖很重Redis 连接出问题会直接导致 Agent 不可用。我遇到过几次 Redis 连接超时导致的线上故障总结了几条经验。首先必须设置连接超时和读写超时。不设置的话Redis 卡住时你的 Agent 线程会一直等待最终拖垮整个服务。redis_client redis.Redis( hostlocalhost, port6379, socket_timeout3, socket_connect_timeout3, retry_on_timeoutTrue, health_check_interval30 )retry_on_timeoutTrue让客户端在超时后自动重试一次。health_check_interval30每 30 秒做一次健康检查及时发现断开的连接。其次要有降级方案。Redis 不可用时Agent 应该能降级到直接查数据源而不是直接报错def safe_cache_get(key: str): try: return r.get(key) except redis.RedisError as e: logger.warning(fRedis get failed: {e}) return None def safe_cache_set(key: str, value: str, ttl: int): try: r.setex(key, ttl, value) except redis.RedisError as e: logger.warning(fRedis set failed: {e})6.3 大 key 和热 key 的识别与处理大 key是指 value 体积过大的 key。Agent 场景下一个包含完整对话历史的 List 可能达到几 MB读写这种 key 会阻塞 Redis。识别大 key 用redis-cli --bigkeys命令它会扫描所有 key 并报告最大的几个。处理方式是拆分把一个大 List 拆成多个小 List或者用 Hash 分字段存储。热 key是指访问频率极高的 key。比如某个热门问题的缓存每秒被访问几千次。热 key 会导致单个 Redis 节点压力过大。识别热 key 用redis-cli --hotkeys需要 Redis 4.0 且开启 LFU 策略。处理方式是在应用层做本地缓存减少对 Redis 的访问from functools import lru_cache lru_cache(maxsize1000) def get_hot_data(key: str): return r.get(key)lru_cache在进程内缓存最近 1000 个 key 的值热 key 会命中本地缓存大幅减少 Redis 压力。但要注意本地缓存的一致性问题TTL 要设短一些。6.4 缓存预热与冷启动优化Agent 服务重启后缓存是空的所有请求都要回源这时候响应会特别慢。解决办法是缓存预热服务启动时主动加载热点数据到缓存。def warm_up_cache(): hot_questions load_hot_questions_from_db(limit100) for q in hot_questions: key cache_key_for_llm(q.prompt, q.model, q.temperature) if not r.exists(key): result actual_llm_call(q.prompt, q.model, q.temperature) r.setex(key, 3600, json.dumps(result, ensure_asciiFalse)) logger.info(fCache warm-up completed for {len(hot_questions)} items)预热数据从哪来可以从历史访问日志中统计高频 query也可以人工整理业务上的核心问题。预热的时机建议在服务正式接流量之前避免预热请求和正常请求抢资源。6.5 常见问题速查表问题现象可能原因排查方法解决方案缓存命中率极低key 包含变化内容打印实际 key 对比移除时间戳、随机数等变化因子内存持续增长未设置 TTL 或 TTL 过长INFO memory查看所有缓存必须设 TTL响应时间波动大大 key 阻塞--bigkeys扫描拆分大 key数据不一致更新时未清缓存检查更新逻辑延迟双删或版本号连接超时连接池耗尽INFO clients查看增大连接池或优化慢查询缓存雪崩TTL 集中过期检查 TTL 分布加随机抖动热 key 压力大单 key 访问集中--hotkeys扫描本地缓存 读写分离7. 一些实战中的个人体会做 AI Agent 的缓存优化最忌讳的就是“一刀切”。我见过有团队给所有缓存统一设 1 小时 TTL结果物流查询返回了一小时前的状态用户投诉说“我的包裹明明已经到了怎么还显示在路上”。也见过有团队为了追求高命中率把 TTL 设得特别长结果知识库更新后 Agent 还在用旧知识回答。我的经验是缓存策略要跟着数据的“半衰期”走。变化越快的数据TTL 越短变化越慢的数据TTL 越长。LLM 调用结果可以缓存几小时工具调用结果缓存几分钟会话状态缓存半小时。这个没有标准答案要根据你的业务场景去调。另一个体会是缓存不是越多越好。有些数据缓存了反而增加复杂度比如那些本来就很快的查询Redis 查询 1ms数据库查询 3ms缓存带来的收益微乎其微却增加了不一致的风险。判断标准很简单如果回源成本远大于缓存维护成本就值得缓存否则不如不缓存。最后说一个容易被忽视的点缓存的 key 一定要可观测。我在项目里加了一个调试接口输入一个 query 就能看到它对应的所有缓存 key 和命中状态。这个工具在排查问题时救命了无数次。没有可观测性的缓存系统就是一个黑盒出了问题只能靠猜。
延伸阅读

更多相关文章

2026/10/6 15:04:20

管道与多线程:VC环境下父子进程通信实例拆解

简介:一份面向Visual C开发者的Windows进程间通信技术文档,以“管道多线程”为主线,分析在多任务系统内,进程如何借助共享内存式的管道实现数据交换与协作;相比剪贴板、DDE、OLE等传统通信手段,管道使用简便…

2026/10/6 15:04:20

2010年网络安全毕设文档的现代复用指南:从策略框架到落地检查表

简介:这份资源是一篇计算机网络安全策略方向的毕业论文终稿,面向计算机科学与技术、信息安全等专业的本科生及需要撰写同类论文的学习者,帮助解决选题定位、框架搭建与策略论述等写作难题。压缩包内仅含1个doc文档,大小约235KB&am…

2026/10/6 15:04:20

1人3周干完4个月活:AI Agent、worktree与CI实战复盘

1. 一个人三周干完四个月的活,到底省在哪了先把这个项目的底牌摊开说:一个企业级交付项目,正常配置是4人团队、2个月工期,实际执行是1个人带着3个AI Agent、3周完成。这不是标题党,是我自己跑完的一个真实项目节奏。关…

2026/10/6 15:59:25

GhostTrack 免费安装教程:5 分钟跑通 IP 查询

GhostTrack 免费安装教程:5 分钟跑通 IP 查询 【免费下载链接】GhostTrack Useful tool to track location or mobile number 项目地址: https://gitcode.com/GitHub_Trending/gh/GhostTrack GhostTrack 是一款免费的 Python 小工具,主打 OSINT 信…

2026/10/6 15:59:25

OpCore-Simplify指南:5分钟生成可用的OpenCore EFI

OpCore-Simplify指南:5分钟生成可用的OpenCore EFI 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify 想在电脑上装macOS,又不想手…

2026/10/6 15:54:25

MuPDF C 多线程渲染实战:主线程读页 + 每页一线程并行输出 PNG

图形学图像处理 【免费下载链接】mupdf mupdf mirror 项目地址: https://gitcode.com/gh_mirrors/mu/mupdf 点击查看 免费下载 MuPDF 是一个轻量级、模块化的 PDF/XPS/CBZ/EPUB 渲染引擎,其 C API 刻意不绑定任何具体线程框架,多线程能力完全…

2026/10/5 6:32:56

Jev+Agent接管浏览器:browser-use实战与jev-ultrafast性能优化

1. 从“Jev”说起:为什么我要把Agent接进浏览器“Jev”这个词最近在圈子里出现的频率越来越高,很多人第一次听到会以为是某个新模型的名字,其实它更像是一种思路——把Jev模型的能力当作底座,通过Agent的方式去接管浏览器&#xf…

2026/10/6 4:01:51

多智能体集群实战:DeepAgents编排、MCP与A2A协议及Skills体系

1. 从"单兵作战"到"集群协同":多智能体编排到底在解决什么问题如果你最近在折腾 Agent 相关的东西,大概率会有一种感觉:单个 Agent 能做的事情,其实很快就摸到天花板了。你给它一个提示词,挂几个工…

2026/10/5 17:38:27

无源低通滤波器设计实战:从RC到LC,手把手教你避开那些坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/6 0:03:23

MR25H40CDF+STM32F031C6工业级高可靠数据存储方案

1. 项目概述:为什么在工业现场非得用 MR25H40CDF 配 STM32F031C6 做数据存储?在工厂产线的 PLC 控制柜里、在风电变流器的散热片背面、在矿井监测终端的金属外壳下,你经常能看到一块指甲盖大小的黑色芯片——它既不是 Flash,也不是…

2026/10/6 0:03:23

MRAM+STM32工业断电数据保全实战指南

1. 项目概述:为什么在工业现场非得用 MR25H40CDF 配 STM32F031C6 做数据存储?在工厂产线的PLC柜里、在野外无人值守的环境监测终端里、在高速运转的包装机控制板上,你经常能看到一块指甲盖大小的黑色芯片,旁边贴着“MR25H40CDF”丝…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑