# 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日
