6.7 KiB
6.7 KiB
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 基础操作
// 缓存操作接口
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 业务封装
// 角色缓存
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 写时失效策略
当数据更新时,立即失效相关缓存:
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 缓存穿透防护
// 防止缓存穿透:查询不存在的数据时,缓存空值
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 监控命令
# 查看Redis状态
redis-cli info memory
# 查看命中率
redis-cli info stats | grep keyspace_hits
# 查看连接数
redis-cli info clients
六、缓存预热
6.1 启动预热
func WarmupCache() {
// 预热配置数据
loadConfigCache()
// 预热排行榜
loadRankCache()
// 预热热门角色
loadHotCharacters()
}
6.2 定时刷新
// 定时刷新配置缓存
go func() {
ticker := time.NewTicker(1 * time.Hour)
for range ticker.C {
loadConfigCache()
}
}()
七、缓存配置
7.1 Redis配置
redis:
addr: "localhost:6379"
password: ""
db: 0
pool_size: 10
min_idle_conns: 5
max_retries: 3
retry_delay: 100ms
7.2 缓存配置
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 批量操作
// 批量获取
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自带的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