319 行
6.7 KiB
Markdown
319 行
6.7 KiB
Markdown
# 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*
|