# T038 缓存池实现 > 审查Agent:MiMo > 日期:2026-07-03 > 审查范围:Redis/Valkey缓存系统设计 --- ## 一、缓存系统架构 ### 1.1 缓存层级 ``` ┌─────────────────────────────────────┐ │ 应用层缓存 │ │ (Go进程内缓存, TTL短) │ ├─────────────────────────────────────┤ │ Redis/Valkey缓存 │ │ (分布式缓存, TTL中) │ ├─────────────────────────────────────┤ │ PostgreSQL数据库 │ │ (持久化存储, 查询慢) │ └─────────────────────────────────────┘ ``` ### 1.2 缓存策略 | 数据类型 | 缓存位置 | TTL | 更新策略 | |---------|---------|-----|---------| | 角色信息 | Redis | 5分钟 | 写时失效 | | 会话数据 | Redis | 30分钟 | 写时失效 | | 配置数据 | Redis | 1小时 | 定时刷新 | | 战斗数据 | Redis | 10分钟 | 写时失效 | | 排行榜 | Redis | 1分钟 | 实时更新 | --- ## 二、缓存Key设计 ### 2.1 Key命名规范 ``` {模块}:{类型}:{ID} ``` ### 2.2 Key列表 | 模块 | Key格式 | TTL | 说明 | |------|---------|-----|------| | 角色 | `char:{id}` | 5min | 角色基本信息 | | 角色属性 | `char:{id}:stats` | 5min | 角色战斗属性 | | 会话 | `session:{id}` | 30min | 玩家会话数据 | | 功法 | `manual:{char_id}:{id}` | 5min | 功法实例数据 | | 技能 | `skill:{char_id}:{id}` | 5min | 技能实例数据 | | 货币 | `currency:{char_id}` | 5min | 货币余额 | | 排行榜 | `rank:{type}:{tier}` | 1min | 各类排行榜 | | 战斗 | `battle:{id}` | 10min | 战斗记录 | | 配置 | `config:{key}` | 1hour | 配置数据 | --- ## 三、缓存操作封装 ### 3.1 基础操作 ```go // 缓存操作接口 type CacheInterface interface { Get(key string) (string, error) Set(key string, value string, ttl time.Duration) error Del(key string) error Exists(key string) (bool, error) Incr(key string) (int64, error) Expire(key string, ttl time.Duration) error } // Redis实现 type RedisCache struct { client *redis.Client } func (c *RedisCache) Get(key string) (string, error) { return c.client.Get(ctx, key).Result() } func (c *RedisCache) Set(key string, value string, ttl time.Duration) error { return c.client.Set(ctx, key, value, ttl).Err() } func (c *RedisCache) Del(key string) error { return c.client.Del(ctx, key).Err() } ``` ### 3.2 业务封装 ```go // 角色缓存 func GetCharacterCache(charID string) (*Character, error) { key := "char:" + charID data, err := cache.Get(key) if err != nil { // 缓存未命中,从数据库加载 char, err := loadCharacterFromDB(charID) if err != nil { return nil, err } // 写入缓存 cache.Set(key, json.Marshal(char), 5*time.Minute) return char, nil } var char Character json.Unmarshal([]byte(data), &char) return &char, nil } func SetCharacterCache(charID string, char *Character) error { key := "char:" + charID data, _ := json.Marshal(char) return cache.Set(key, string(data), 5*time.Minute) } func InvalidateCharacterCache(charID string) error { keys := []string{ "char:" + charID, "char:" + charID + ":stats", "currency:" + charID, } return cache.Del(keys...) } ``` --- ## 四、缓存一致性 ### 4.1 写时失效策略 当数据更新时,立即失效相关缓存: ```go func UpdateCharacter(charID string, data map[string]interface{}) error { // 1. 更新数据库 err := updateDB(charID, data) if err != nil { return err } // 2. 失效缓存 InvalidateCharacterCache(charID) return nil } ``` ### 4.2 缓存穿透防护 ```go // 防止缓存穿透:查询不存在的数据时,缓存空值 func GetWithProtection(key string) (string, error) { data, err := cache.Get(key) if err == redis.Nil { // 缓存未命中 data, err := loadFromDB(key) if err != nil { // 数据不存在,缓存空值(短TTL) cache.Set(key, "", 1*time.Minute) return "", nil } cache.Set(key, data, 5*time.Minute) return data, nil } return data, err } ``` --- ## 五、缓存监控 ### 5.1 监控指标 | 指标 | 说明 | 告警阈值 | |------|------|---------| | 命中率 | 缓存命中/总请求 | <80% | | 内存使用 | Redis内存使用量 | >80% | | 连接数 | Redis连接数 | >1000 | | 延迟 | 缓存操作延迟 | >10ms | ### 5.2 监控命令 ```bash # 查看Redis状态 redis-cli info memory # 查看命中率 redis-cli info stats | grep keyspace_hits # 查看连接数 redis-cli info clients ``` --- ## 六、缓存预热 ### 6.1 启动预热 ```go func WarmupCache() { // 预热配置数据 loadConfigCache() // 预热排行榜 loadRankCache() // 预热热门角色 loadHotCharacters() } ``` ### 6.2 定时刷新 ```go // 定时刷新配置缓存 go func() { ticker := time.NewTicker(1 * time.Hour) for range ticker.C { loadConfigCache() } }() ``` --- ## 七、缓存配置 ### 7.1 Redis配置 ```yaml redis: addr: "localhost:6379" password: "" db: 0 pool_size: 10 min_idle_conns: 5 max_retries: 3 retry_delay: 100ms ``` ### 7.2 缓存配置 ```yaml cache: character_ttl: 5m session_ttl: 30m config_ttl: 1h battle_ttl: 10m rank_ttl: 1m max_memory: 1gb eviction_policy: allkeys-lru ``` --- ## 八、性能优化 ### 8.1 批量操作 ```go // 批量获取 func GetMulti(keys []string) (map[string]string, error) { return cache.MGet(keys...) } // 批量设置 func SetMulti(data map[string]string, ttl time.Duration) error { pipe := cache.Pipeline() for k, v := range data { pipe.Set(ctx, k, v, ttl) } _, err := pipe.Exec(ctx) return err } ``` ### 8.2 本地缓存 ```go // 使用Go自带的sync.Map作为L1缓存 var localCache sync.Map func GetWithLocalCache(key string) (string, error) { // L1: 本地缓存 if val, ok := localCache.Load(key); ok { return val.(string), nil } // L2: Redis缓存 data, err := cache.Get(key) if err != nil { return "", err } // 写入L1缓存(短TTL) localCache.Store(key, data) go func() { time.Sleep(30 * time.Second) localCache.Delete(key) }() return data, nil } ``` --- *缓存池实现 v1.0 | 2026-07-03 | T038*