1498 lines
33 KiB
Markdown
1498 lines
33 KiB
Markdown
# Go-Zero 框架 Redis 配置完全指南
|
||
|
||
**框架版本:** go-zero v1.5+
|
||
**Redis 版本:** 7.0.12
|
||
**部署环境:** Kubernetes (juwan namespace)
|
||
**文档日期:** 2026年2月22日
|
||
|
||
---
|
||
|
||
## 📋 目录
|
||
|
||
1. [配置概览](#配置概览)
|
||
2. [单节点模式](#单节点模式)
|
||
3. [Sentinel 哨兵模式](#sentinel-哨兵模式)
|
||
4. [集群模式](#集群模式)
|
||
5. [配置项详解](#配置项详解)
|
||
6. [代码实现](#代码实现)
|
||
7. [常用操作示例](#常用操作示例)
|
||
8. [高级特性](#高级特性)
|
||
9. [性能优化](#性能优化)
|
||
10. [故障排查](#故障排查)
|
||
11. [最佳实践](#最佳实践)
|
||
|
||
---
|
||
|
||
## 🎯 配置概览
|
||
|
||
### Go-Zero Redis 支持的模式
|
||
|
||
| 模式 | Type 值 | 用途 | 高可用 | 推荐度 |
|
||
|-----|---------|------|--------|--------|
|
||
| **单节点** | `node` | 开发/测试 | ❌ | ⭐⭐ |
|
||
| **Sentinel** | `sentinel` | 生产环境 | ✅ | ⭐⭐⭐⭐⭐ |
|
||
| **集群** | `cluster` | 大规模分片 | ✅ | ⭐⭐⭐⭐ |
|
||
|
||
### 配置文件位置
|
||
|
||
```
|
||
app/users/rpc/
|
||
├── etc/
|
||
│ └── pb.yaml ← Redis 配置写在这里
|
||
├── internal/
|
||
│ ├── config/
|
||
│ │ └── config.go ← 定义配置结构
|
||
│ └── svc/
|
||
│ └── serviceContext.go ← 初始化 Redis 客户端
|
||
└── pb.go
|
||
```
|
||
|
||
---
|
||
|
||
## 🔵 单节点模式
|
||
|
||
### 适用场景
|
||
|
||
- ✅ 开发环境
|
||
- ✅ 测试环境
|
||
- ✅ POC 演示
|
||
- ❌ 生产环境(无高可用)
|
||
|
||
### 配置文件
|
||
|
||
**`app/users/rpc/etc/pb.yaml`**
|
||
```yaml
|
||
Name: user.rpc
|
||
ListenOn: 0.0.0.0:9001
|
||
|
||
# Redis 单节点配置
|
||
Redis:
|
||
Host: user-redis-master.juwan.svc.cluster.local:6379
|
||
Type: node
|
||
Pass: ${REDIS_PASSWORD} # 从环境变量读取
|
||
# Db: 0 # 可选,默认 0
|
||
# MaxIdle: 8 # 可选,连接池最大闲置连接数
|
||
# MaxActive: 0 # 可选,连接池最大活跃连接数,0 表示无限制
|
||
|
||
Etcd:
|
||
Hosts:
|
||
- etcd-service.juwan.svc.cluster.local:2379
|
||
Key: user.rpc
|
||
```
|
||
|
||
### Config 结构
|
||
|
||
**`app/users/rpc/internal/config/config.go`**
|
||
```go
|
||
package config
|
||
|
||
import (
|
||
"github.com/zeromicro/go-zero/core/stores/redis"
|
||
"github.com/zeromicro/go-zero/zrpc"
|
||
)
|
||
|
||
type Config struct {
|
||
zrpc.RpcServerConf
|
||
Redis redis.RedisConf // Redis 配置
|
||
}
|
||
```
|
||
|
||
### ServiceContext 初始化
|
||
|
||
**`app/users/rpc/internal/svc/serviceContext.go`**
|
||
```go
|
||
package svc
|
||
|
||
import (
|
||
"github.com/zeromicro/go-zero/core/stores/redis"
|
||
"juwan-backend/app/users/rpc/internal/config"
|
||
)
|
||
|
||
type ServiceContext struct {
|
||
Config config.Config
|
||
Redis *redis.Redis
|
||
}
|
||
|
||
func NewServiceContext(c config.Config) *ServiceContext {
|
||
return &ServiceContext{
|
||
Config: c,
|
||
Redis: redis.MustNewRedis(c.Redis), // 初始化 Redis
|
||
}
|
||
}
|
||
```
|
||
|
||
### 使用示例
|
||
|
||
**`app/users/rpc/internal/logic/getUsersByIdLogic.go`**
|
||
```go
|
||
package logic
|
||
|
||
import (
|
||
"context"
|
||
"encoding/json"
|
||
"fmt"
|
||
"time"
|
||
|
||
"juwan-backend/app/users/rpc/internal/svc"
|
||
"juwan-backend/app/users/rpc/pb"
|
||
|
||
"github.com/zeromicro/go-zero/core/logx"
|
||
)
|
||
|
||
type GetUsersByIdLogic struct {
|
||
ctx context.Context
|
||
svcCtx *svc.ServiceContext
|
||
logx.Logger
|
||
}
|
||
|
||
func NewGetUsersByIdLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUsersByIdLogic {
|
||
return &GetUsersByIdLogic{
|
||
ctx: ctx,
|
||
svcCtx: svcCtx,
|
||
Logger: logx.WithContext(ctx),
|
||
}
|
||
}
|
||
|
||
func (l *GetUsersByIdLogic) GetUsersById(in *pb.GetUsersByIdReq) (*pb.GetUsersByIdResp, error) {
|
||
// 缓存 key
|
||
cacheKey := fmt.Sprintf("user:%d", in.Id)
|
||
|
||
// 1. 尝试从缓存获取
|
||
cached, err := l.svcCtx.Redis.Get(cacheKey)
|
||
if err == nil && cached != "" {
|
||
// 缓存命中
|
||
var user pb.User
|
||
if err := json.Unmarshal([]byte(cached), &user); err == nil {
|
||
l.Logger.Infof("Cache hit for user:%d", in.Id)
|
||
return &pb.GetUsersByIdResp{User: &user}, nil
|
||
}
|
||
}
|
||
|
||
// 2. 缓存未命中,从数据库查询
|
||
l.Logger.Infof("Cache miss for user:%d, querying DB", in.Id)
|
||
user := l.fetchUserFromDB(in.Id)
|
||
if user == nil {
|
||
return nil, fmt.Errorf("user not found")
|
||
}
|
||
|
||
// 3. 写入缓存(1小时过期)
|
||
userJSON, _ := json.Marshal(user)
|
||
err = l.svcCtx.Redis.Setex(cacheKey, string(userJSON), 3600)
|
||
if err != nil {
|
||
l.Logger.Errorf("Failed to set cache: %v", err)
|
||
}
|
||
|
||
return &pb.GetUsersByIdResp{User: user}, nil
|
||
}
|
||
|
||
func (l *GetUsersByIdLogic) fetchUserFromDB(id int64) *pb.User {
|
||
// 实际从数据库查询
|
||
// ...
|
||
return &pb.User{Id: id, Name: "John Doe"}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🟡 Sentinel 哨兵模式
|
||
|
||
### 适用场景
|
||
|
||
- ✅✅✅ **生产环境强烈推荐**
|
||
- ✅ 自动故障转移
|
||
- ✅ 高可用架构
|
||
- ✅ 主从自动切换
|
||
|
||
### 配置文件
|
||
|
||
**`app/users/rpc/etc/pb.yaml`**
|
||
```yaml
|
||
Name: user.rpc
|
||
ListenOn: 0.0.0.0:9001
|
||
|
||
# Redis Sentinel 配置(推荐生产环境使用)
|
||
Redis:
|
||
- Host: user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379
|
||
Type: sentinel
|
||
Pass: ${REDIS_PASSWORD}
|
||
|
||
# 或者使用完整配置
|
||
# Redis:
|
||
# Host: user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379
|
||
# Type: sentinel
|
||
# Pass: ${REDIS_PASSWORD}
|
||
# # Sentinel 特有配置
|
||
# MasterName: mymaster # Sentinel 主节点名称,默认 mymaster
|
||
|
||
Etcd:
|
||
Hosts:
|
||
- etcd-service.juwan.svc.cluster.local:2379
|
||
Key: user.rpc
|
||
```
|
||
|
||
### Config 结构(同单节点)
|
||
|
||
**`app/users/rpc/internal/config/config.go`**
|
||
```go
|
||
package config
|
||
|
||
import (
|
||
"github.com/zeromicro/go-zero/core/stores/redis"
|
||
"github.com/zeromicro/go-zero/zrpc"
|
||
)
|
||
|
||
type Config struct {
|
||
zrpc.RpcServerConf
|
||
Redis redis.RedisConf // 支持所有模式
|
||
}
|
||
```
|
||
|
||
### ServiceContext 初始化(同单节点)
|
||
|
||
**`app/users/rpc/internal/svc/serviceContext.go`**
|
||
```go
|
||
package svc
|
||
|
||
import (
|
||
"github.com/zeromicro/go-zero/core/stores/redis"
|
||
"juwan-backend/app/users/rpc/internal/config"
|
||
)
|
||
|
||
type ServiceContext struct {
|
||
Config config.Config
|
||
Redis *redis.Redis
|
||
}
|
||
|
||
func NewServiceContext(c config.Config) *ServiceContext {
|
||
// go-zero 会根据 Type 自动选择连接模式
|
||
return &ServiceContext{
|
||
Config: c,
|
||
Redis: redis.MustNewRedis(c.Redis),
|
||
}
|
||
}
|
||
```
|
||
|
||
### Sentinel 配置详解
|
||
|
||
**完整配置选项:**
|
||
```yaml
|
||
Redis:
|
||
Host: user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379
|
||
Type: sentinel
|
||
Pass: ${REDIS_PASSWORD}
|
||
|
||
# Sentinel 特有配置
|
||
MasterName: mymaster # Sentinel 监控的主节点名称
|
||
|
||
# 连接池配置(可选)
|
||
MaxIdle: 8 # 最大闲置连接数
|
||
MaxActive: 0 # 最大活跃连接数,0 表示无限制
|
||
IdleTimeout: 300 # 闲置连接超时时间(秒)
|
||
|
||
# 超时配置(可选)
|
||
ConnectTimeout: 5000 # 连接超时(毫秒)
|
||
ReadTimeout: 3000 # 读超时(毫秒)
|
||
WriteTimeout: 3000 # 写超时(毫秒)
|
||
```
|
||
|
||
### 优势说明
|
||
|
||
```go
|
||
// Sentinel 模式的自动故障处理流程:
|
||
|
||
// 1. 应用连接到 Sentinel
|
||
app → Sentinel Service (26379)
|
||
|
||
// 2. Sentinel 返回当前主节点地址
|
||
Sentinel → app: "主节点在 10.244.1.10:6379"
|
||
|
||
// 3. 应用连接到主节点进行读写
|
||
app → Redis Master (10.244.1.10:6379)
|
||
|
||
// 4. 主节点故障,Sentinel 检测到
|
||
Redis Master (✗ 宕机)
|
||
Sentinel → 检测 → 投票 → 提升新主节点
|
||
|
||
// 5. 应用下次请求时自动连接到新主节点
|
||
app → Sentinel → "新主节点在 10.244.2.20:6379"
|
||
app → New Redis Master (10.244.2.20:6379)
|
||
|
||
// 整个过程应用无需重启,自动完成切换!
|
||
```
|
||
|
||
---
|
||
|
||
## 🔴 集群模式
|
||
|
||
### 适用场景
|
||
|
||
- ✅ 大规模数据(需要分片)
|
||
- ✅ 超高并发
|
||
- ✅ 数据量超过单机内存
|
||
- ⚠️ 配置和运维复杂度高
|
||
|
||
### 配置文件
|
||
|
||
**`app/users/rpc/etc/pb.yaml`**
|
||
```yaml
|
||
Name: user.rpc
|
||
ListenOn: 0.0.0.0:9001
|
||
|
||
# Redis Cluster 配置
|
||
Redis:
|
||
- Host: redis-cluster-0.redis-cluster.juwan.svc.cluster.local:6379
|
||
- Host: redis-cluster-1.redis-cluster.juwan.svc.cluster.local:6379
|
||
- Host: redis-cluster-2.redis-cluster.juwan.svc.cluster.local:6379
|
||
Type: cluster
|
||
Pass: ${REDIS_PASSWORD}
|
||
|
||
Etcd:
|
||
Hosts:
|
||
- etcd-service.juwan.svc.cluster.local:2379
|
||
Key: user.rpc
|
||
```
|
||
|
||
### Config 结构
|
||
|
||
**`app/users/rpc/internal/config/config.go`**
|
||
```go
|
||
package config
|
||
|
||
import (
|
||
"github.com/zeromicro/go-zero/core/stores/redis"
|
||
"github.com/zeromicro/go-zero/zrpc"
|
||
)
|
||
|
||
type Config struct {
|
||
zrpc.RpcServerConf
|
||
Redis redis.RedisConf
|
||
}
|
||
```
|
||
|
||
### 集群模式特点
|
||
|
||
**数据分片:**
|
||
```
|
||
应用请求
|
||
↓
|
||
根据 key 计算 hash slot (0-16383)
|
||
↓
|
||
路由到对应的分片节点
|
||
↓
|
||
┌─────────┬─────────┬─────────┐
|
||
│ Shard 1 │ Shard 2 │ Shard 3 │
|
||
│ 0-5460 │5461-10922│10923-16383│
|
||
└─────────┴─────────┴─────────┘
|
||
```
|
||
|
||
**注意事项:**
|
||
- ❌ 不支持多 key 操作(如 MGET, MSET)跨分片
|
||
- ❌ 不支持事务(MULTI/EXEC)跨分片
|
||
- ✅ 单 key 操作完全正常
|
||
- ✅ 支持 hash tag 控制 key 分布
|
||
|
||
---
|
||
|
||
## 📚 配置项详解
|
||
|
||
### redis.RedisConf 完整配置
|
||
|
||
**结构定义:**
|
||
```go
|
||
type RedisConf struct {
|
||
Host string // Redis 地址
|
||
Type string // 类型: node, sentinel, cluster
|
||
Pass string // 密码
|
||
Db int // 数据库编号 (0-15),cluster 模式不支持
|
||
|
||
// Sentinel 模式专用
|
||
MasterName string // Sentinel 主节点名称
|
||
|
||
// 连接池配置
|
||
MaxIdle int // 最大闲置连接数
|
||
MaxActive int // 最大活跃连接数,0 表示无限制
|
||
IdleTimeout time.Duration // 闲置连接超时
|
||
|
||
// 超时配置
|
||
ConnectTimeout time.Duration // 连接超时
|
||
ReadTimeout time.Duration // 读超时
|
||
WriteTimeout time.Duration // 写超时
|
||
|
||
// TLS 配置(可选)
|
||
Tls bool // 是否启用 TLS
|
||
}
|
||
```
|
||
|
||
### 各配置项说明
|
||
|
||
#### 1. Host(必填)
|
||
|
||
**单节点模式:**
|
||
```yaml
|
||
Redis:
|
||
Host: user-redis-master.juwan.svc.cluster.local:6379
|
||
```
|
||
|
||
**Sentinel 模式:**
|
||
```yaml
|
||
Redis:
|
||
Host: user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379
|
||
# 注意:这里填 Sentinel 地址(端口 26379),不是 Redis 地址
|
||
```
|
||
|
||
**集群模式:**
|
||
```yaml
|
||
Redis:
|
||
# 可以填任意一个节点,客户端会自动发现其他节点
|
||
- Host: redis-cluster-0:6379
|
||
- Host: redis-cluster-1:6379
|
||
- Host: redis-cluster-2:6379
|
||
```
|
||
|
||
#### 2. Type(必填)
|
||
|
||
| 值 | 说明 |
|
||
|----|------|
|
||
| `node` | 单节点模式 |
|
||
| `sentinel` | Sentinel 哨兵模式 |
|
||
| `cluster` | 集群模式 |
|
||
|
||
#### 3. Pass(强烈推荐)
|
||
|
||
**从环境变量读取(推荐):**
|
||
```yaml
|
||
Redis:
|
||
Pass: ${REDIS_PASSWORD}
|
||
```
|
||
|
||
**硬编码(不推荐):**
|
||
```yaml
|
||
Redis:
|
||
Pass: "your-password" # ❌ 不安全
|
||
```
|
||
|
||
#### 4. Db(可选,默认 0)
|
||
|
||
**适用模式:** 仅 `node` 和 `sentinel` 模式
|
||
|
||
```yaml
|
||
Redis:
|
||
Db: 0 # 数据库编号 0-15
|
||
```
|
||
|
||
**注意:**
|
||
- ❌ Cluster 模式不支持多数据库
|
||
- ✅ 单节点和 Sentinel 支持 0-15
|
||
|
||
#### 5. MaxIdle(可选,默认 8)
|
||
|
||
```yaml
|
||
Redis:
|
||
MaxIdle: 8 # 连接池中最大闲置连接数
|
||
```
|
||
|
||
**建议值:**
|
||
- 低并发:`8`
|
||
- 中并发:`16`
|
||
- 高并发:`32` 或 `CPU 核心数 * 2`
|
||
|
||
#### 6. MaxActive(可选,默认 0)
|
||
|
||
```yaml
|
||
Redis:
|
||
MaxActive: 0 # 0 表示无限制
|
||
# MaxActive: 100 # 或设置一个上限
|
||
```
|
||
|
||
**建议值:**
|
||
- 开发环境:`0`(无限制)
|
||
- 生产环境:`100-500`(根据实际负载)
|
||
|
||
#### 7. IdleTimeout(可选,默认 300 秒)
|
||
|
||
```yaml
|
||
Redis:
|
||
IdleTimeout: 300 # 秒
|
||
```
|
||
|
||
**说明:** 闲置连接超过此时间会被关闭
|
||
|
||
#### 8. 超时配置(可选)
|
||
|
||
```yaml
|
||
Redis:
|
||
ConnectTimeout: 5000 # 连接超时 5 秒
|
||
ReadTimeout: 3000 # 读超时 3 秒
|
||
WriteTimeout: 3000 # 写超时 3 秒
|
||
```
|
||
|
||
---
|
||
|
||
## 💻 代码实现
|
||
|
||
### 完整项目结构
|
||
|
||
```
|
||
app/users/rpc/
|
||
├── etc/
|
||
│ ├── pb.yaml # 开发环境配置
|
||
│ └── pb-prod.yaml # 生产环境配置
|
||
├── internal/
|
||
│ ├── config/
|
||
│ │ └── config.go # 配置结构定义
|
||
│ ├── svc/
|
||
│ │ └── serviceContext.go # 服务上下文(初始化 Redis)
|
||
│ ├── logic/
|
||
│ │ ├── addUsersLogic.go
|
||
│ │ ├── getUsersByIdLogic.go
|
||
│ │ └── ...
|
||
│ └── server/
|
||
│ └── usercenterServer.go
|
||
├── pb/
|
||
│ ├── users.pb.go
|
||
│ └── users_grpc.pb.go
|
||
└── usercenter.go # 主程序入口
|
||
```
|
||
|
||
### 1. 配置文件示例
|
||
|
||
**开发环境 `etc/pb.yaml`:**
|
||
```yaml
|
||
Name: user.rpc
|
||
ListenOn: 0.0.0.0:9001
|
||
|
||
# 开发环境使用单节点
|
||
Redis:
|
||
Host: localhost:6379
|
||
Type: node
|
||
Pass: dev_password
|
||
Db: 0
|
||
|
||
Etcd:
|
||
Hosts:
|
||
- localhost:2379
|
||
Key: user.rpc
|
||
|
||
Log:
|
||
Level: info
|
||
Mode: console
|
||
```
|
||
|
||
**生产环境 `etc/pb-prod.yaml`:**
|
||
```yaml
|
||
Name: user.rpc
|
||
ListenOn: 0.0.0.0:9001
|
||
|
||
# 生产环境使用 Sentinel
|
||
Redis:
|
||
Host: user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379
|
||
Type: sentinel
|
||
Pass: ${REDIS_PASSWORD}
|
||
MasterName: mymaster
|
||
MaxIdle: 16
|
||
MaxActive: 100
|
||
IdleTimeout: 300
|
||
ConnectTimeout: 5000
|
||
ReadTimeout: 3000
|
||
WriteTimeout: 3000
|
||
|
||
Etcd:
|
||
Hosts:
|
||
- etcd-0.etcd.juwan.svc.cluster.local:2379
|
||
- etcd-1.etcd.juwan.svc.cluster.local:2379
|
||
- etcd-2.etcd.juwan.svc.cluster.local:2379
|
||
Key: user.rpc
|
||
|
||
Log:
|
||
Level: error
|
||
Mode: file
|
||
Path: /var/log/user-rpc
|
||
KeepDays: 7
|
||
```
|
||
|
||
### 2. Config 定义
|
||
|
||
**`internal/config/config.go`**
|
||
```go
|
||
package config
|
||
|
||
import (
|
||
"github.com/zeromicro/go-zero/core/stores/redis"
|
||
"github.com/zeromicro/go-zero/zrpc"
|
||
)
|
||
|
||
type Config struct {
|
||
zrpc.RpcServerConf
|
||
|
||
// Redis 配置
|
||
Redis redis.RedisConf
|
||
|
||
// 其他配置...
|
||
// DB postgres.Config
|
||
// Kafka kafka.Config
|
||
}
|
||
```
|
||
|
||
### 3. ServiceContext 初始化
|
||
|
||
**`internal/svc/serviceContext.go`**
|
||
```go
|
||
package svc
|
||
|
||
import (
|
||
"github.com/zeromicro/go-zero/core/stores/redis"
|
||
"juwan-backend/app/users/rpc/internal/config"
|
||
)
|
||
|
||
type ServiceContext struct {
|
||
Config config.Config
|
||
Redis *redis.Redis
|
||
// 其他依赖...
|
||
// DB *gorm.DB
|
||
}
|
||
|
||
func NewServiceContext(c config.Config) *ServiceContext {
|
||
// 初始化 Redis(支持所有模式:node, sentinel, cluster)
|
||
rdb := redis.MustNewRedis(c.Redis)
|
||
|
||
return &ServiceContext{
|
||
Config: c,
|
||
Redis: rdb,
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4. 主程序入口
|
||
|
||
**`usercenter.go`**
|
||
```go
|
||
package main
|
||
|
||
import (
|
||
"flag"
|
||
"fmt"
|
||
|
||
"juwan-backend/app/users/rpc/internal/config"
|
||
"juwan-backend/app/users/rpc/internal/server"
|
||
"juwan-backend/app/users/rpc/internal/svc"
|
||
"juwan-backend/app/users/rpc/pb"
|
||
|
||
"github.com/zeromicro/go-zero/core/conf"
|
||
"github.com/zeromicro/go-zero/core/service"
|
||
"github.com/zeromicro/go-zero/zrpc"
|
||
"google.golang.org/grpc"
|
||
"google.golang.org/grpc/reflection"
|
||
)
|
||
|
||
var configFile = flag.String("f", "etc/pb.yaml", "the config file")
|
||
|
||
func main() {
|
||
flag.Parse()
|
||
|
||
// 加载配置
|
||
var c config.Config
|
||
conf.MustLoad(*configFile, &c)
|
||
|
||
// 初始化服务上下文
|
||
ctx := svc.NewServiceContext(c)
|
||
|
||
// 创建 gRPC 服务
|
||
s := zrpc.MustNewServer(c.RpcServerConf, func(grpcServer *grpc.Server) {
|
||
pb.RegisterUsercenterServer(grpcServer, server.NewUsercenterServer(ctx))
|
||
|
||
if c.Mode == service.DevMode || c.Mode == service.TestMode {
|
||
reflection.Register(grpcServer)
|
||
}
|
||
})
|
||
defer s.Stop()
|
||
|
||
fmt.Printf("Starting rpc server at %s...\n", c.ListenOn)
|
||
s.Start()
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🔧 常用操作示例
|
||
|
||
### 1. 基本读写操作
|
||
|
||
```go
|
||
package logic
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"time"
|
||
)
|
||
|
||
type UserLogic struct {
|
||
ctx context.Context
|
||
svcCtx *svc.ServiceContext
|
||
logx.Logger
|
||
}
|
||
|
||
// Set 操作
|
||
func (l *UserLogic) SetUser(userId int64, data string) error {
|
||
key := fmt.Sprintf("user:%d", userId)
|
||
return l.svcCtx.Redis.Set(key, data)
|
||
}
|
||
|
||
// Setex 操作(带过期时间)
|
||
func (l *UserLogic) SetUserWithExpiry(userId int64, data string) error {
|
||
key := fmt.Sprintf("user:%d", userId)
|
||
// 缓存 1 小时
|
||
return l.svcCtx.Redis.Setex(key, data, 3600)
|
||
}
|
||
|
||
// Get 操作
|
||
func (l *UserLogic) GetUser(userId int64) (string, error) {
|
||
key := fmt.Sprintf("user:%d", userId)
|
||
return l.svcCtx.Redis.Get(key)
|
||
}
|
||
|
||
// Del 操作
|
||
func (l *UserLogic) DeleteUser(userId int64) error {
|
||
key := fmt.Sprintf("user:%d", userId)
|
||
_, err := l.svcCtx.Redis.Del(key)
|
||
return err
|
||
}
|
||
|
||
// Exists 检查
|
||
func (l *UserLogic) UserExists(userId int64) (bool, error) {
|
||
key := fmt.Sprintf("user:%d", userId)
|
||
return l.svcCtx.Redis.Exists(key)
|
||
}
|
||
```
|
||
|
||
### 2. Hash 操作
|
||
|
||
```go
|
||
// HSet 操作
|
||
func (l *UserLogic) SetUserField(userId int64, field, value string) error {
|
||
key := fmt.Sprintf("user:%d", userId)
|
||
return l.svcCtx.Redis.Hset(key, field, value)
|
||
}
|
||
|
||
// HGet 操作
|
||
func (l *UserLogic) GetUserField(userId int64, field string) (string, error) {
|
||
key := fmt.Sprintf("user:%d", userId)
|
||
return l.svcCtx.Redis.Hget(key, field)
|
||
}
|
||
|
||
// HGetAll 操作
|
||
func (l *UserLogic) GetAllUserFields(userId int64) (map[string]string, error) {
|
||
key := fmt.Sprintf("user:%d", userId)
|
||
return l.svcCtx.Redis.Hgetall(key)
|
||
}
|
||
|
||
// HMSet 批量设置
|
||
func (l *UserLogic) SetUserFields(userId int64, fields map[string]string) error {
|
||
key := fmt.Sprintf("user:%d", userId)
|
||
return l.svcCtx.Redis.Hmset(key, fields)
|
||
}
|
||
```
|
||
|
||
### 3. List 操作
|
||
|
||
```go
|
||
// LPush 操作
|
||
func (l *UserLogic) AddMessage(userId int64, message string) error {
|
||
key := fmt.Sprintf("messages:%d", userId)
|
||
_, err := l.svcCtx.Redis.Lpush(key, message)
|
||
return err
|
||
}
|
||
|
||
// LRange 操作
|
||
func (l *UserLogic) GetMessages(userId int64, start, stop int) ([]string, error) {
|
||
key := fmt.Sprintf("messages:%d", userId)
|
||
return l.svcCtx.Redis.Lrange(key, start, stop)
|
||
}
|
||
|
||
// LLen 操作
|
||
func (l *UserLogic) GetMessageCount(userId int64) (int, error) {
|
||
key := fmt.Sprintf("messages:%d", userId)
|
||
return l.svcCtx.Redis.Llen(key)
|
||
}
|
||
```
|
||
|
||
### 4. Set 操作
|
||
|
||
```go
|
||
// SAdd 添加成员
|
||
func (l *UserLogic) AddUserTag(userId int64, tag string) error {
|
||
key := fmt.Sprintf("user:tags:%d", userId)
|
||
_, err := l.svcCtx.Redis.Sadd(key, tag)
|
||
return err
|
||
}
|
||
|
||
// SMembers 获取所有成员
|
||
func (l *UserLogic) GetUserTags(userId int64) ([]string, error) {
|
||
key := fmt.Sprintf("user:tags:%d", userId)
|
||
return l.svcCtx.Redis.Smembers(key)
|
||
}
|
||
|
||
// SIsMember 检查成员
|
||
func (l *UserLogic) HasUserTag(userId int64, tag string) (bool, error) {
|
||
key := fmt.Sprintf("user:tags:%d", userId)
|
||
return l.svcCtx.Redis.Sismember(key, tag)
|
||
}
|
||
```
|
||
|
||
### 5. Sorted Set 操作
|
||
|
||
```go
|
||
// ZAdd 添加成员
|
||
func (l *UserLogic) AddToLeaderboard(userId int64, score int64) error {
|
||
key := "leaderboard"
|
||
_, err := l.svcCtx.Redis.Zadd(key, score, fmt.Sprintf("%d", userId))
|
||
return err
|
||
}
|
||
|
||
// ZRevRange 获取排行榜(从高到低)
|
||
func (l *UserLogic) GetTopUsers(count int) ([]string, error) {
|
||
key := "leaderboard"
|
||
return l.svcCtx.Redis.Zrevrange(key, 0, int64(count-1))
|
||
}
|
||
|
||
// ZRank 获取排名
|
||
func (l *UserLogic) GetUserRank(userId int64) (int64, error) {
|
||
key := "leaderboard"
|
||
return l.svcCtx.Redis.Zrank(key, fmt.Sprintf("%d", userId))
|
||
}
|
||
```
|
||
|
||
### 6. 缓存模式实现
|
||
|
||
**Cache-Aside Pattern(推荐):**
|
||
```go
|
||
func (l *UserLogic) GetUserById(userId int64) (*User, error) {
|
||
cacheKey := fmt.Sprintf("user:%d", userId)
|
||
|
||
// 1. 查缓存
|
||
cached, err := l.svcCtx.Redis.Get(cacheKey)
|
||
if err == nil && cached != "" {
|
||
var user User
|
||
if err := json.Unmarshal([]byte(cached), &user); err == nil {
|
||
return &user, nil
|
||
}
|
||
}
|
||
|
||
// 2. 查数据库
|
||
user, err := l.getUserFromDB(userId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 3. 写缓存
|
||
userJSON, _ := json.Marshal(user)
|
||
l.svcCtx.Redis.Setex(cacheKey, string(userJSON), 3600)
|
||
|
||
return user, nil
|
||
}
|
||
|
||
func (l *UserLogic) UpdateUser(user *User) error {
|
||
// 1. 更新数据库
|
||
if err := l.updateUserInDB(user); err != nil {
|
||
return err
|
||
}
|
||
|
||
// 2. 删除缓存(下次读取时会重新加载)
|
||
cacheKey := fmt.Sprintf("user:%d", user.Id)
|
||
l.svcCtx.Redis.Del(cacheKey)
|
||
|
||
return nil
|
||
}
|
||
```
|
||
|
||
### 7. 分布式锁
|
||
|
||
```go
|
||
// 获取分布式锁
|
||
func (l *UserLogic) AcquireLock(key string, expiry int) (bool, error) {
|
||
lockKey := fmt.Sprintf("lock:%s", key)
|
||
return l.svcCtx.Redis.Setnx(lockKey, "1")
|
||
}
|
||
|
||
// 释放锁
|
||
func (l *UserLogic) ReleaseLock(key string) error {
|
||
lockKey := fmt.Sprintf("lock:%s", key)
|
||
_, err := l.svcCtx.Redis.Del(lockKey)
|
||
return err
|
||
}
|
||
|
||
// 使用示例
|
||
func (l *UserLogic) ProcessWithLock(userId int64) error {
|
||
lockKey := fmt.Sprintf("user:%d", userId)
|
||
|
||
// 获取锁
|
||
acquired, err := l.AcquireLock(lockKey, 10)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if !acquired {
|
||
return fmt.Errorf("failed to acquire lock")
|
||
}
|
||
defer l.ReleaseLock(lockKey)
|
||
|
||
// 执行业务逻辑
|
||
// ...
|
||
|
||
return nil
|
||
}
|
||
```
|
||
|
||
### 8. Pipeline 批量操作
|
||
|
||
```go
|
||
// 使用 go-redis 原生客户端进行 Pipeline
|
||
func (l *UserLogic) BatchSetUsers(users []*User) error {
|
||
// go-zero 的 Redis 包装了 go-redis,可以获取原生客户端
|
||
rdb := l.svcCtx.Redis
|
||
|
||
pipe := rdb.Pipelined(func(pip redis.Pipeliner) error {
|
||
for _, user := range users {
|
||
key := fmt.Sprintf("user:%d", user.Id)
|
||
userJSON, _ := json.Marshal(user)
|
||
pip.Set(context.Background(), key, userJSON, time.Hour)
|
||
}
|
||
return nil
|
||
})
|
||
|
||
return pipe
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🚀 高级特性
|
||
|
||
### 1. 缓存穿透防护(布隆过滤器)
|
||
|
||
```go
|
||
import "github.com/zeromicro/go-zero/core/bloom"
|
||
|
||
type UserLogic struct {
|
||
ctx context.Context
|
||
svcCtx *svc.ServiceContext
|
||
filter *bloom.Filter
|
||
}
|
||
|
||
func (l *UserLogic) GetUserWithBloom(userId int64) (*User, error) {
|
||
// 1. 布隆过滤器检查
|
||
if !l.filter.Exists([]byte(fmt.Sprintf("%d", userId))) {
|
||
return nil, fmt.Errorf("user not found")
|
||
}
|
||
|
||
// 2. 查缓存
|
||
cacheKey := fmt.Sprintf("user:%d", userId)
|
||
cached, err := l.svcCtx.Redis.Get(cacheKey)
|
||
if err == nil && cached != "" {
|
||
var user User
|
||
json.Unmarshal([]byte(cached), &user)
|
||
return &user, nil
|
||
}
|
||
|
||
// 3. 查数据库
|
||
user, err := l.getUserFromDB(userId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 4. 写缓存
|
||
userJSON, _ := json.Marshal(user)
|
||
l.svcCtx.Redis.Setex(cacheKey, string(userJSON), 3600)
|
||
|
||
return user, nil
|
||
}
|
||
```
|
||
|
||
### 2. 缓存击穿防护(Singleflight)
|
||
|
||
```go
|
||
import "golang.org/x/sync/singleflight"
|
||
|
||
type UserLogic struct {
|
||
ctx context.Context
|
||
svcCtx *svc.ServiceContext
|
||
sg singleflight.Group
|
||
}
|
||
|
||
func (l *UserLogic) GetUserWithSingleflight(userId int64) (*User, error) {
|
||
cacheKey := fmt.Sprintf("user:%d", userId)
|
||
|
||
// 使用 Singleflight 确保同一时刻只有一个请求查询
|
||
v, err, _ := l.sg.Do(cacheKey, func() (interface{}, error) {
|
||
// 1. 查缓存
|
||
cached, err := l.svcCtx.Redis.Get(cacheKey)
|
||
if err == nil && cached != "" {
|
||
var user User
|
||
json.Unmarshal([]byte(cached), &user)
|
||
return &user, nil
|
||
}
|
||
|
||
// 2. 查数据库
|
||
user, err := l.getUserFromDB(userId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 3. 写缓存
|
||
userJSON, _ := json.Marshal(user)
|
||
l.svcCtx.Redis.Setex(cacheKey, string(userJSON), 3600)
|
||
|
||
return user, nil
|
||
})
|
||
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
return v.(*User), nil
|
||
}
|
||
```
|
||
|
||
### 3. 缓存雪崩防护(随机过期时间)
|
||
|
||
```go
|
||
import (
|
||
"math/rand"
|
||
"time"
|
||
)
|
||
|
||
func (l *UserLogic) SetCacheWithRandomExpiry(key string, value string, baseExpiry int) error {
|
||
// 在基础过期时间上增加随机值(±20%)
|
||
randomOffset := rand.Intn(baseExpiry / 5)
|
||
expiry := baseExpiry + randomOffset - (baseExpiry / 10)
|
||
|
||
return l.svcCtx.Redis.Setex(key, value, expiry)
|
||
}
|
||
|
||
// 使用示例
|
||
func (l *UserLogic) CacheUser(user *User) error {
|
||
key := fmt.Sprintf("user:%d", user.Id)
|
||
userJSON, _ := json.Marshal(user)
|
||
|
||
// 基础过期时间 1 小时,实际会在 48-72 分钟之间随机
|
||
return l.SetCacheWithRandomExpiry(key, string(userJSON), 3600)
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## ⚡ 性能优化
|
||
|
||
### 1. 连接池配置优化
|
||
|
||
**根据并发量调整:**
|
||
```yaml
|
||
# 低并发(< 100 QPS)
|
||
Redis:
|
||
MaxIdle: 8
|
||
MaxActive: 100
|
||
|
||
# 中并发(100-1000 QPS)
|
||
Redis:
|
||
MaxIdle: 16
|
||
MaxActive: 500
|
||
|
||
# 高并发(> 1000 QPS)
|
||
Redis:
|
||
MaxIdle: 32
|
||
MaxActive: 1000
|
||
```
|
||
|
||
### 2. 超时配置优化
|
||
|
||
```yaml
|
||
Redis:
|
||
# 连接超时:通常设置较大值
|
||
ConnectTimeout: 5000 # 5 秒
|
||
|
||
# 读写超时:设置较小值,快速失败
|
||
ReadTimeout: 1000 # 1 秒
|
||
WriteTimeout: 1000 # 1 秒
|
||
```
|
||
|
||
### 3. Pipeline 批量操作
|
||
|
||
**避免循环调用:**
|
||
```go
|
||
// ❌ 不好:循环调用
|
||
for _, user := range users {
|
||
key := fmt.Sprintf("user:%d", user.Id)
|
||
l.svcCtx.Redis.Set(key, user.Name)
|
||
}
|
||
|
||
// ✅ 推荐:使用 Pipeline
|
||
pipe := l.svcCtx.Redis.Pipelined(func(pip redis.Pipeliner) error {
|
||
for _, user := range users {
|
||
key := fmt.Sprintf("user:%d", user.Id)
|
||
pip.Set(context.Background(), key, user.Name, 0)
|
||
}
|
||
return nil
|
||
})
|
||
```
|
||
|
||
### 4. 合理的缓存过期时间
|
||
|
||
```go
|
||
const (
|
||
CacheExpiryShort = 300 // 5 分钟 - 热点数据
|
||
CacheExpiryMedium = 3600 // 1 小时 - 常规数据
|
||
CacheExpiryLong = 86400 // 1 天 - 冷数据
|
||
)
|
||
|
||
func (l *UserLogic) SetUserCache(user *User, expiry int) error {
|
||
key := fmt.Sprintf("user:%d", user.Id)
|
||
userJSON, _ := json.Marshal(user)
|
||
return l.svcCtx.Redis.Setex(key, string(userJSON), expiry)
|
||
}
|
||
```
|
||
|
||
### 5. Key 命名规范
|
||
|
||
```go
|
||
// 推荐的 Key 命名规范
|
||
const (
|
||
KeyPrefixUser = "user:" // user:123
|
||
KeyPrefixSession = "session:" // session:abc123
|
||
KeyPrefixCache = "cache:" // cache:user:list
|
||
KeyPrefixLock = "lock:" // lock:order:456
|
||
KeyPrefixCounter = "counter:" // counter:page:views
|
||
)
|
||
|
||
// 使用函数生成 Key
|
||
func UserCacheKey(userId int64) string {
|
||
return fmt.Sprintf("%s%d", KeyPrefixUser, userId)
|
||
}
|
||
|
||
func SessionKey(sessionId string) string {
|
||
return fmt.Sprintf("%s%s", KeyPrefixSession, sessionId)
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 🔍 故障排查
|
||
|
||
### 1. 连接失败
|
||
|
||
**问题:** `dial tcp xxx:6379: i/o timeout`
|
||
|
||
**排查步骤:**
|
||
```bash
|
||
# 1. 检查 Redis 服务
|
||
kubectl get pods -n juwan | grep redis
|
||
|
||
# 2. 检查 Service
|
||
kubectl get svc -n juwan | grep redis
|
||
|
||
# 3. 测试网络连通性
|
||
kubectl run -it --rm nettest --image=busybox --restart=Never -n juwan -- \
|
||
nc -zv user-redis-master 6379
|
||
|
||
# 4. 查看应用日志
|
||
kubectl logs -f user-rpc-xxx -n juwan
|
||
```
|
||
|
||
**解决方案:**
|
||
- 确认 Host 配置正确
|
||
- 确认网络策略允许访问
|
||
- 检查 Redis Pod 状态
|
||
|
||
### 2. 认证失败
|
||
|
||
**问题:** `NOAUTH Authentication required`
|
||
|
||
**排查:**
|
||
```go
|
||
// 打印配置(调试用)
|
||
func main() {
|
||
var c config.Config
|
||
conf.MustLoad(*configFile, &c)
|
||
|
||
// 检查密码是否正确加载
|
||
fmt.Printf("Redis Config: Host=%s, Pass=%s\n", c.Redis.Host, c.Redis.Pass)
|
||
}
|
||
```
|
||
|
||
**解决方案:**
|
||
- 确认环境变量 `REDIS_PASSWORD` 已设置
|
||
- 确认 Secret 正确挂载
|
||
- 检查密码是否正确
|
||
|
||
### 3. 性能问题
|
||
|
||
**慢查询检测:**
|
||
```go
|
||
import "time"
|
||
|
||
func (l *UserLogic) GetUserWithMetrics(userId int64) (*User, error) {
|
||
start := time.Now()
|
||
defer func() {
|
||
duration := time.Since(start)
|
||
if duration > 100*time.Millisecond {
|
||
l.Logger.Warnf("Slow Redis query: %v", duration)
|
||
}
|
||
}()
|
||
|
||
// 执行查询
|
||
key := fmt.Sprintf("user:%d", userId)
|
||
cached, err := l.svcCtx.Redis.Get(key)
|
||
// ...
|
||
}
|
||
```
|
||
|
||
**常见原因:**
|
||
- 连接池耗尽 → 增大 MaxActive
|
||
- 大 Value 传输 → 拆分或压缩数据
|
||
- 网络延迟 → 检查网络质量
|
||
|
||
### 4. 内存泄漏
|
||
|
||
**检查连接是否正确关闭:**
|
||
```go
|
||
// go-zero 的 Redis 客户端会自动管理连接
|
||
// 但如果使用原生 go-redis 客户端,需要手动关闭
|
||
|
||
// ❌ 错误示例
|
||
func bad() {
|
||
rdb := redis.NewClient(&redis.Options{...})
|
||
// 使用完后没有关闭
|
||
}
|
||
|
||
// ✅ 正确示例
|
||
func good() {
|
||
rdb := redis.NewClient(&redis.Options{...})
|
||
defer rdb.Close()
|
||
// ...
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 📖 最佳实践
|
||
|
||
### 1. 环境变量管理
|
||
|
||
**Kubernetes Deployment:**
|
||
```yaml
|
||
apiVersion: apps/v1
|
||
kind: Deployment
|
||
metadata:
|
||
name: user-rpc
|
||
namespace: juwan
|
||
spec:
|
||
template:
|
||
spec:
|
||
containers:
|
||
- name: user-rpc
|
||
image: user-rpc:v1
|
||
env:
|
||
# 从 Secret 读取 Redis 密码
|
||
- name: REDIS_PASSWORD
|
||
valueFrom:
|
||
secretKeyRef:
|
||
name: user-redis
|
||
key: password
|
||
|
||
# 从 ConfigMap 读取其他配置
|
||
- name: REDIS_HOST
|
||
valueFrom:
|
||
configMapKeyRef:
|
||
name: user-rpc-config
|
||
key: redis.host
|
||
```
|
||
|
||
### 2. 配置分离
|
||
|
||
**开发、测试、生产环境分离:**
|
||
```bash
|
||
# 开发环境
|
||
go run usercenter.go -f etc/pb-dev.yaml
|
||
|
||
# 测试环境
|
||
go run usercenter.go -f etc/pb-test.yaml
|
||
|
||
# 生产环境
|
||
./usercenter -f etc/pb-prod.yaml
|
||
```
|
||
|
||
### 3. 监控指标
|
||
|
||
```go
|
||
import (
|
||
"github.com/zeromicro/go-zero/core/metric"
|
||
"github.com/zeromicro/go-zero/core/prometheus"
|
||
)
|
||
|
||
var (
|
||
redisCacheHit = metric.NewCounterVec(&metric.CounterVecOpts{
|
||
Namespace: "user_rpc",
|
||
Subsystem: "redis",
|
||
Name: "cache_hit_total",
|
||
Help: "redis cache hit count",
|
||
Labels: []string{"key"},
|
||
})
|
||
|
||
redisCacheMiss = metric.NewCounterVec(&metric.CounterVecOpts{
|
||
Namespace: "user_rpc",
|
||
Subsystem: "redis",
|
||
Name: "cache_miss_total",
|
||
Help: "redis cache miss count",
|
||
Labels: []string{"key"},
|
||
})
|
||
)
|
||
|
||
func (l *UserLogic) GetUserWithMetrics(userId int64) (*User, error) {
|
||
cacheKey := fmt.Sprintf("user:%d", userId)
|
||
|
||
cached, err := l.svcCtx.Redis.Get(cacheKey)
|
||
if err == nil && cached != "" {
|
||
redisCacheHit.Inc("user")
|
||
var user User
|
||
json.Unmarshal([]byte(cached), &user)
|
||
return &user, nil
|
||
}
|
||
|
||
redisCacheMiss.Inc("user")
|
||
// 查询数据库...
|
||
}
|
||
```
|
||
|
||
### 4. 错误处理
|
||
|
||
```go
|
||
func (l *UserLogic) GetUser(userId int64) (*User, error) {
|
||
cacheKey := fmt.Sprintf("user:%d", userId)
|
||
|
||
// 缓存查询失败不应该中断流程
|
||
cached, err := l.svcCtx.Redis.Get(cacheKey)
|
||
if err == nil && cached != "" {
|
||
var user User
|
||
if json.Unmarshal([]byte(cached), &user) == nil {
|
||
return &user, nil
|
||
}
|
||
}
|
||
|
||
// 缓存失败,降级查询数据库
|
||
user, err := l.getUserFromDB(userId)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 尝试回写缓存,失败不影响返回结果
|
||
go func() {
|
||
userJSON, _ := json.Marshal(user)
|
||
if err := l.svcCtx.Redis.Setex(cacheKey, string(userJSON), 3600); err != nil {
|
||
l.Logger.Errorf("Failed to set cache: %v", err)
|
||
}
|
||
}()
|
||
|
||
return user, nil
|
||
}
|
||
```
|
||
|
||
### 5. 缓存更新策略
|
||
|
||
**Write-Through(同步更新):**
|
||
```go
|
||
func (l *UserLogic) UpdateUser(user *User) error {
|
||
// 1. 更新数据库
|
||
if err := l.updateUserInDB(user); err != nil {
|
||
return err
|
||
}
|
||
|
||
// 2. 同步更新缓存
|
||
cacheKey := fmt.Sprintf("user:%d", user.Id)
|
||
userJSON, _ := json.Marshal(user)
|
||
if err := l.svcCtx.Redis.Setex(cacheKey, string(userJSON), 3600); err != nil {
|
||
l.Logger.Errorf("Failed to update cache: %v", err)
|
||
}
|
||
|
||
return nil
|
||
}
|
||
```
|
||
|
||
**Write-Behind(异步更新):**
|
||
```go
|
||
func (l *UserLogic) UpdateUserAsync(user *User) error {
|
||
// 1. 立即更新缓存
|
||
cacheKey := fmt.Sprintf("user:%d", user.Id)
|
||
userJSON, _ := json.Marshal(user)
|
||
l.svcCtx.Redis.Setex(cacheKey, string(userJSON), 3600)
|
||
|
||
// 2. 异步更新数据库
|
||
go func() {
|
||
if err := l.updateUserInDB(user); err != nil {
|
||
l.Logger.Errorf("Failed to update DB: %v", err)
|
||
// 回滚缓存
|
||
l.svcCtx.Redis.Del(cacheKey)
|
||
}
|
||
}()
|
||
|
||
return nil
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 📚 参考资源
|
||
|
||
### 官方文档
|
||
- [go-zero 官方文档](https://go-zero.dev/)
|
||
- [go-zero Redis 文档](https://go-zero.dev/docs/tutorials/redis)
|
||
- [go-redis 文档](https://redis.uptrace.dev/)
|
||
|
||
### 示例代码
|
||
- [go-zero Examples](https://github.com/zeromicro/go-zero/tree/master/example)
|
||
- [go-zero Book Store](https://github.com/zeromicro/go-zero-book-store)
|
||
|
||
### 相关工具
|
||
- [RedisInsight](https://redis.com/redis-enterprise/redis-insight/) - Redis 管理工具
|
||
- [redis-cli](https://redis.io/docs/manual/cli/) - Redis 命令行工具
|
||
|
||
---
|
||
|
||
## 📝 总结
|
||
|
||
### 快速开始检查清单
|
||
|
||
- [ ] 1. 在 `config.go` 中定义 `Redis redis.RedisConf`
|
||
- [ ] 2. 在配置文件中添加 Redis 配置
|
||
- [ ] 3. 在 `ServiceContext` 中初始化 `redis.MustNewRedis(c.Redis)`
|
||
- [ ] 4. 在 Kubernetes中配置环境变量 `REDIS_PASSWORD`
|
||
- [ ] 5. 在 logic 中使用 `l.svcCtx.Redis`
|
||
- [ ] 6. 测试连接是否正常
|
||
|
||
### 生产环境推荐配置
|
||
|
||
```yaml
|
||
Redis:
|
||
Host: user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379
|
||
Type: sentinel
|
||
Pass: ${REDIS_PASSWORD}
|
||
MasterName: mymaster
|
||
MaxIdle: 16
|
||
MaxActive: 100
|
||
ConnectTimeout: 5000
|
||
ReadTimeout: 3000
|
||
WriteTimeout: 3000
|
||
```
|
||
|
||
### 关键点提醒
|
||
|
||
1. ✅ **生产环境必须使用 Sentinel 模式**
|
||
2. ✅ **密码通过环境变量传递,不要硬编码**
|
||
3. ✅ **合理设置过期时间,防止缓存雪崩**
|
||
4. ✅ **使用 Pipeline 优化批量操作**
|
||
5. ✅ **实现缓存降级策略,Redis 故障不影响主流程**
|
||
|
||
---
|
||
|
||
**文档版本:** 1.0
|
||
**创建日期:** 2026年2月22日
|
||
**维护者:** Backend Team
|
||
**下次审查:** 2026年3月22日
|