780 lines
22 KiB
Markdown
780 lines
22 KiB
Markdown
# Redis Sentinel 部署问题诊断与修复报告
|
||
|
||
**问题日期:** 2026年2月22日
|
||
**命名空间:** juwan
|
||
**涉及资源:** user-rpc deployment, RedisSentinel
|
||
|
||
---
|
||
|
||
## 📋 目录
|
||
|
||
1. [问题背景](#问题背景)
|
||
2. [问题现象](#问题现象)
|
||
3. [诊断过程](#诊断过程)
|
||
4. [根因分析](#根因分析)
|
||
5. [解决方案](#解决方案)
|
||
6. [修复步骤](#修复步骤)
|
||
7. [验证结果](#验证结果)
|
||
8. [后续建议](#后续建议)
|
||
|
||
---
|
||
|
||
## 🎯 问题背景
|
||
|
||
### 部署目标
|
||
部署一个简单的三节点 Redis Sentinel 哨兵集群作为缓存服务,供 user-rpc 服务使用。后续如有需要再扩展为分片集群。
|
||
|
||
### 初始配置
|
||
在 `deploy/k8s/service/user/user-rpc.yaml` 中配置了:
|
||
- user-rpc Deployment(3副本)
|
||
- user-rpc Service
|
||
- HPA(CPU和内存)
|
||
- **RedisSentinel 资源**
|
||
- PostgreSQL Cluster
|
||
|
||
---
|
||
|
||
## 🔴 问题现象
|
||
|
||
### 执行的操作
|
||
```bash
|
||
kubectl apply -f .\deploy\k8s\service\user\user-rpc.yaml
|
||
```
|
||
|
||
### 输出结果
|
||
```
|
||
deployment.apps/user-rpc configured
|
||
service/user-rpc-svc unchanged
|
||
horizontalpodautoscaler.autoscaling/user-rpc-hpa-c unchanged
|
||
horizontalpodautoscaler.autoscaling/user-rpc-hpa-m unchanged
|
||
redissentinel.redis.redis.opstreelabs.in/user-redis unchanged
|
||
cluster.postgresql.cnpg.io/user-db unchanged
|
||
```
|
||
|
||
### 观察到的异常
|
||
查看命名空间资源:
|
||
```bash
|
||
kubectl get all -n juwan
|
||
```
|
||
|
||
**发现:**
|
||
- ✅ user-api pods 正常运行
|
||
- ✅ user-rpc pods 正常运行
|
||
- ✅ PostgreSQL clusters 正常运行
|
||
- ❌ **没有任何 Redis 相关的 Pod**
|
||
- ❌ **没有 Redis Service**
|
||
|
||
---
|
||
|
||
## 🔍 诊断过程
|
||
|
||
### 步骤 1:检查 RedisSentinel 资源状态
|
||
|
||
**目的:** 确认 RedisSentinel 资源是否被成功创建
|
||
|
||
**命令:**
|
||
```bash
|
||
kubectl get redissentinel user-redis -n juwan
|
||
```
|
||
|
||
**输出:**
|
||
```
|
||
NAME AGE
|
||
user-redis 9m56s
|
||
```
|
||
|
||
**分析:**
|
||
- ✅ RedisSentinel 资源已创建
|
||
- ❌ 但没有创建任何 Pod
|
||
- **结论:** Operator 没有按照 RedisSentinel 规格创建实际资源
|
||
|
||
---
|
||
|
||
### 步骤 2:查看 RedisSentinel 详细信息
|
||
|
||
**目的:** 检查资源的详细配置和事件
|
||
|
||
**命令:**
|
||
```bash
|
||
kubectl describe redissentinel user-redis -n juwan
|
||
```
|
||
|
||
**关键输出:**
|
||
```yaml
|
||
API Version: redis.redis.opstreelabs.in/v1beta2
|
||
Kind: RedisSentinel
|
||
Metadata:
|
||
Creation Timestamp: 2026-02-22T12:41:47Z
|
||
Finalizers:
|
||
redisSentinelFinalizer
|
||
Generation: 2
|
||
Spec:
|
||
Cluster Size: 3
|
||
Redis Sentinel Config:
|
||
Redis Replication Name: user-redis # ⚠️ 关键配置
|
||
Master Group Name: myMaster
|
||
Redis Port: 6379
|
||
Quorum: 2
|
||
Events: <none> # ⚠️ 没有任何事件
|
||
```
|
||
|
||
**分析:**
|
||
- 配置中引用了 `redisReplicationName: user-redis`
|
||
- 没有任何 Events,说明 Operator 可能在等待某些前置条件
|
||
- **需要进一步检查依赖资源**
|
||
|
||
---
|
||
|
||
### 步骤 3:检查 Secret 资源
|
||
|
||
**目的:** 确认 RedisSentinel 所需的密码 Secret 是否存在
|
||
|
||
**命令:**
|
||
```bash
|
||
kubectl get secret user-redis -n juwan
|
||
```
|
||
|
||
**输出:**
|
||
```
|
||
NAME TYPE DATA AGE
|
||
user-redis Opaque 1 5h48m
|
||
```
|
||
|
||
**分析:**
|
||
- ✅ Secret 存在,排除认证配置问题
|
||
|
||
---
|
||
|
||
### 步骤 4:查找 Redis Pods
|
||
|
||
**目的:** 确认是否有 Redis Pod 使用不同的命名规则
|
||
|
||
**命令:**
|
||
```bash
|
||
kubectl get pods -n juwan | Select-String redis
|
||
```
|
||
|
||
**输出:**
|
||
```
|
||
(空输出 - 没有找到任何 Redis Pod)
|
||
```
|
||
|
||
**分析:**
|
||
- ❌ 确认没有任何 Redis Pod 被创建
|
||
|
||
---
|
||
|
||
### 步骤 5:检查 StatefulSet
|
||
|
||
**目的:** Redis 通常使用 StatefulSet 部署,检查是否有相关资源
|
||
|
||
**命令:**
|
||
```bash
|
||
kubectl get statefulset -n juwan
|
||
```
|
||
|
||
**输出:**
|
||
```
|
||
No resources found in juwan namespace.
|
||
```
|
||
|
||
**分析:**
|
||
- ❌ 没有 StatefulSet 被创建
|
||
- **结论:** Operator 完全没有执行创建动作
|
||
|
||
---
|
||
|
||
### 步骤 6:检查 Redis Operator 状态
|
||
|
||
**目的:** 确认 Redis Operator 本身是否正常运行
|
||
|
||
**命令:**
|
||
```bash
|
||
kubectl get pods -A | Select-String redis-operator
|
||
```
|
||
|
||
**输出:**
|
||
```
|
||
default redis-operator-7dcf4468c9-gfbcm 1/1 Running 0 4h50m
|
||
ot-operators redis-operator-69bb645f5b-6kxkv 0/1 ErrImageNeverPull 0 4h48m
|
||
```
|
||
|
||
**分析:**
|
||
- ✅ default namespace 中的 Operator 正常运行
|
||
- ⚠️ ot-operators namespace 中的 Operator 镜像拉取失败(但不影响我们的场景)
|
||
|
||
---
|
||
|
||
### 步骤 7:查看 Operator 日志
|
||
|
||
**目的:** 从 Operator 日志中寻找线索
|
||
|
||
**命令:**
|
||
```bash
|
||
kubectl logs redis-operator-7dcf4468c9-gfbcm -n default --tail=50
|
||
```
|
||
|
||
**关键输出:**
|
||
```json
|
||
{"level":"info","ts":"2026-02-22T08:01:56Z","msg":"Starting Controller","controller":"redissentinel"}
|
||
{"level":"info","ts":"2026-02-22T08:01:56Z","msg":"Starting workers","controller":"redissentinel","worker count":1}
|
||
```
|
||
|
||
**分析:**
|
||
- ✅ RedisSentinel Controller 已启动
|
||
- ✅ 没有错误日志
|
||
- ❌ 但也没有处理 user-redis 资源的日志
|
||
- **推测:** Operator 在等待某个依赖资源
|
||
|
||
---
|
||
|
||
### 步骤 8:检查 RedisReplication 资源(关键发现)
|
||
|
||
**目的:** 根据 RedisSentinel 配置中的 `redisReplicationName: user-redis`,检查对应的 RedisReplication 是否存在
|
||
|
||
**命令:**
|
||
```bash
|
||
kubectl get redisreplication -n juwan
|
||
```
|
||
|
||
**输出:**
|
||
```
|
||
No resources found in juwan namespace.
|
||
```
|
||
|
||
**分析:**
|
||
- ❌ **RedisReplication 资源不存在!**
|
||
- 🔎 **这就是问题的根本原因**
|
||
|
||
---
|
||
|
||
## 💡 根因分析
|
||
|
||
### 问题根源
|
||
|
||
**RedisSentinel 依赖 RedisReplication,但配置中只创建了 RedisSentinel,没有创建 RedisReplication。**
|
||
|
||
### Redis Operator 架构理解
|
||
|
||
在 OpsTree Redis Operator 中,资源之间的关系如下:
|
||
|
||
```
|
||
┌─────────────────────────────────────────┐
|
||
│ RedisSentinel (哨兵层) │
|
||
│ - 3个 Sentinel 节点 │
|
||
│ - 负责监控和自动故障转移 │
|
||
│ - 引用: redisReplicationName │
|
||
└──────────────┬──────────────────────────┘
|
||
│ 监控
|
||
↓
|
||
┌─────────────────────────────────────────┐
|
||
│ RedisReplication (数据层) │
|
||
│ - 1个 Master + N个 Replica │
|
||
│ - 提供实际的缓存服务 │
|
||
│ - 主从复制 │
|
||
└─────────────────────────────────────────┘
|
||
```
|
||
|
||
### 错误配置的问题
|
||
|
||
原始配置直接创建了 RedisSentinel,但:
|
||
|
||
1. **缺少被监控对象:** Sentinel 需要监控一个 RedisReplication 集群
|
||
2. **引用不存在的资源:** `redisReplicationName: user-redis` 指向一个不存在的 RedisReplication
|
||
3. **Operator 行为:** Operator 发现依赖的 RedisReplication 不存在,因此不会创建 Sentinel Pod
|
||
|
||
### 为什么没有错误提示?
|
||
|
||
- CRD 验证只检查语法和字段类型
|
||
- 资源引用关系由 Operator 运行时检查
|
||
- Operator 采用了"等待依赖"策略,而不是报错
|
||
|
||
---
|
||
|
||
## ✅ 解决方案
|
||
|
||
### 正确的部署顺序
|
||
|
||
1. **先创建 RedisReplication**(建立 Redis 主从复制集群)
|
||
2. **再创建 RedisSentinel**(监控上述复制集群)
|
||
|
||
### 配置结构
|
||
|
||
```yaml
|
||
# 第一步:创建 Redis 主从复制(数据层)
|
||
apiVersion: redis.redis.opstreelabs.in/v1beta2
|
||
kind: RedisReplication
|
||
metadata:
|
||
name: user-redis # Sentinel 将引用这个名称
|
||
namespace: juwan
|
||
spec:
|
||
clusterSize: 3 # 1 Master + 2 Replicas
|
||
kubernetesConfig:
|
||
image: quay.io/opstree/redis:v7.0.12
|
||
resources:
|
||
requests:
|
||
cpu: 100m
|
||
memory: 128Mi
|
||
limits:
|
||
cpu: 500m
|
||
memory: 512Mi
|
||
redisSecret:
|
||
name: user-redis
|
||
key: password
|
||
storage:
|
||
volumeClaimTemplate:
|
||
spec:
|
||
accessModes: ["ReadWriteOnce"]
|
||
resources:
|
||
requests:
|
||
storage: 1Gi # 每个 Redis 节点 1GB 存储
|
||
|
||
---
|
||
# 第二步:创建 Sentinel 监控(监控层)
|
||
apiVersion: redis.redis.opstreelabs.in/v1beta2
|
||
kind: RedisSentinel
|
||
metadata:
|
||
name: user-redis-sentinel # 使用不同的名称避免混淆
|
||
namespace: juwan
|
||
spec:
|
||
clusterSize: 3 # 3个 Sentinel 节点(推荐奇数)
|
||
kubernetesConfig:
|
||
image: quay.io/opstree/redis-sentinel:v7.0.12 # 使用 Sentinel 专用镜像
|
||
redisSentinelConfig:
|
||
redisReplicationName: user-redis # 引用上面的 RedisReplication
|
||
masterGroupName: mymaster
|
||
quorum: "2" # 需要 2 个 Sentinel 同意才能进行故障转移
|
||
```
|
||
|
||
---
|
||
|
||
## 🔧 修复步骤
|
||
|
||
### 步骤 1:删除错误的 RedisSentinel 资源
|
||
|
||
**命令:**
|
||
```bash
|
||
kubectl delete redissentinel user-redis -n juwan
|
||
```
|
||
|
||
**输出:**
|
||
```
|
||
redissentinel.redis.redis.opstreelabs.in "user-redis" deleted
|
||
```
|
||
|
||
**说明:** 删除仅创建了 CRD 实例但未创建实际 Pod 的资源
|
||
|
||
---
|
||
|
||
### 步骤 2:更新配置文件
|
||
|
||
修改 `deploy/k8s/service/user/user-rpc.yaml`,将单独的 RedisSentinel 替换为:
|
||
1. RedisReplication(数据层)
|
||
2. RedisSentinel(监控层)
|
||
|
||
**变更内容:**
|
||
- 添加 `RedisReplication` 资源定义
|
||
- 添加 `storage.volumeClaimTemplate` 配置
|
||
- 修改 RedisSentinel 的 `metadata.name` 为 `user-redis-sentinel`
|
||
- 使用正确的 Sentinel 镜像:`quay.io/opstree/redis-sentinel:v7.0.12`
|
||
- 完善 Sentinel 配置参数
|
||
|
||
---
|
||
|
||
### 步骤 3:应用更新后的配置
|
||
|
||
**命令:**
|
||
```bash
|
||
kubectl apply -f .\deploy\k8s\service\user\user-rpc.yaml
|
||
```
|
||
|
||
**输出:**
|
||
```
|
||
deployment.apps/user-rpc configured
|
||
service/user-rpc-svc unchanged
|
||
horizontalpodautoscaler.autoscaling/user-rpc-hpa-c unchanged
|
||
horizontalpodautoscaler.autoscaling/user-rpc-hpa-m unchanged
|
||
redisreplication.redis.redis.opstreelabs.in/user-redis created ✅
|
||
redissentinel.redis.redis.opstreelabs.in/user-redis-sentinel created ✅
|
||
cluster.postgresql.cnpg.io/user-db unchanged
|
||
```
|
||
|
||
**分析:**
|
||
- ✅ RedisReplication 成功创建
|
||
- ✅ RedisSentinel 成功创建
|
||
- 🎯 两个资源都是新创建(created),符合预期
|
||
|
||
---
|
||
|
||
## ✅ 验证结果
|
||
|
||
### 验证 1:检查 Pod 创建情况(等待 30 秒)
|
||
|
||
**命令:**
|
||
```bash
|
||
kubectl get statefulset,pods -n juwan | Select-String -Pattern "user-redis|NAME"
|
||
```
|
||
|
||
**输出:**
|
||
```
|
||
NAME READY AGE
|
||
statefulset.apps/user-redis 3/3 81s ✅
|
||
statefulset.apps/user-redis-sentinel-sentinel 3/3 24s ✅
|
||
|
||
NAME READY STATUS RESTARTS AGE
|
||
pod/user-redis-0 2/2 Running 0 80s ✅
|
||
pod/user-redis-1 2/2 Running 0 52s ✅
|
||
pod/user-redis-2 2/2 Running 0 47s ✅
|
||
pod/user-redis-sentinel-sentinel-0 1/1 Running 0 24s ✅
|
||
pod/user-redis-sentinel-sentinel-1 1/1 Running 0 8s ✅
|
||
pod/user-redis-sentinel-sentinel-2 1/1 Running 0 5s ✅
|
||
```
|
||
|
||
**分析:**
|
||
- ✅ **RedisReplication** 创建了 3 个 Pod(user-redis-0/1/2)
|
||
- 每个 Pod 有 2 个容器(2/2):Redis + Exporter
|
||
- 所有 Pod 处于 Running 状态
|
||
- ✅ **RedisSentinel** 创建了 3 个 Pod(user-redis-sentinel-sentinel-0/1/2)
|
||
- 每个 Pod 有 1 个容器(1/1):Sentinel
|
||
- 所有 Pod 处于 Running 状态
|
||
- ✅ 创建了 2 个 StatefulSet,READY 状态为 3/3
|
||
|
||
---
|
||
|
||
### 验证 2:检查 Service 资源
|
||
|
||
**命令:**
|
||
```bash
|
||
kubectl get svc -n juwan | Select-String -Pattern "redis|NAME"
|
||
```
|
||
|
||
**输出:**
|
||
```
|
||
NAME TYPE CLUSTER-IP PORT(S) AGE
|
||
user-redis ClusterIP 10.103.91.84 6379/TCP,9121/TCP 95s ✅
|
||
user-redis-additional ClusterIP 10.107.228.48 6379/TCP 95s
|
||
user-redis-headless ClusterIP None 6379/TCP 95s ✅
|
||
user-redis-master ClusterIP 10.97.120.76 6379/TCP 95s ✅
|
||
user-redis-replica ClusterIP 10.100.213.103 6379/TCP 95s ✅
|
||
user-redis-sentinel-sentinel ClusterIP 10.105.28.231 26379/TCP 40s ✅
|
||
user-redis-sentinel-sentinel-additional ClusterIP 10.97.111.42 26379/TCP 39s
|
||
user-redis-sentinel-sentinel-headless ClusterIP None 26379/TCP 41s
|
||
```
|
||
|
||
**Service 功能说明:**
|
||
|
||
#### Redis 数据层 Service(端口 6379)
|
||
- **user-redis-master**: 主节点服务,用于写操作
|
||
- **user-redis-replica**: 从节点服务,用于读操作
|
||
- **user-redis**: 通用访问入口(负载均衡到所有节点)
|
||
- **user-redis-headless**: 无头服务,用于 StatefulSet Pod 间通信
|
||
- **user-redis-additional**: 额外的访问入口
|
||
|
||
#### Sentinel 监控层 Service(端口 26379)
|
||
- **user-redis-sentinel-sentinel**: Sentinel 访问入口
|
||
- **user-redis-sentinel-sentinel-headless**: Sentinel 节点间通信
|
||
- **user-redis-sentinel-sentinel-additional**: 额外的 Sentinel 访问入口
|
||
|
||
---
|
||
|
||
### 验证 3:检查完整的集群状态
|
||
|
||
**命令:**
|
||
```bash
|
||
kubectl get all -n juwan
|
||
```
|
||
|
||
**最终状态统计:**
|
||
|
||
| 资源类型 | 名称 | 数量 | 状态 |
|
||
|---------|------|------|------|
|
||
| **Deployment** | user-api | 3/3 | ✅ Running |
|
||
| **Deployment** | user-rpc | 3/3 | ✅ Running |
|
||
| **StatefulSet** | cluster-example (PostgreSQL) | 3/3 | ✅ Running |
|
||
| **StatefulSet** | user-db (PostgreSQL) | 3/3 | ✅ Running |
|
||
| **StatefulSet** | user-redis (Redis 数据) | 3/3 | ✅ Running |
|
||
| **StatefulSet** | user-redis-sentinel-sentinel | 3/3 | ✅ Running |
|
||
|
||
**Pod 总计:** 18 个(全部 Running)
|
||
**Service 总计:** 13 个
|
||
**HPA 总计:** 6 个
|
||
|
||
---
|
||
|
||
## 📊 架构图
|
||
|
||
### 部署后的 Redis 架构
|
||
|
||
```
|
||
┌────────────────────────────────────────────────────────────┐
|
||
│ 应用层 (user-rpc) │
|
||
│ │
|
||
│ [需要添加 Redis 连接配置] │
|
||
└──────────┬─────────────────────────────┬───────────────────┘
|
||
│ │
|
||
│ 写操作 │ 读操作
|
||
↓ ↓
|
||
┌─────────────┐ ┌─────────────┐
|
||
│ user-redis- │ │ user-redis- │
|
||
│ master │ │ replica │
|
||
│ Service │ │ Service │
|
||
└─────────────┘ └─────────────┘
|
||
│ │
|
||
└──────────┬──────────────────┘
|
||
↓
|
||
┌──────────────────────────────────────────┐
|
||
│ RedisReplication (数据层) │
|
||
│ │
|
||
│ ┌──────────┐ ┌──────────┐ ┌───────┐ │
|
||
│ │ Master │→ │ Replica │→ │Replica│ │
|
||
│ │ redis-0 │ │ redis-1 │ │redis-2│ │
|
||
│ └──────────┘ └──────────┘ └───────┘ │
|
||
└──────────────────────────────────────────┘
|
||
↑
|
||
│ 监控 & 故障转移
|
||
│
|
||
┌──────────────────────────────────────────┐
|
||
│ RedisSentinel (监控层) │
|
||
│ │
|
||
│ ┌──────────┐ ┌──────────┐ ┌───────┐ │
|
||
│ │Sentinel-0│ │Sentinel-1│ │Sentinel-2│
|
||
│ └──────────┘ └──────────┘ └───────┘ │
|
||
│ │
|
||
│ Quorum: 2/3 (多数派决策) │
|
||
└──────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 📝 后续建议
|
||
|
||
### 1. 应用集成 Redis
|
||
|
||
user-rpc 服务目前还没有配置 Redis 连接,需要:
|
||
|
||
#### 修改配置文件 `app/users/rpc/etc/pb.yaml`
|
||
```yaml
|
||
Name: pb.rpc
|
||
ListenOn: 0.0.0.0:8080
|
||
|
||
# 添加 Redis 配置(使用 Sentinel 模式)
|
||
Redis:
|
||
- Host: user-redis-sentinel-sentinel:26379
|
||
Type: sentinel
|
||
MasterName: mymaster
|
||
Pass: ${REDIS_PASSWORD}
|
||
|
||
# 或使用主从模式
|
||
# Redis:
|
||
# - Host: user-redis-master:6379 # 写
|
||
# Type: node
|
||
# Pass: ${REDIS_PASSWORD}
|
||
# - Host: user-redis-replica:6379 # 读
|
||
# Type: node
|
||
# Pass: ${REDIS_PASSWORD}
|
||
|
||
Etcd:
|
||
Hosts:
|
||
- etcd-service:2379 # 需要配置实际的 Etcd 地址
|
||
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 配置
|
||
}
|
||
```
|
||
|
||
#### 初始化 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 // 添加 Redis 客户端
|
||
}
|
||
|
||
func NewServiceContext(c config.Config) *ServiceContext {
|
||
return &ServiceContext{
|
||
Config: c,
|
||
Redis: redis.MustNewRedis(c.Redis), // 初始化 Redis
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 更新 Deployment 环境变量
|
||
```yaml
|
||
# deploy/k8s/service/user/user-rpc.yaml
|
||
env:
|
||
- name: DB_URI
|
||
valueFrom:
|
||
secretKeyRef:
|
||
name: user-db-app
|
||
key: uri
|
||
- name: REDIS_PASSWORD # 添加 Redis 密码
|
||
valueFrom:
|
||
secretKeyRef:
|
||
name: user-redis
|
||
key: password
|
||
```
|
||
|
||
---
|
||
|
||
### 2. Redis 性能监控
|
||
|
||
已启用 Redis Exporter(端口 9121),可以配置 Prometheus 监控:
|
||
|
||
```yaml
|
||
apiVersion: v1
|
||
kind: ServiceMonitor
|
||
metadata:
|
||
name: user-redis-metrics
|
||
namespace: juwan
|
||
spec:
|
||
selector:
|
||
matchLabels:
|
||
app: user-redis
|
||
endpoints:
|
||
- port: redis-exporter
|
||
interval: 30s
|
||
```
|
||
|
||
**监控指标:**
|
||
- redis_up: 实例状态
|
||
- redis_connected_clients: 连接数
|
||
- redis_memory_used_bytes: 内存使用
|
||
- redis_commands_processed_total: 命令处理数
|
||
- redis_master_repl_offset: 复制偏移量
|
||
|
||
---
|
||
|
||
### 3. 高可用性测试
|
||
|
||
#### 测试主节点故障转移
|
||
```bash
|
||
# 1. 查找当前主节点
|
||
kubectl exec -it user-redis-sentinel-sentinel-0 -n juwan -- redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster
|
||
|
||
# 2. 模拟主节点故障
|
||
kubectl delete pod user-redis-0 -n juwan
|
||
|
||
# 3. 观察 Sentinel 的故障转移过程
|
||
kubectl logs -f user-redis-sentinel-sentinel-0 -n juwan
|
||
|
||
# 4. 确认新主节点
|
||
kubectl exec -it user-redis-sentinel-sentinel-0 -n juwan -- redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster
|
||
```
|
||
|
||
#### 预期结果
|
||
- Sentinel 检测到主节点下线(5 秒)
|
||
- 2/3 Sentinel 节点达成共识(quorum=2)
|
||
- 自动提升一个从节点为主节点
|
||
- 客户端自动重连到新主节点
|
||
|
||
---
|
||
|
||
### 4. 扩展为分片集群(未来)
|
||
|
||
当缓存数据量增长需要横向扩展时,可以迁移到 RedisCluster:
|
||
|
||
```yaml
|
||
apiVersion: redis.redis.opstreelabs.in/v1beta2
|
||
kind: RedisCluster
|
||
metadata:
|
||
name: user-redis-cluster
|
||
namespace: juwan
|
||
spec:
|
||
clusterSize: 6 # 3 主 + 3 从
|
||
kubernetesConfig:
|
||
image: quay.io/opstree/redis:v7.0.12
|
||
redisLeader:
|
||
replicas: 3
|
||
redisFollower:
|
||
replicas: 3
|
||
storage:
|
||
volumeClaimTemplate:
|
||
spec:
|
||
accessModes: ["ReadWriteOnce"]
|
||
resources:
|
||
requests:
|
||
storage: 5Gi
|
||
```
|
||
|
||
**迁移步骤:**
|
||
1. 部署新的 RedisCluster
|
||
2. 使用 redis-cli --cluster import 迁移数据
|
||
3. 更新应用配置指向新集群
|
||
4. 下线旧的 Sentinel 集群
|
||
|
||
---
|
||
|
||
### 5. 备份策略
|
||
|
||
Redis Operator 不提供自动备份,建议配置定时任务:
|
||
|
||
```bash
|
||
# 创建 CronJob 定期执行 BGSAVE
|
||
apiVersion: batch/v1
|
||
kind: CronJob
|
||
metadata:
|
||
name: redis-backup
|
||
namespace: juwan
|
||
spec:
|
||
schedule: "0 2 * * *" # 每天凌晨 2 点
|
||
jobTemplate:
|
||
spec:
|
||
template:
|
||
spec:
|
||
containers:
|
||
- name: backup
|
||
image: redis:7.0.12
|
||
command:
|
||
- /bin/sh
|
||
- -c
|
||
- |
|
||
redis-cli -h user-redis-master -a $REDIS_PASSWORD BGSAVE
|
||
# 将 /data/dump.rdb 上传到对象存储
|
||
restartPolicy: OnFailure
|
||
```
|
||
|
||
---
|
||
|
||
## 📚 总结
|
||
|
||
### 关键经验
|
||
|
||
1. **理解资源依赖关系:** RedisSentinel 依赖 RedisReplication,部署顺序很重要
|
||
2. **资源命名规范:** 使用清晰的名称区分不同层次的资源(如 user-redis 和 user-redis-sentinel)
|
||
3. **诊断思路:**
|
||
- 从现象(Pod 缺失)→ 资源状态(CRD 存在)→ Operator 日志 → 依赖检查
|
||
- 逐层排查,最终定位到 RedisReplication 缺失
|
||
4. **验证完整性:** 不仅要检查 Pod,还要验证 Service、StatefulSet 等所有相关资源
|
||
|
||
### 文档价值
|
||
|
||
本文档可用于:
|
||
- ✅ 团队知识传承
|
||
- ✅ 类似问题的快速排查手册
|
||
- ✅ 新成员的 Redis Operator 学习资料
|
||
- ✅ 事后复盘和经验总结
|
||
|
||
---
|
||
|
||
**最后更新时间:** 2026年2月22日
|
||
**文档状态:** ✅ 问题已解决,Redis 集群运行正常
|
||
**下一步行动:** 配置应用连接 Redis
|