You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5.9 KiB
5.9 KiB
AI Provider Factory 缓存永不过期机制
日期: 2026-02-14
类型: Bug 修复 + 架构优化
影响范围: 后端 AI Provider 缓存系统
严重程度: 高(影响所有 AI 功能)
问题描述
原问题
应用在运行 5 小时后,用户调用 AI 功能时出现错误:
模型 {model_name} 不存在或未激活。
请检查:1) 模型是否已同步到数据库 2) 模型是否已启用(is_active=True) 3) Redis 缓存是否已初始化
根本原因
- Redis 缓存 TTL 过短: 原 TTL 为 3600 秒(1 小时)
- 缓存过期后未自动重建: 应用启动 5 小时后,缓存已过期且未刷新
问题影响
- 所有 AI 相关功能(文生图、文生视频、配音等)不可用
- 需要手动重启应用才能恢复
解决方案
技术方案
采用 永不过期 + 懒加载 + 手动刷新 的组合方案:
- ✅ Redis 缓存永不过期: 彻底解决缓存失效问题
- ✅ 实现懒加载: 缓存不存在时自动从数据库重建
- ✅ 手动刷新接口: 模型更新后可主动刷新缓存
- ✅ 应用启动时强制刷新: 确保数据最新
方案演进
| 阶段 | 方案 | TTL | 问题 |
|---|---|---|---|
| 阶段 1 | 原方案 | 1 小时 | ❌ 1 小时后服务不可用 |
| 阶段 2 | 延长 TTL | 24 小时 | ⚠️ 24 小时后仍会过期 |
| 阶段 3 | 永不过期 ✅ | 无 | ✅ 彻底解决缓存失效问题 |
为什么永不过期是最优解?
AI 模型配置的特点:
- 📊 低频变更: 通常几周/几个月才更新一次
- 🔒 管理员操作: 模型更新由管理员控制
- 📈 高频读取: 每次 AI 请求都需要查询模型配置
永不过期的优势:
- ✅ 零缓存失效: 彻底消除缓存过期问题
- ✅ 性能最优: 所有请求都从 Redis 读取(< 1ms)
- ✅ 架构简单: 无需管理 TTL,无需定时任务
- ✅ 可控刷新: 主动控制刷新时机
关键改动
1. 移除 CACHE_TTL
class AIProviderFactory:
- CACHE_TTL = 86400 # 缓存过期时间:24 小时
+ # 注意:缓存永不过期,模型更新后需手动调用 refresh_cache()
2. 使用 redis.set() 替代 redis.setex()
# 应用启动时初始化
- await redis.setex(cls.CACHE_KEY, cls.CACHE_TTL, json.dumps(cache_dict))
+ await redis.set(cls.CACHE_KEY, json.dumps(cache_dict))
# 懒加载重建
- await redis_client.setex(cls.CACHE_KEY, cls.CACHE_TTL, json.dumps(cache_dict))
+ await redis_client.set(cls.CACHE_KEY, json.dumps(cache_dict))
3. 更新日志信息
- logger.info("✅ AI Provider Factory 缓存已初始化(Redis): 已加载 %d 个模型", len(cache_dict))
+ logger.info("✅ AI Provider Factory 缓存已初始化(Redis,永不过期): 已加载 %d 个模型", len(cache_dict))
- logger.info("✅ 缓存重建成功: 已加载 %d 个模型", len(cache_dict))
+ logger.info("✅ 缓存重建成功(永不过期): 已加载 %d 个模型", len(cache_dict))
验证测试
测试 1: 懒加载验证
# 1. 清空缓存
docker exec jointo-server-redis redis-cli DEL "ai_models:provider_cache"
# 2. 执行测试
docker exec jointo-server-app python tests/manual/test_cache_lazy_loading.py
# 预期结果
⚠️ Redis 缓存为空,正在从数据库重建缓存...
✅ 缓存重建成功(永不过期): 已加载 21 个模型
测试 2: 永不过期验证
# 检查 TTL
docker exec jointo-server-redis redis-cli TTL "ai_models:provider_cache"
# 返回: -1 (表示永不过期)
运维指南
何时需要刷新缓存?
当执行以下操作后,需要手动刷新缓存:
- ✏️ 新增/删除 AI 模型
- ✏️ 修改模型配置(provider、capabilities)
- ✏️ 启用/禁用模型(
is_active)
刷新缓存的方法
方法 1: 代码中调用(推荐)
from app.services.ai_providers.factory import AIProviderFactory
# 在修改模型后立即刷新
await AIProviderFactory.refresh_cache(db)
方法 2: 重启应用
docker restart jointo-server-app
应用启动时会自动刷新缓存。
方法 3: 删除 Redis 键(触发懒加载)
docker exec jointo-server-redis redis-cli DEL "ai_models:provider_cache"
下次 AI 请求时会自动重建缓存。
性能影响
正常情况(缓存命中)
- Redis 查询: 1 次 GET(< 1ms)
- 数据库查询: 0 次
- 性能: 最优 ✅
缓存重建(懒加载触发)
- 数据库查询: 1 次(< 100ms,21 个模型)
- 频率: 仅在缓存被手动删除或 Redis 重启后触发
架构优势
- ✅ 零缓存失效 - 永不过期,应用可长期运行
- ✅ 性能最优 - 所有请求都从 Redis 读取
- ✅ 架构简单 - 无需管理 TTL,无需定时任务
- ✅ 可控刷新 - 管理员主动控制刷新时机
风险与缓解
风险 1: 忘记刷新缓存
缓解:
- ✅ 代码规范:模型更新时自动调用
refresh_cache() - ✅ 应用重启:部署新版本时自动刷新
- ✅ 懒加载兜底:缓存被删除时自动重建
风险 2: Redis 重启导致缓存丢失
缓解:
- ✅ 懒加载:自动从数据库重建
- ✅ Redis 持久化:生产环境已启用 RDB/AOF
后续优化建议
1. 自动刷新集成
在模型更新的 Service 层自动刷新缓存。
2. 监控告警
添加 Prometheus 指标:ai_cache_rebuilds_total
3. 管理后台
添加缓存管理界面(查看状态、手动刷新)
相关文件
修改文件
server/app/services/ai_providers/factory.py
新增文件
server/tests/manual/test_cache_lazy_loading.py
变更记录
- 2026-02-14 17:30: 升级为永不过期方案
- 2026-02-14 17:25: 初版(24h TTL + 懒加载)
- 修复人员: AI Assistant