220 lines
9.0 KiB
Markdown
220 lines
9.0 KiB
Markdown
# Redis缓存集成
|
||
|
||
<cite>
|
||
**本文档引用的文件**
|
||
- [redis.go](file://pkg/redis/redis.go)
|
||
- [manager.go](file://pkg/redis/manager.go)
|
||
- [config.go](file://pkg/config/config.go)
|
||
- [jwt.go](file://pkg/auth/jwt.go)
|
||
- [captcha_service.go](file://internal/service/captcha_service.go)
|
||
- [verification_service.go](file://internal/service/verification_service.go)
|
||
</cite>
|
||
|
||
## 目录
|
||
1. [项目结构](#项目结构)
|
||
2. [Redis客户端封装设计](#redis客户端封装设计)
|
||
3. [连接池与健康检查机制](#连接池与健康检查机制)
|
||
4. [缓存操作实现原理](#缓存操作实现原理)
|
||
5. [JWT令牌存储应用](#jwt令牌存储应用)
|
||
6. [会话管理与验证码应用](#会话管理与验证码应用)
|
||
7. [限流控制实现](#限流控制实现)
|
||
8. [缓存问题预防策略](#缓存问题预防策略)
|
||
9. [高可用架构支持](#高可用架构支持)
|
||
|
||
## 项目结构
|
||
|
||
```mermaid
|
||
graph TB
|
||
subgraph "pkg"
|
||
Redis[redis]
|
||
Config[config]
|
||
Auth[auth]
|
||
end
|
||
subgraph "internal"
|
||
Service[service]
|
||
Repository[repository]
|
||
end
|
||
Redis --> Service
|
||
Config --> Redis
|
||
Auth --> Service
|
||
Service --> Repository
|
||
```
|
||
|
||
**图示来源**
|
||
- [redis.go](file://pkg/redis/redis.go#L1-L175)
|
||
- [config.go](file://pkg/config/config.go#L1-L305)
|
||
- [captcha_service.go](file://internal/service/captcha_service.go#L1-L166)
|
||
|
||
## Redis客户端封装设计
|
||
|
||
CarrotSkin项目中的Redis客户端封装采用分层设计模式,通过`Client`结构体对`github.com/redis/go-redis/v9`库进行包装,提供更简洁的API接口。`Client`结构体包含`*redis.Client`指针和`*zap.Logger`日志记录器,实现了日志记录和错误处理的统一管理。
|
||
|
||
封装设计遵循单一职责原则,将Redis连接管理、操作执行和日志记录分离。通过`New`函数创建客户端实例时,会根据配置参数初始化连接,并执行连接测试,确保连接的可用性。这种设计模式提高了代码的可维护性和可测试性。
|
||
|
||
**本节来源**
|
||
- [redis.go](file://pkg/redis/redis.go#L15-L52)
|
||
- [manager.go](file://pkg/redis/manager.go#L11-L18)
|
||
|
||
## 连接池与健康检查机制
|
||
|
||
Redis连接池配置在`RedisConfig`结构体中定义,包含`Host`、`Port`、`Password`、`Database`和`PoolSize`等关键参数。连接池大小通过`PoolSize`字段配置,默认值为10,可根据实际负载情况进行调整。
|
||
|
||
健康检查机制在客户端初始化时实现,通过`Ping`命令测试连接可用性。使用`context.WithTimeout`设置5秒超时,防止连接测试阻塞主线程。连接成功后会记录包含主机、端口和数据库信息的日志,便于监控和故障排查。
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant App as 应用程序
|
||
participant Manager as Redis管理器
|
||
participant Client as Redis客户端
|
||
participant Redis as Redis服务器
|
||
App->>Manager : Init(cfg, logger)
|
||
Manager->>Client : New(cfg, logger)
|
||
Client->>Redis : Ping()
|
||
Redis-->>Client : PONG
|
||
Client-->>Manager : 返回客户端实例
|
||
Manager-->>App : 初始化完成
|
||
```
|
||
|
||
**图示来源**
|
||
- [redis.go](file://pkg/redis/redis.go#L22-L47)
|
||
- [config.go](file://pkg/config/config.go#L49-L56)
|
||
|
||
**本节来源**
|
||
- [redis.go](file://pkg/redis/redis.go#L22-L47)
|
||
- [config.go](file://pkg/config/config.go#L49-L56)
|
||
|
||
## 缓存操作实现原理
|
||
|
||
缓存操作通过`Client`结构体的方法实现,包括`Set`、`Get`、`Del`、`Exists`、`Expire`等基本操作。这些方法直接代理到底层`redis.Client`的对应方法,保持了与原生API的一致性。
|
||
|
||
`Set`方法接受`context.Context`、键、值和过期时间参数,支持设置键值对及其过期时间。`Get`方法返回字符串值和错误,通过`Nil`方法可以判断键不存在的情况。`Expire`方法用于修改现有键的过期时间,支持动态调整缓存策略。
|
||
|
||
```mermaid
|
||
classDiagram
|
||
class Client {
|
||
+*redis.Client
|
||
+*zap.Logger
|
||
+Set(ctx, key, value, expiration) error
|
||
+Get(ctx, key) (string, error)
|
||
+Del(ctx, keys) error
|
||
+Exists(ctx, keys) (int64, error)
|
||
+Expire(ctx, key, expiration) error
|
||
+Nil(err) bool
|
||
}
|
||
class RedisConfig {
|
||
+Host string
|
||
+Port int
|
||
+Password string
|
||
+Database int
|
||
+PoolSize int
|
||
}
|
||
Client --> RedisConfig : 使用
|
||
```
|
||
|
||
**图示来源**
|
||
- [redis.go](file://pkg/redis/redis.go#L60-L83)
|
||
- [config.go](file://pkg/config/config.go#L49-L56)
|
||
|
||
**本节来源**
|
||
- [redis.go](file://pkg/redis/redis.go#L60-L83)
|
||
|
||
## JWT令牌存储应用
|
||
|
||
JWT令牌存储利用Redis作为临时存储介质,通过`Set`方法将令牌与用户信息关联存储。令牌的过期时间与JWT的有效期保持一致,确保令牌在Redis中的生命周期与JWT一致。
|
||
|
||
在`jwt.go`中,JWT服务生成令牌后,可以通过Redis存储令牌的元数据,如用户ID、角色等信息。这种设计实现了无状态认证与有状态缓存的结合,既保持了JWT的无状态特性,又可以通过Redis快速验证令牌的有效性。
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant User as 用户
|
||
participant Auth as 认证服务
|
||
participant Redis as Redis缓存
|
||
User->>Auth : 登录请求
|
||
Auth->>Auth : 生成JWT令牌
|
||
Auth->>Redis : Set(token, userInfo, expireTime)
|
||
Redis-->>Auth : 存储成功
|
||
Auth-->>User : 返回JWT令牌
|
||
User->>Auth : 带JWT的请求
|
||
Auth->>Redis : Get(token)
|
||
Redis-->>Auth : 返回用户信息
|
||
Auth-->>User : 处理请求
|
||
```
|
||
|
||
**图示来源**
|
||
- [jwt.go](file://pkg/auth/jwt.go#L32-L52)
|
||
- [redis.go](file://pkg/redis/redis.go#L60-L63)
|
||
|
||
**本节来源**
|
||
- [jwt.go](file://pkg/auth/jwt.go#L32-L52)
|
||
- [redis.go](file://pkg/redis/redis.go#L60-L63)
|
||
|
||
## 会话管理与验证码应用
|
||
|
||
会话管理通过Redis存储会话数据,每个会话以唯一ID作为键,会话数据作为值进行存储。验证码应用在`captcha_service.go`中实现,使用`redisKeyPrefix = "captcha:"`作为键前缀,确保验证码数据的隔离性。
|
||
|
||
验证码生成时,将滑块的目标坐标等验证信息序列化后存储到Redis,设置300秒过期时间。验证时从Redis获取原始数据,与用户输入进行比对,验证成功后立即删除Redis记录,防止重复使用。
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Start([生成验证码]) --> Generate["生成滑块坐标(Tx,Ty)"]
|
||
Generate --> Serialize["序列化为JSON"]
|
||
Serialize --> Store["Set(captcha:id, json, 300s)"]
|
||
Store --> Return["返回验证码数据"]
|
||
Verify([验证验证码]) --> Get["Get(captcha:id)"]
|
||
Get --> Check{"是否存在?"}
|
||
Check --> |否| Expired["返回: 验证码已过期"]
|
||
Check --> |是| Parse["解析JSON数据"]
|
||
Parse --> Validate["验证用户输入"]
|
||
Validate --> Delete["Del(captcha:id)"]
|
||
Delete --> Result["返回验证结果"]
|
||
```
|
||
|
||
**图示来源**
|
||
- [captcha_service.go](file://internal/service/captcha_service.go#L75-L135)
|
||
- [redis.go](file://pkg/redis/redis.go#L60-L63)
|
||
|
||
**本节来源**
|
||
- [captcha_service.go](file://internal/service/captcha_service.go#L75-L135)
|
||
- [redis.go](file://pkg/redis/redis.go#L144-L146)
|
||
|
||
## 限流控制实现
|
||
|
||
限流控制在`verification_service.go`中实现,通过Redis的`Set`命令设置频率限制。使用`codeType`和`email`组合生成限流键,值设为"1",过期时间由`CodeRateLimit`常量定义。
|
||
|
||
当用户请求发送验证码时,先检查限流键是否存在,若存在则拒绝请求,防止频繁发送。这种基于Redis的限流机制简单高效,能够有效防止恶意刷屏攻击,保护系统资源。
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
Request[发送验证码请求] --> Check["Exists(verification:rate:email)"]
|
||
Check --> |存在| Reject[拒绝请求]
|
||
Check --> |不存在| Send[发送验证码]
|
||
Send --> Set["Set(verification:rate:email, 1, 60s)"]
|
||
Set --> Response[返回响应]
|
||
```
|
||
|
||
**图示来源**
|
||
- [verification_service.go](file://internal/service/verification_service.go#L58-L67)
|
||
- [redis.go](file://pkg/redis/redis.go#L75-L78)
|
||
|
||
**本节来源**
|
||
- [verification_service.go](file://internal/service/verification_service.go#L58-L67)
|
||
|
||
## 缓存问题预防策略
|
||
|
||
针对缓存穿透、雪崩、击穿问题,CarrotSkin采用多种预防策略。对于缓存穿透,使用`Nil`方法识别空值情况,避免频繁查询数据库。对于缓存雪崩,建议在配置中设置随机的过期时间偏移,避免大量缓存同时失效。
|
||
|
||
缓存击穿问题通过互斥锁或逻辑过期策略解决。当热点数据失效时,只允许一个请求加载数据,其他请求等待并使用旧数据,直到新数据加载完成。这种策略既保证了数据的一致性,又避免了数据库的瞬时压力。
|
||
|
||
**本节来源**
|
||
- [redis.go](file://pkg/redis/redis.go#L160-L162)
|
||
- [captcha_service.go](file://internal/service/captcha_service.go#L144-L145)
|
||
|
||
## 高可用架构支持
|
||
|
||
Redis高可用架构支持通过配置文件中的连接参数实现。虽然当前代码主要针对单机模式,但`github.com/redis/go-redis/v9`库原生支持哨兵模式和集群模式。通过修改配置,可以无缝切换到高可用架构。
|
||
|
||
连接故障恢复机制内置于客户端库中,自动处理网络抖动和临时故障。建议在生产环境中配置合理的超时时间和重试策略,确保系统的稳定性和可靠性。监控连接状态和性能指标,及时发现和解决潜在问题。
|
||
|
||
**本节来源**
|
||
- [redis.go](file://pkg/redis/redis.go#L24-L32)
|
||
- [config.go](file://pkg/config/config.go#L49-L56) |