1180 lines
28 KiB
Markdown
1180 lines
28 KiB
Markdown
# Redis Services 连接指南
|
||
|
||
**环境:** juwan namespace
|
||
**Redis 版本:** 7.0.12
|
||
**部署模式:** RedisReplication + RedisSentinel
|
||
**文档日期:** 2026年2月22日
|
||
|
||
---
|
||
|
||
## 📋 目录
|
||
|
||
1. [Service 列表总览](#service-列表总览)
|
||
2. [Redis 数据层 Service 详解](#redis-数据层-service-详解)
|
||
3. [Sentinel 监控层 Service 详解](#sentinel-监控层-service-详解)
|
||
4. [管理工具连接方式](#管理工具连接方式)
|
||
5. [应用服务连接方式](#应用服务连接方式)
|
||
6. [连接方式对比](#连接方式对比)
|
||
7. [最佳实践建议](#最佳实践建议)
|
||
8. [故障排查](#故障排查)
|
||
|
||
---
|
||
|
||
## 📊 Service 列表总览
|
||
|
||
当前集群中部署的 Redis 相关 Service:
|
||
|
||
| Service 名称 | 类型 | Cluster IP | 端口 | 用途 |
|
||
|-------------|------|-----------|------|------|
|
||
| **user-redis** | ClusterIP | 10.103.91.84 | 6379, 9121 | 通用访问 + 监控 |
|
||
| **user-redis-additional** | ClusterIP | 10.107.228.48 | 6379 | 额外访问入口 |
|
||
| **user-redis-headless** | ClusterIP(None) | None | 6379 | Pod 间直接访问 |
|
||
| **user-redis-master** ⭐ | ClusterIP | 10.97.120.76 | 6379 | 主节点访问 |
|
||
| **user-redis-replica** ⭐ | ClusterIP | 10.100.213.103 | 6379 | 从节点访问 |
|
||
| **user-redis-sentinel-sentinel** ⭐⭐⭐ | ClusterIP | 10.105.28.231 | 26379 | Sentinel 访问 |
|
||
| **user-redis-sentinel-sentinel-additional** | ClusterIP | 10.97.111.42 | 26379 | 额外 Sentinel 入口 |
|
||
| **user-redis-sentinel-sentinel-headless** | ClusterIP(None) | None | 26379 | Sentinel 间通信 |
|
||
|
||
**图例:**
|
||
- ⭐⭐⭐ 生产环境强烈推荐
|
||
- ⭐ 生产环境可用
|
||
- 无标记:特殊场景或内部使用
|
||
|
||
---
|
||
|
||
## 🔴 Redis 数据层 Service 详解
|
||
|
||
### 1. user-redis-master ⭐
|
||
|
||
**基本信息**
|
||
```yaml
|
||
名称: user-redis-master
|
||
类型: ClusterIP
|
||
IP: 10.97.120.76
|
||
端口: 6379/TCP
|
||
DNS: user-redis-master.juwan.svc.cluster.local
|
||
```
|
||
|
||
**功能特点**
|
||
- 🎯 自动追踪当前 Redis 主节点
|
||
- ✅ 确保所有写操作到达主节点
|
||
- 🔄 故障转移后自动指向新主节点
|
||
- 💪 提供最强一致性保证
|
||
|
||
**适用场景**
|
||
- ✅ 所有写操作(SET, HSET, ZADD 等)
|
||
- ✅ 需要强一致性的读操作
|
||
- ✅ 事务操作(MULTI/EXEC)
|
||
- ❌ 不适合高并发读请求
|
||
|
||
**连接示例**
|
||
```go
|
||
// Go - go-redis
|
||
rdb := redis.NewClient(&redis.Options{
|
||
Addr: "user-redis-master.juwan.svc.cluster.local:6379",
|
||
Password: os.Getenv("REDIS_PASSWORD"),
|
||
DB: 0,
|
||
})
|
||
|
||
// 写操作
|
||
err := rdb.Set(ctx, "user:1001", "John Doe", 0).Err()
|
||
```
|
||
|
||
```bash
|
||
# CLI 测试
|
||
kubectl run -it --rm redis-cli --image=redis:7.0.12 --restart=Never -n juwan -- \
|
||
redis-cli -h user-redis-master -a <password> SET test "hello"
|
||
```
|
||
|
||
---
|
||
|
||
### 2. user-redis-replica ⭐
|
||
|
||
**基本信息**
|
||
```yaml
|
||
名称: user-redis-replica
|
||
类型: ClusterIP
|
||
IP: 10.100.213.103
|
||
端口: 6379/TCP
|
||
DNS: user-redis-replica.juwan.svc.cluster.local
|
||
```
|
||
|
||
**功能特点**
|
||
- 📖 负载均衡到所有从节点(当前 2 个)
|
||
- ⚡ 分散读请求,提升吞吐量
|
||
- 🕐 可能存在轻微的复制延迟(通常 < 100ms)
|
||
- 🚫 只读模式,写操作会失败
|
||
|
||
**适用场景**
|
||
- ✅ 高并发读请求
|
||
- ✅ 查询操作(GET, HGET, ZRANGE 等)
|
||
- ✅ 统计分析类查询
|
||
- ⚠️ 对数据实时性要求不高的场景
|
||
- ❌ 不能用于写操作
|
||
|
||
**连接示例**
|
||
```go
|
||
// Go - 读写分离配置
|
||
masterClient := redis.NewClient(&redis.Options{
|
||
Addr: "user-redis-master.juwan.svc.cluster.local:6379",
|
||
Password: os.Getenv("REDIS_PASSWORD"),
|
||
})
|
||
|
||
replicaClient := redis.NewClient(&redis.Options{
|
||
Addr: "user-redis-replica.juwan.svc.cluster.local:6379",
|
||
Password: os.Getenv("REDIS_PASSWORD"),
|
||
ReadOnly: true,
|
||
})
|
||
|
||
// 写操作用 master
|
||
masterClient.Set(ctx, "counter", 100, 0)
|
||
|
||
// 读操作用 replica
|
||
val, err := replicaClient.Get(ctx, "counter").Result()
|
||
```
|
||
|
||
---
|
||
|
||
### 3. user-redis
|
||
|
||
**基本信息**
|
||
```yaml
|
||
名称: user-redis
|
||
类型: ClusterIP
|
||
IP: 10.103.91.84
|
||
端口: 6379/TCP (Redis), 9121/TCP (Exporter)
|
||
DNS: user-redis.juwan.svc.cluster.local
|
||
```
|
||
|
||
**功能特点**
|
||
- 🔀 负载均衡到所有 Redis 节点(主 + 从)
|
||
- 📊 端口 9121 暴露 Prometheus 指标
|
||
- ⚠️ 写操作可能路由到从节点导致失败
|
||
|
||
**适用场景**
|
||
- ✅ Prometheus 监控抓取(端口 9121)
|
||
- ⚠️ 测试环境的简单访问
|
||
- ❌ 不推荐生产环境读写操作
|
||
|
||
**监控配置**
|
||
```yaml
|
||
# Prometheus ServiceMonitor
|
||
apiVersion: monitoring.coreos.com/v1
|
||
kind: ServiceMonitor
|
||
metadata:
|
||
name: redis-metrics
|
||
namespace: juwan
|
||
spec:
|
||
selector:
|
||
matchLabels:
|
||
app: redis
|
||
endpoints:
|
||
- port: redis-exporter
|
||
interval: 30s
|
||
path: /metrics
|
||
```
|
||
|
||
---
|
||
|
||
### 4. user-redis-additional
|
||
|
||
**基本信息**
|
||
```yaml
|
||
名称: user-redis-additional
|
||
类型: ClusterIP
|
||
IP: 10.107.228.48
|
||
端口: 6379/TCP
|
||
```
|
||
|
||
**功能特点**
|
||
- 功能类似 user-redis
|
||
- 提供额外的访问入口
|
||
- 用于多租户或网络隔离场景
|
||
|
||
**适用场景**
|
||
- 特殊网络策略场景
|
||
- 多应用隔离访问
|
||
- 备用访问点
|
||
|
||
---
|
||
|
||
### 5. user-redis-headless
|
||
|
||
**基本信息**
|
||
```yaml
|
||
名称: user-redis-headless
|
||
类型: ClusterIP (Headless - None)
|
||
端口: 6379/TCP
|
||
DNS:
|
||
- user-redis-0.user-redis-headless.juwan.svc.cluster.local
|
||
- user-redis-1.user-redis-headless.juwan.svc.cluster.local
|
||
- user-redis-2.user-redis-headless.juwan.svc.cluster.local
|
||
```
|
||
|
||
**功能特点**
|
||
- 🎯 直接返回所有 Pod IP,不做负载均衡
|
||
- 🔗 用于 StatefulSet Pod 间通信
|
||
- 📡 Redis 主从复制使用此服务发现
|
||
|
||
**适用场景**
|
||
- ✅ 内部复制通信
|
||
- ✅ 集群管理操作
|
||
- ✅ 需要直接访问特定 Pod
|
||
- ❌ 不适合应用层使用
|
||
|
||
**直接访问示例**
|
||
```bash
|
||
# 直接连接 user-redis-0
|
||
redis-cli -h user-redis-0.user-redis-headless.juwan.svc.cluster.local -a <password>
|
||
|
||
# DNS 解析会返回具体 Pod IP
|
||
nslookup user-redis-headless.juwan.svc.cluster.local
|
||
```
|
||
|
||
---
|
||
|
||
## 🟡 Sentinel 监控层 Service 详解
|
||
|
||
### 1. user-redis-sentinel-sentinel ⭐⭐⭐
|
||
|
||
**基本信息**
|
||
```yaml
|
||
名称: user-redis-sentinel-sentinel
|
||
类型: ClusterIP
|
||
IP: 10.105.28.231
|
||
端口: 26379/TCP
|
||
DNS: user-redis-sentinel-sentinel.juwan.svc.cluster.local
|
||
```
|
||
|
||
**功能特点**
|
||
- 🛡️ 提供高可用 Redis 访问
|
||
- 🔄 自动发现主节点
|
||
- ⚡ 主节点故障时自动切换
|
||
- 📍 客户端自动跟踪主节点变化
|
||
|
||
**Sentinel 架构**
|
||
```
|
||
应用 → Sentinel Service → Sentinel 节点 (3个)
|
||
↓
|
||
监控 Redis 集群
|
||
↓
|
||
自动发现当前主节点位置
|
||
```
|
||
|
||
**适用场景**
|
||
- ✅✅✅ **生产环境强烈推荐**
|
||
- ✅ 需要自动故障转移
|
||
- ✅ 高可用架构
|
||
- ✅ 无需手动处理主从切换
|
||
|
||
**连接示例**
|
||
```go
|
||
// Go - go-redis Sentinel 模式
|
||
rdb := redis.NewFailoverClient(&redis.FailoverOptions{
|
||
MasterName: "mymaster",
|
||
SentinelAddrs: []string{
|
||
"user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379",
|
||
},
|
||
Password: os.Getenv("REDIS_PASSWORD"),
|
||
DB: 0,
|
||
|
||
// 连接池配置
|
||
PoolSize: 10,
|
||
MinIdleConns: 5,
|
||
|
||
// 超时配置
|
||
DialTimeout: 5 * time.Second,
|
||
ReadTimeout: 3 * time.Second,
|
||
WriteTimeout: 3 * time.Second,
|
||
})
|
||
|
||
// 使用方式与普通客户端完全一致
|
||
err := rdb.Set(ctx, "key", "value", 0).Err()
|
||
val, err := rdb.Get(ctx, "key").Result()
|
||
```
|
||
|
||
```python
|
||
# Python - redis-py Sentinel 模式
|
||
from redis.sentinel import Sentinel
|
||
|
||
sentinel = Sentinel([
|
||
('user-redis-sentinel-sentinel.juwan.svc.cluster.local', 26379)
|
||
], socket_timeout=0.5)
|
||
|
||
# 获取主节点(写)
|
||
master = sentinel.master_for('mymaster',
|
||
password=os.getenv('REDIS_PASSWORD'),
|
||
socket_timeout=0.5)
|
||
master.set('key', 'value')
|
||
|
||
# 获取从节点(读)
|
||
slave = sentinel.slave_for('mymaster',
|
||
password=os.getenv('REDIS_PASSWORD'),
|
||
socket_timeout=0.5)
|
||
value = slave.get('key')
|
||
```
|
||
|
||
```yaml
|
||
# Spring Boot application.yml
|
||
spring:
|
||
redis:
|
||
sentinel:
|
||
master: mymaster
|
||
nodes:
|
||
- user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379
|
||
password: ${REDIS_PASSWORD}
|
||
```
|
||
|
||
**Sentinel 命令查询**
|
||
```bash
|
||
# 查看主节点信息
|
||
kubectl exec -it user-redis-sentinel-sentinel-0 -n juwan -- \
|
||
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster
|
||
|
||
# 查看所有监控的主节点
|
||
kubectl exec -it user-redis-sentinel-sentinel-0 -n juwan -- \
|
||
redis-cli -p 26379 SENTINEL masters
|
||
|
||
# 查看从节点列表
|
||
kubectl exec -it user-redis-sentinel-sentinel-0 -n juwan -- \
|
||
redis-cli -p 26379 SENTINEL slaves mymaster
|
||
|
||
# 查看 Sentinel 节点
|
||
kubectl exec -it user-redis-sentinel-sentinel-0 -n juwan -- \
|
||
redis-cli -p 26379 SENTINEL sentinels mymaster
|
||
```
|
||
|
||
---
|
||
|
||
### 2. user-redis-sentinel-sentinel-additional
|
||
|
||
**基本信息**
|
||
```yaml
|
||
名称: user-redis-sentinel-sentinel-additional
|
||
类型: ClusterIP
|
||
IP: 10.97.111.42
|
||
端口: 26379/TCP
|
||
```
|
||
|
||
**功能特点**
|
||
- 功能同 user-redis-sentinel-sentinel
|
||
- 提供额外访问入口
|
||
- 用于多客户端分离
|
||
|
||
**适用场景**
|
||
- 多应用共享 Redis 时的访问隔离
|
||
- 网络策略要求
|
||
- 流量分离
|
||
|
||
---
|
||
|
||
### 3. user-redis-sentinel-sentinel-headless
|
||
|
||
**基本信息**
|
||
```yaml
|
||
名称: user-redis-sentinel-sentinel-headless
|
||
类型: ClusterIP (Headless - None)
|
||
端口: 26379/TCP
|
||
```
|
||
|
||
**功能特点**
|
||
- Sentinel 节点间通信
|
||
- 选举和投票
|
||
- 状态同步
|
||
|
||
**适用场景**
|
||
- 内部使用,应用层无需关注
|
||
|
||
---
|
||
|
||
## 🔧 管理工具连接方式
|
||
|
||
### 使用 kubectl port-forward(推荐)
|
||
|
||
#### 方式一:连接主节点
|
||
```bash
|
||
# 转发主节点服务到本地
|
||
kubectl port-forward -n juwan svc/user-redis-master 6379:6379
|
||
|
||
# 或直接转发到 Pod
|
||
kubectl port-forward -n juwan pod/user-redis-0 6379:6379
|
||
```
|
||
|
||
然后在管理工具中配置:
|
||
- **Host**: localhost
|
||
- **Port**: 6379
|
||
- **Password**: (见下方获取方法)
|
||
|
||
#### 方式二:使用 LoadBalancer(生产不推荐)
|
||
```yaml
|
||
# 临时暴露服务(仅用于调试)
|
||
apiVersion: v1
|
||
kind: Service
|
||
metadata:
|
||
name: redis-external
|
||
namespace: juwan
|
||
spec:
|
||
type: LoadBalancer
|
||
selector:
|
||
app: user-redis
|
||
ports:
|
||
- port: 6379
|
||
targetPort: 6379
|
||
```
|
||
|
||
---
|
||
|
||
### 获取 Redis 密码
|
||
|
||
```bash
|
||
# 方式一:直接输出
|
||
kubectl get secret user-redis -n juwan -o jsonpath='{.data.password}' | base64 -d
|
||
|
||
# 方式二:设置为环境变量
|
||
export REDIS_PASSWORD=$(kubectl get secret user-redis -n juwan -o jsonpath='{.data.password}' | base64 -d)
|
||
echo $REDIS_PASSWORD
|
||
|
||
# 方式三:保存到文件
|
||
kubectl get secret user-redis -n juwan -o jsonpath='{.data.password}' | base64 -d > redis-password.txt
|
||
```
|
||
|
||
---
|
||
|
||
### 常用管理工具配置
|
||
|
||
#### Redis Desktop Manager (RedisInsight)
|
||
```
|
||
Connection Name: juwan-user-redis
|
||
Host: localhost (使用 port-forward)
|
||
Port: 6379
|
||
Username: (留空)
|
||
Password: (从 Secret 获取)
|
||
```
|
||
|
||
#### redis-cli
|
||
```bash
|
||
# 在集群内访问
|
||
kubectl exec -it user-redis-0 -n juwan -- redis-cli -a <password>
|
||
|
||
# 从本地访问(需要 port-forward)
|
||
redis-cli -h localhost -p 6379 -a <password>
|
||
|
||
# 常用命令
|
||
INFO replication # 查看复制状态
|
||
INFO stats # 查看统计信息
|
||
CLUSTER INFO # 查看集群信息
|
||
KEYS * # 查看所有 key(生产谨慎使用)
|
||
```
|
||
|
||
---
|
||
|
||
## 💻 应用服务连接方式
|
||
|
||
### 方案一:Sentinel 模式(生产强烈推荐)⭐⭐⭐
|
||
|
||
**优点**
|
||
- ✅ 自动故障转移
|
||
- ✅ 高可用
|
||
- ✅ 无需手动切换
|
||
- ✅ 客户端自动重连
|
||
- ✅ 支持读写分离
|
||
|
||
#### Go-Zero 配置
|
||
|
||
**配置文件** `app/users/rpc/etc/pb.yaml`
|
||
```yaml
|
||
Name: pb.rpc
|
||
ListenOn: 0.0.0.0:9001
|
||
|
||
# Redis Sentinel 配置
|
||
Redis:
|
||
Type: sentinel
|
||
MasterName: mymaster
|
||
SentinelAddrs:
|
||
- user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379
|
||
Pass: ${REDIS_PASSWORD} # 从环境变量读取
|
||
|
||
Etcd:
|
||
Hosts:
|
||
- etcd-service.juwan.svc.cluster.local:2379
|
||
Key: pb.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** `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),
|
||
}
|
||
}
|
||
```
|
||
|
||
**使用示例** `app/users/rpc/internal/logic/getUsersByIdLogic.go`
|
||
```go
|
||
func (l *GetUsersByIdLogic) GetUsersById(in *pb.GetUsersByIdReq) (*pb.GetUsersByIdResp, error) {
|
||
// 尝试从缓存获取
|
||
cacheKey := fmt.Sprintf("user:%d", in.Id)
|
||
cached, err := l.svcCtx.Redis.Get(cacheKey)
|
||
if err == nil && cached != "" {
|
||
// 缓存命中
|
||
var user pb.User
|
||
json.Unmarshal([]byte(cached), &user)
|
||
return &pb.GetUsersByIdResp{User: &user}, nil
|
||
}
|
||
|
||
// 从数据库查询
|
||
user := l.fetchUserFromDB(in.Id)
|
||
|
||
// 写入缓存
|
||
userJSON, _ := json.Marshal(user)
|
||
l.svcCtx.Redis.Setex(cacheKey, string(userJSON), 3600) // 1小时过期
|
||
|
||
return &pb.GetUsersByIdResp{User: user}, nil
|
||
}
|
||
```
|
||
|
||
#### Go (原生 go-redis)
|
||
|
||
```go
|
||
package main
|
||
|
||
import (
|
||
"context"
|
||
"github.com/redis/go-redis/v9"
|
||
"time"
|
||
)
|
||
|
||
func NewRedisClient() *redis.Client {
|
||
rdb := redis.NewFailoverClient(&redis.FailoverOptions{
|
||
MasterName: "mymaster",
|
||
SentinelAddrs: []string{
|
||
"user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379",
|
||
},
|
||
Password: os.Getenv("REDIS_PASSWORD"),
|
||
DB: 0,
|
||
|
||
// 连接池配置
|
||
PoolSize: 10,
|
||
MinIdleConns: 5,
|
||
|
||
// 超时配置
|
||
DialTimeout: 5 * time.Second,
|
||
ReadTimeout: 3 * time.Second,
|
||
WriteTimeout: 3 * time.Second,
|
||
|
||
// 重试配置
|
||
MaxRetries: 3,
|
||
MinRetryBackoff: 8 * time.Millisecond,
|
||
MaxRetryBackoff: 512 * time.Millisecond,
|
||
})
|
||
|
||
// 测试连接
|
||
ctx := context.Background()
|
||
if err := rdb.Ping(ctx).Err(); err != nil {
|
||
panic(err)
|
||
}
|
||
|
||
return rdb
|
||
}
|
||
```
|
||
|
||
#### Python (redis-py)
|
||
|
||
```python
|
||
from redis.sentinel import Sentinel
|
||
import os
|
||
|
||
# 初始化 Sentinel
|
||
sentinel = Sentinel([
|
||
('user-redis-sentinel-sentinel.juwan.svc.cluster.local', 26379)
|
||
], socket_timeout=5.0)
|
||
|
||
# 获取主节点连接(用于写操作)
|
||
master = sentinel.master_for(
|
||
'mymaster',
|
||
password=os.getenv('REDIS_PASSWORD'),
|
||
socket_timeout=3.0,
|
||
socket_connect_timeout=5.0,
|
||
socket_keepalive=True,
|
||
socket_keepalive_options={},
|
||
connection_pool_kwargs={
|
||
'max_connections': 50
|
||
}
|
||
)
|
||
|
||
# 获取从节点连接(用于读操作)
|
||
slave = sentinel.slave_for(
|
||
'mymaster',
|
||
password=os.getenv('REDIS_PASSWORD'),
|
||
socket_timeout=3.0
|
||
)
|
||
|
||
# 使用
|
||
master.set('key', 'value')
|
||
value = slave.get('key')
|
||
```
|
||
|
||
#### Java (Spring Data Redis)
|
||
|
||
```yaml
|
||
# application.yml
|
||
spring:
|
||
redis:
|
||
timeout: 3000ms
|
||
password: ${REDIS_PASSWORD}
|
||
sentinel:
|
||
master: mymaster
|
||
nodes:
|
||
- user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379
|
||
lettuce:
|
||
pool:
|
||
max-active: 10
|
||
max-idle: 5
|
||
min-idle: 2
|
||
max-wait: 3000ms
|
||
```
|
||
|
||
```java
|
||
@Configuration
|
||
public class RedisConfig {
|
||
|
||
@Bean
|
||
public RedisTemplate<String, Object> redisTemplate(
|
||
RedisConnectionFactory connectionFactory) {
|
||
RedisTemplate<String, Object> template = new RedisTemplate<>();
|
||
template.setConnectionFactory(connectionFactory);
|
||
template.setKeySerializer(new StringRedisSerializer());
|
||
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
|
||
return template;
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 方案二:主从分离模式 ⭐
|
||
|
||
**优点**
|
||
- ✅ 读写性能优化
|
||
- ✅ 配置清晰
|
||
- ⚠️ 需要手动处理故障
|
||
|
||
**Go-Zero 配置**
|
||
```yaml
|
||
# app/users/rpc/etc/pb.yaml
|
||
Redis:
|
||
- Host: user-redis-master.juwan.svc.cluster.local:6379
|
||
Type: node
|
||
Pass: ${REDIS_PASSWORD}
|
||
- Host: user-redis-replica.juwan.svc.cluster.local:6379
|
||
Type: node
|
||
Pass: ${REDIS_PASSWORD}
|
||
```
|
||
|
||
**代码示例**
|
||
```go
|
||
type ServiceContext struct {
|
||
Config config.Config
|
||
RedisMaster *redis.Redis // 写操作
|
||
RedisReplica *redis.Redis // 读操作
|
||
}
|
||
|
||
func NewServiceContext(c config.Config) *ServiceContext {
|
||
return &ServiceContext{
|
||
Config: c,
|
||
RedisMaster: redis.MustNewRedis(c.Redis[0]), // master
|
||
RedisReplica: redis.MustNewRedis(c.Redis[1]), // replica
|
||
}
|
||
}
|
||
|
||
// 写操作
|
||
l.svcCtx.RedisMaster.Set("key", "value")
|
||
|
||
// 读操作
|
||
val, _ := l.svcCtx.RedisReplica.Get("key")
|
||
```
|
||
|
||
---
|
||
|
||
### 方案三:简单模式(仅测试环境)
|
||
|
||
```yaml
|
||
Redis:
|
||
Host: user-redis-master.juwan.svc.cluster.local:6379
|
||
Type: node
|
||
Pass: ${REDIS_PASSWORD}
|
||
```
|
||
|
||
---
|
||
|
||
### Kubernetes Deployment 配置
|
||
|
||
```yaml
|
||
# deploy/k8s/service/user/user-rpc.yaml
|
||
apiVersion: apps/v1
|
||
kind: Deployment
|
||
metadata:
|
||
name: user-rpc
|
||
namespace: juwan
|
||
spec:
|
||
template:
|
||
spec:
|
||
containers:
|
||
- name: user-rpc
|
||
image: user-rpc:v1
|
||
env:
|
||
# 数据库连接
|
||
- name: DB_URI
|
||
valueFrom:
|
||
secretKeyRef:
|
||
name: user-db-app
|
||
key: uri
|
||
|
||
# Redis 密码
|
||
- name: REDIS_PASSWORD
|
||
valueFrom:
|
||
secretKeyRef:
|
||
name: user-redis
|
||
key: password
|
||
|
||
# 健康检查
|
||
readinessProbe:
|
||
tcpSocket:
|
||
port: 9001
|
||
initialDelaySeconds: 10
|
||
periodSeconds: 10
|
||
|
||
livenessProbe:
|
||
tcpSocket:
|
||
port: 9001
|
||
initialDelaySeconds: 15
|
||
periodSeconds: 20
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 连接方式对比
|
||
|
||
| 连接方式 | 优点 | 缺点 | 故障转移 | 读写分离 | 复杂度 | 推荐度 |
|
||
|---------|------|------|---------|---------|--------|--------|
|
||
| **Sentinel 模式** | 自动高可用,客户端自动切换 | 配置稍复杂 | ✅ 自动 | ✅ 支持 | 中 | ⭐⭐⭐⭐⭐ |
|
||
| **主从分离** | 性能优化,逻辑清晰 | 需手动处理故障 | ❌ 手动 | ✅ 支持 | 中 | ⭐⭐⭐ |
|
||
| **仅连 Master** | 配置简单,强一致性 | 单点故障,读性能差 | ❌ 手动 | ❌ 不支持 | 低 | ⭐⭐ |
|
||
| **仅连 Replica** | 读性能好 | 只读,不能写入 | ❌ 手动 | ✅ 仅读 | 低 | ⭐ |
|
||
| **连 user-redis** | 极简单 | 性能差,不可靠 | ❌ 无 | ❌ 不支持 | 低 | ❌ |
|
||
|
||
---
|
||
|
||
## 🎯 最佳实践建议
|
||
|
||
### 生产环境(强烈推荐)
|
||
|
||
```yaml
|
||
# 使用 Sentinel 模式
|
||
Redis:
|
||
Type: sentinel
|
||
MasterName: mymaster
|
||
SentinelAddrs:
|
||
- user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379
|
||
Pass: ${REDIS_PASSWORD}
|
||
|
||
# 连接池配置
|
||
PoolSize: 10
|
||
MinIdleConns: 5
|
||
|
||
# 超时配置
|
||
DialTimeout: 5s
|
||
ReadTimeout: 3s
|
||
WriteTimeout: 3s
|
||
|
||
# 重试配置
|
||
MaxRetries: 3
|
||
```
|
||
|
||
**理由**
|
||
- ✅ 自动故障转移,RTO < 30秒
|
||
- ✅ 客户端无感知切换
|
||
- ✅ 无需人工介入
|
||
- ✅ 久经考验的成熟方案
|
||
|
||
---
|
||
|
||
### 开发/测试环境
|
||
|
||
```yaml
|
||
# 简化配置,直连主节点
|
||
Redis:
|
||
Host: user-redis-master.juwan.svc.cluster.local:6379
|
||
Type: node
|
||
Pass: ${REDIS_PASSWORD}
|
||
```
|
||
|
||
或使用 port-forward:
|
||
```bash
|
||
kubectl port-forward -n juwan svc/user-redis-master 6379:6379
|
||
```
|
||
|
||
---
|
||
|
||
### 性能优化建议
|
||
|
||
#### 1. 连接池配置
|
||
```go
|
||
PoolSize: runtime.NumCPU() * 2, // CPU 数量的 2 倍
|
||
MinIdleConns: runtime.NumCPU(), // CPU 数量
|
||
MaxConnAge: 30 * time.Minute, // 连接最大存活时间
|
||
```
|
||
|
||
#### 2. 超时配置
|
||
```go
|
||
DialTimeout: 5 * time.Second, // 连接超时
|
||
ReadTimeout: 3 * time.Second, // 读超时
|
||
WriteTimeout: 3 * time.Second, // 写超时
|
||
PoolTimeout: 4 * time.Second, // 获取连接超时
|
||
```
|
||
|
||
#### 3. 命令优化
|
||
```go
|
||
// ❌ 避免:循环中多次调用
|
||
for i := 0; i < 1000; i++ {
|
||
rdb.Set(ctx, fmt.Sprintf("key:%d", i), i)
|
||
}
|
||
|
||
// ✅ 推荐:使用 Pipeline
|
||
pipe := rdb.Pipeline()
|
||
for i := 0; i < 1000; i++ {
|
||
pipe.Set(ctx, fmt.Sprintf("key:%d", i), i, 0)
|
||
}
|
||
pipe.Exec(ctx)
|
||
```
|
||
|
||
#### 4. 缓存策略
|
||
```go
|
||
// Cache-Aside Pattern
|
||
func GetUser(id int64) (*User, error) {
|
||
// 1. 先查缓存
|
||
cacheKey := fmt.Sprintf("user:%d", id)
|
||
cached, err := rdb.Get(ctx, cacheKey).Result()
|
||
if err == nil {
|
||
var user User
|
||
json.Unmarshal([]byte(cached), &user)
|
||
return &user, nil
|
||
}
|
||
|
||
// 2. 缓存未命中,查数据库
|
||
user := queryFromDB(id)
|
||
|
||
// 3. 写入缓存
|
||
userJSON, _ := json.Marshal(user)
|
||
rdb.Set(ctx, cacheKey, userJSON, 1*time.Hour)
|
||
|
||
return user, nil
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 监控配置
|
||
|
||
#### Prometheus 指标采集
|
||
```yaml
|
||
apiVersion: monitoring.coreos.com/v1
|
||
kind: ServiceMonitor
|
||
metadata:
|
||
name: redis-exporter
|
||
namespace: juwan
|
||
spec:
|
||
selector:
|
||
matchLabels:
|
||
app: user-redis
|
||
endpoints:
|
||
- port: redis-exporter # 端口 9121
|
||
interval: 30s
|
||
path: /metrics
|
||
```
|
||
|
||
#### 关键指标监控
|
||
```yaml
|
||
# 告警规则示例
|
||
groups:
|
||
- name: redis
|
||
rules:
|
||
# Redis 实例宕机
|
||
- alert: RedisDown
|
||
expr: redis_up == 0
|
||
for: 1m
|
||
annotations:
|
||
summary: "Redis instance down"
|
||
|
||
# 内存使用率过高
|
||
- alert: RedisMemoryHigh
|
||
expr: redis_memory_used_bytes / redis_memory_max_bytes > 0.9
|
||
for: 5m
|
||
annotations:
|
||
summary: "Redis memory usage > 90%"
|
||
|
||
# 连接数过高
|
||
- alert: RedisConnectionsHigh
|
||
expr: redis_connected_clients > 1000
|
||
for: 5m
|
||
annotations:
|
||
summary: "Redis connections > 1000"
|
||
```
|
||
|
||
---
|
||
|
||
### 安全建议
|
||
|
||
#### 1. 密码管理
|
||
```bash
|
||
# 定期轮换密码
|
||
kubectl create secret generic user-redis \
|
||
--from-literal=password=$(openssl rand -base64 32) \
|
||
--dry-run=client -o yaml | kubectl apply -f -
|
||
|
||
# 重启 Redis Pods 使新密码生效
|
||
kubectl rollout restart statefulset/user-redis -n juwan
|
||
```
|
||
|
||
#### 2. 网络策略
|
||
```yaml
|
||
apiVersion: networking.k8s.io/v1
|
||
kind: NetworkPolicy
|
||
metadata:
|
||
name: redis-access
|
||
namespace: juwan
|
||
spec:
|
||
podSelector:
|
||
matchLabels:
|
||
app: user-redis
|
||
policyTypes:
|
||
- Ingress
|
||
ingress:
|
||
# 只允许同命名空间的 user-rpc 访问
|
||
- from:
|
||
- podSelector:
|
||
matchLabels:
|
||
app: user-rpc
|
||
ports:
|
||
- protocol: TCP
|
||
port: 6379
|
||
```
|
||
|
||
#### 3. TLS 加密(可选)
|
||
```yaml
|
||
# Redis TLS 配置
|
||
apiVersion: redis.redis.opstreelabs.in/v1beta2
|
||
kind: RedisReplication
|
||
metadata:
|
||
name: user-redis
|
||
spec:
|
||
TLS:
|
||
enabled: true
|
||
secret:
|
||
secretName: redis-tls-cert
|
||
```
|
||
|
||
---
|
||
|
||
## 🔍 故障排查
|
||
|
||
### 1. 连接失败
|
||
|
||
**症状**
|
||
```
|
||
Error: dial tcp 10.97.120.76:6379: i/o timeout
|
||
```
|
||
|
||
**排查步骤**
|
||
```bash
|
||
# 1. 检查 Service 是否存在
|
||
kubectl get svc user-redis-master -n juwan
|
||
|
||
# 2. 检查 Endpoints
|
||
kubectl get endpoints user-redis-master -n juwan
|
||
|
||
# 3. 检查 Pod 状态
|
||
kubectl get pods -l app=user-redis -n juwan
|
||
|
||
# 4. 测试网络连通性
|
||
kubectl run -it --rm netshoot --image=nicolaka/netshoot --restart=Never -n juwan -- \
|
||
nc -zv user-redis-master 6379
|
||
|
||
# 5. 查看 Pod 日志
|
||
kubectl logs user-redis-0 -n juwan -c redis
|
||
```
|
||
|
||
---
|
||
|
||
### 2. 认证失败
|
||
|
||
**症状**
|
||
```
|
||
Error: NOAUTH Authentication required
|
||
```
|
||
|
||
**解决方法**
|
||
```bash
|
||
# 1. 确认 Secret 存在
|
||
kubectl get secret user-redis -n juwan
|
||
|
||
# 2. 验证密码
|
||
PASSWORD=$(kubectl get secret user-redis -n juwan -o jsonpath='{.data.password}' | base64 -d)
|
||
echo $PASSWORD
|
||
|
||
# 3. 测试连接
|
||
kubectl exec -it user-redis-0 -n juwan -- redis-cli -a $PASSWORD PING
|
||
```
|
||
|
||
---
|
||
|
||
### 3. 主从复制异常
|
||
|
||
**症状**
|
||
```
|
||
Warning: Redis replica lag is high
|
||
```
|
||
|
||
**排查**
|
||
```bash
|
||
# 在主节点执行
|
||
kubectl exec -it user-redis-0 -n juwan -- redis-cli -a <password> INFO replication
|
||
|
||
# 查看输出
|
||
# role:master
|
||
# connected_slaves:2
|
||
# slave0:ip=10.244.1.10,port=6379,state=online,offset=1234,lag=0
|
||
# slave1:ip=10.244.2.15,port=6379,state=online,offset=1234,lag=0
|
||
```
|
||
|
||
**如果 lag 过大**
|
||
```bash
|
||
# 检查网络延迟
|
||
kubectl exec -it user-redis-0 -n juwan -- ping user-redis-1
|
||
|
||
# 检查 Redis 性能
|
||
kubectl exec -it user-redis-0 -n juwan -- redis-cli -a <password> INFO stats
|
||
```
|
||
|
||
---
|
||
|
||
### 4. Sentinel 无法发现主节点
|
||
|
||
**症状**
|
||
```
|
||
Error: sentinel: no master found
|
||
```
|
||
|
||
**排查**
|
||
```bash
|
||
# 1. 检查 Sentinel 状态
|
||
kubectl exec -it user-redis-sentinel-sentinel-0 -n juwan -- \
|
||
redis-cli -p 26379 SENTINEL masters
|
||
|
||
# 2. 检查主节点地址
|
||
kubectl exec -it user-redis-sentinel-sentinel-0 -n juwan -- \
|
||
redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster
|
||
|
||
# 3. 查看 Sentinel 日志
|
||
kubectl logs user-redis-sentinel-sentinel-0 -n juwan
|
||
|
||
# 4. 手动触发故障转移(慎用)
|
||
kubectl exec -it user-redis-sentinel-sentinel-0 -n juwan -- \
|
||
redis-cli -p 26379 SENTINEL failover mymaster
|
||
```
|
||
|
||
---
|
||
|
||
### 5. 性能问题
|
||
|
||
**慢查询分析**
|
||
```bash
|
||
# 查看慢查询
|
||
kubectl exec -it user-redis-0 -n juwan -- \
|
||
redis-cli -a <password> SLOWLOG GET 10
|
||
|
||
# 设置慢查询阈值(10ms)
|
||
kubectl exec -it user-redis-0 -n juwan -- \
|
||
redis-cli -a <password> CONFIG SET slowlog-log-slower-than 10000
|
||
```
|
||
|
||
**命令统计**
|
||
```bash
|
||
# 查看命令统计
|
||
kubectl exec -it user-redis-0 -n juwan -- \
|
||
redis-cli -a <password> INFO commandstats
|
||
```
|
||
|
||
**内存分析**
|
||
```bash
|
||
# 查看内存使用
|
||
kubectl exec -it user-redis-0 -n juwan -- \
|
||
redis-cli -a <password> INFO memory
|
||
|
||
# 查看大 key
|
||
kubectl exec -it user-redis-0 -n juwan -- \
|
||
redis-cli -a <password> --bigkeys
|
||
```
|
||
|
||
---
|
||
|
||
## 📚 参考资源
|
||
|
||
### 官方文档
|
||
- [Redis Sentinel Documentation](https://redis.io/docs/management/sentinel/)
|
||
- [go-redis Documentation](https://redis.uptrace.dev/)
|
||
- [OpsTree Redis Operator](https://ot-redis-operator.netlify.app/)
|
||
|
||
### 客户端库
|
||
- Go: [github.com/redis/go-redis/v9](https://github.com/redis/go-redis)
|
||
- Python: [redis-py](https://github.com/redis/redis-py)
|
||
- Java: [Spring Data Redis](https://spring.io/projects/spring-data-redis)
|
||
- Node.js: [ioredis](https://github.com/luin/ioredis)
|
||
|
||
### 监控工具
|
||
- [RedisInsight](https://redis.com/redis-enterprise/redis-insight/)
|
||
- [Redis Exporter](https://github.com/oliver006/redis_exporter)
|
||
- Grafana Dashboard: [Redis Dashboard 11835](https://grafana.com/grafana/dashboards/11835)
|
||
|
||
---
|
||
|
||
## 📝 更新日志
|
||
|
||
| 日期 | 版本 | 变更内容 |
|
||
|------|------|---------|
|
||
| 2026-02-22 | 1.0 | 初始版本,包含完整的 Service 介绍和连接指南 |
|
||
|
||
---
|
||
|
||
**文档维护者**: DevOps Team
|
||
**最后更新**: 2026年2月22日
|
||
**下一次审查**: 2026年3月22日
|