# Redis Kubernetes Service 详细解析

**问题：** 为什么 Redis 有 8 个 Service，但应用配置中只使用 `user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379`？

**日期：** 2026年2月22日

---

## 📋 目录

1. [Service 概览](#service-概览)
2. [Kubernetes Service 基础](#kubernetes-service-基础)
3. [8 个 Service 的详细说明](#8-个-service-的详细说明)
4. [为什么使用哪个 Service](#为什么使用哪个-service)
5. [Service 创建原理](#service-创建原理)
6. [网络流量路由](#网络流量路由)
7. [故障排查](#故障排查)

---

## 📊 Service 概览

### 当前 Redis 的 8 个 Service

```bash
$ kubectl get svc -n juwan | grep redis

NAME                                  TYPE        CLUSTER-IP       PORTS
user-redis                            ClusterIP   10.103.91.84     6379/TCP,9121/TCP   33m
user-redis-additional                 ClusterIP   10.107.228.48    6379/TCP            33m
user-redis-headless                   ClusterIP   None             6379/TCP            33m
user-redis-master                     ClusterIP   10.97.120.76     6379/TCP            33m
user-redis-replica                    ClusterIP   10.100.213.103   6379/TCP            33m
user-redis-sentinel-sentinel          ClusterIP   10.105.28.231    26379/TCP           32m
user-redis-sentinel-sentinel-additional ClusterIP  10.97.111.42     26379/TCP           32m
user-redis-sentinel-sentinel-headless ClusterIP   None             26379/TCP           32m
```

### 按功能分类

| 分类 | Service 名称 | 作用 |
|-----|-------------|------|
| **Redis 数据层** | user-redis | 通用入口 |
| | user-redis-additional | 备用入口 |
| | user-redis-master | 主节点专用 |
| | user-redis-replica | 从节点专用 |
| | user-redis-headless | Pod 间通信 |
| **Sentinel 监控层** | user-redis-sentinel-sentinel | Sentinel 入口 ⭐ |
| | user-redis-sentinel-sentinel-additional | 备用入口 |
| | user-redis-sentinel-sentinel-headless | Sentinel 间通信 |

---

## 🔷 Kubernetes Service 基础

### Service 的作用

**Kubernetes 中的 Service 是什么？**

```
┌─────────────────────────────────────────────────┐
│                  Kubernetes Cluster             │
│                                                 │
│  Service (虚拟 IP + DNS)                        │
│  ↓                                              │
│  Endpoints (实际 Pod IP 列表)                    │
│  ├─ 10.244.0.10:6379  (Pod 1)                   │
│  ├─ 10.244.1.20:6379  (Pod 2)                   │
│  └─ 10.244.2.30:6379  (Pod 3)                   │
│                                                 │
│  客户端 ──→ Service IP (稳定) ──→ Pod IP (变化)   │
└─────────────────────────────────────────────────┘
```

### Service 的三种类型

| 类型 | CLUSTER-IP | 用途 | 示例 |
|-----|-----------|------|------|
| **ClusterIP** | ✅ 有 | 集群内访问 | 10.103.91.84 |
| **ClusterIP<br/>(Headless)** | ❌ None | Pod 间直接通信 | None |
| **NodePort** | ✅ 有 | 集群外访问 | 10.103.91.84 |

---

## 🔍 8 个 Service 的详细说明

### 第一组：Redis 数据层 Service（端口 6379）

#### 1️⃣ user-redis（ClusterIP）

**基本信息：**
```yaml
名称: user-redis
类型: ClusterIP (有负载均衡)
Cluster IP: 10.103.91.84
端口: 6379/TCP, 9121/TCP
DNS: user-redis.juwan.svc.cluster.local
```

**Endpoints 信息：**
```bash
$ kubectl get endpoints user-redis -n juwan

NAME         ENDPOINTS
user-redis   10.244.0.10:6379,10.244.1.20:6379,10.244.2.30:6379
```

**负载均衡机制：**
```
客户端请求 ──→ Service IP (10.103.91.84)
                     ↓
              kube-proxy (iptables/ipvs)
                     ↓
            随机选择一个 Pod
            ├─ 10.244.0.10 (redis-0)
            ├─ 10.244.1.20 (redis-1)  ← 可能
            └─ 10.244.2.30 (redis-2)
```

**特点：**
- ✅ 对所有 Pod 轮询负载均衡
- ✅ 包含 Redis 数据服务（6379）和 Exporter（9121）
- ⚠️ 可能把写请求轮询到从节点导致失败

**适用场景：**
- 监控抓取（Prometheus 从 9121 端口抓指标）
- 不关心读写分离的简单查询

**为什么有 2 个端口？**
```
6379: Redis 数据服务
9121: Prometheus Exporter 监控端口
      └─ 暴露 Redis 性能指标给 Prometheus
         (redis_up, redis_memory_used, etc.)
```

**不用这个的原因：**
```
❌ 如果直接使用 user-redis 进行读写：
   ├─ 写请求可能被路由到从节点 (error)
   ├─ 无法进行故障自动转移
   └─ 依赖于手动更新配置
```

---

#### 2️⃣ user-redis-additional（ClusterIP）

**基本信息：**
```yaml
名称: user-redis-additional
类型: ClusterIP (有负载均衡)
Cluster IP: 10.107.228.48
端口: 6379/TCP
Endpoints: 同 user-redis
```

**作用：**
- 功能完全同 `user-redis`
- 提供额外的访问入口
- 用于多租户/网络隔离场景

**为什么有这个？**
```
场景：某些网络策略可能只允许访问特定 Service
└─ 额外的 Service 提供备用入口
```

**不常用的原因：**
- 大多数场景用 `user-redis` 就足够
- `user-redis-additional` 是备用

---

#### 3️⃣ user-redis-headless（ClusterIP: None）

**基本信息：**
```yaml
名称: user-redis-headless
类型: ClusterIP (Headless Service)
Cluster IP: None  ← 关键：无虚拟 IP
端口: 6379/TCP
DNS: user-redis-headless.juwan.svc.cluster.local
```

**特殊之处：无虚拟 IP**

```bash
# 正常 Service 查询返回虚拟 IP
$ nslookup user-redis.juwan.svc.cluster.local
Name: user-redis.juwan.svc.cluster.local
Address: 10.103.91.84  ← 虚拟 IP

# Headless Service 查询返回所有 Pod IP
$ nslookup user-redis-headless.juwan.svc.cluster.local
Name: user-redis-headless.juwan.svc.cluster.local
Address: 10.244.0.10   ← Pod 1 实际 IP
Address: 10.244.1.20   ← Pod 2 实际 IP
Address: 10.244.2.30   ← Pod 3 实际 IP
```

**使用场景：**

```
┌─────────────────────────────────────────────────┐
│  StatefulSet (Redis Cluster/Replication)       │
│                                                 │
│  redis-0 (主)   redis-1 (从)   redis-2 (从)    │
│     ↓               ↓               ↓           │
│  10.244.0.10   10.244.1.20    10.244.2.30      │
│                    ↑                            │
│  需要直接连接到特定 Pod：                        │
│  redis-0.user-redis-headless  (连接主节点)      │
│  redis-1.user-redis-headless  (连接从节点)      │
└─────────────────────────────────────────────────┘
```

**谁在使用？**
- Redis 主从复制：从节点需要连接到已知的主节点
- Sentinel 监控：需要直接访问特定 Redis 实例
- Redis Operator 内部使用

**为什么应用不用这个？**
```
❌ Pod DNS 只能在 Pod 内使用
   └─ 外部应用不知道 Pod 的具体 DNS 名称

✅ 用虚拟 Service IP 的优势
   └─ 无需关心底层 Pod 变化
```

---

#### 4️⃣ user-redis-master（ClusterIP）

**基本信息：**
```yaml
名称: user-redis-master
类型: ClusterIP
Cluster IP: 10.97.120.76
端口: 6379/TCP
Endpoints: 10.244.0.10:6379  (只有 1 个 Pod)
DNS: user-redis-master.juwan.svc.cluster.local
```

**特点：只指向主节点**

```bash
$ kubectl get endpoints user-redis-master -n juwan

NAME                ENDPOINTS
user-redis-master   10.244.0.10:6379  ← 仅主节点
```

**对比所有 Endpoints：**
```
user-redis-master:  10.244.0.10        (主)
user-redis-replica: 10.244.1.20, 10.244.2.30  (从)
user-redis:         所有 Pod
```

**为什么分开？**
```
┌─────────────────────────────────────────┐
│        Redis 主从架构                    │
│                                         │
│  Redis Master (10.244.0.10)             │
│    ├─ 处理所有写操作                     │
│    └─ 赋值数据给 Slave                   │
│                                         │
│  Redis Slave 1 (10.244.1.20)            │
│    └─ 处理只读操作                       │
│                                         │
│  Redis Slave 2 (10.244.2.30)            │
│    └─ 处理只读操作                       │
└─────────────────────────────────────────┘

请求分类：
┌───────────────────────┐
│ SET key value         │ ──→ user-redis-master (10.97.120.76)
│ HSET user:1 name john │
└───────────────────────┘

┌───────────────────────┐
│ GET key               │ ──→ user-redis-replica (10.100.213.103)
│ HGET user:1 name      │
└───────────────────────┘
```

**适用场景：**
- ✅ 读写分离架构
- ✅ 优化读性能（从节点处理读）
- ✅ 减轻主节点负担

**为什么应用通常不直接用？**
```
❌ 需要在应用层面区分读写操作
   ├─ 写操作 → user-redis-master
   ├─ 只读操作 → user-redis-replica
   └─ 代码复杂度高

✅ Sentinel 模式自动处理
   └─ 应用无需关心主从区别
```

---

#### 5️⃣ user-redis-replica（ClusterIP）

**基本信息：**
```yaml
名称: user-redis-replica
类型: ClusterIP
Cluster IP: 10.100.213.103
端口: 6379/TCP
Endpoints: 10.244.1.20:6379, 10.244.2.30:6379  (两个从节点)
DNS: user-redis-replica.juwan.svc.cluster.local
```

**特点：只指向从节点，支持负载均衡**

```bash
$ kubectl get endpoints user-redis-replica -n juwan

NAME                 ENDPOINTS
user-redis-replica   10.244.1.20:6379, 10.244.2.30:6379
```

**读流量分散：**
```
应用发送 GET 请求
          ↓
   user-redis-replica (10.100.213.103)
          ↓
   随机选择一个从节点
   ├─ 10.244.1.20 (redis-1) ← 可能
   └─ 10.244.2.30 (redis-2) ← 可能
```

**适用场景：**
- 除了 Sentinel 模式外的读优化
- 需要手动管理读写分离

---

### 第二组：Sentinel 监控层 Service（端口 26379）

#### 6️⃣ user-redis-sentinel-sentinel（ClusterIP）⭐⭐⭐

**基本信息：**
```yaml
名称: user-redis-sentinel-sentinel
类型: ClusterIP
Cluster IP: 10.105.28.231
端口: 26379/TCP
Endpoints: 10.244.0.50:26379, 10.244.1.70:26379, 10.244.2.90:26379
           (3 个 Sentinel 实例)
DNS: user-redis-sentinel-sentinel.juwan.svc.cluster.local
```

**为什么应用使用这个？**

```
应用程序配置：
┌──────────────────────────────────────────────┐
│ Redis:                                       │
│   Host: user-redis-sentinel-sentinel         │
│   Port: 26379                                │
│   Type: sentinel                             │
│   MasterName: mymaster                       │
└──────────────────────────────────────────────┘

连接流程：
┌─────────────────────────────────────────────┐
│                 应用程序                     │
└────────────────────┬────────────────────────┘
                     │
                     ↓
┌─────────────────────────────────────────────┐
│  user-redis-sentinel-sentinel (26379)        │
│  ├─ Sentinel 1: 10.244.0.50:26379           │
│  ├─ Sentinel 2: 10.244.1.70:26379           │
│  └─ Sentinel 3: 10.244.2.90:26379           │
└────────────────────┬────────────────────────┘
                     │
         应用询问: "mymaster 在哪？"
                     ↓
         Sentinel 回答: "在 10.244.0.10:6379"
                     ↓
┌─────────────────────────────────────────────┐
│  Redis Master: 10.244.0.10:6379              │
│  (应用直接连接进行读写)                      │
└─────────────────────────────────────────────┘

故障转移过程：
Master 故障 → Sentinel 检测 → 提升新主节点
           → 应用下次查询时 → 获得新主节点 IP
           → 自动连接新主节点
```

**为什么这是最佳选择？**

1. **自动故障转移**
   ```
   主节点宕机 (✗) → Sentinel 自动选举新主 → 应用自动连接
   ```

2. **高可用**
   ```
   Sentinel 集群(3 个) → 任意 1-2 个故障仍可用
   ```

3. **应用无感知**
   ```
   应用只需配置 MasterName: mymaster
   无需关心主从地址变化
   ```

4. **标准做法**
   ```
   ✅ 业界公认的 Redis 高可用方案
   ✅ 最小化应用改动
   ✅ 自动化程度最高
   ```

**为什么不用其他 Service？**

```
❌ user-redis-master/user-redis-replica
   └─ 需要应用层区分读写，主从切换需要重启应用

❌ user-redis/user-redis-additional
   └─ 没有故障转移能力，故障时应用会报错

✅ user-redis-sentinel-sentinel
   └─ 自动发现新主节点，无需重启应用
```

---

#### 7️⃣ user-redis-sentinel-sentinel-additional（ClusterIP）

**说明：** 功能同 `user-redis-sentinel-sentinel`，备用入口

---

#### 8️⃣ user-redis-sentinel-sentinel-headless（ClusterIP: None）

**说明：** 供 Sentinel 内部通信和选举使用

---

## 🎯 为什么使用哪个 Service

### 应用配置选择

#### ⭐⭐⭐ Sentinel 模式（生产推荐）

```yaml
# 应用配置
Redis:
  Host: user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379
  Type: sentinel
  MasterName: mymaster
  Pass: ${REDIS_PASSWORD}
```

**优势：**
- ✅ 自动故障转移（RTO < 30 秒）
- ✅ 应用无需重启
- ✅ 自动发现新主节点
- ✅ 生产标准做法

---

#### ⭐⭐ 主从分离模式（可选）

```yaml
# 应用配置（需要两个 host）
Redis:
  Master:
    Host: user-redis-master.juwan.svc.cluster.local:6379
  Slave:
    Host: user-redis-replica.juwan.svc.cluster.local:6379
```

**适用场景：**
- 读写分离显著
- 对读性能有极高要求

**缺点：**
- 主从故障需手动切换
- 应用层复杂度高

---

#### ❌ 不推荐的做法

```yaml
# ❌ 直接连接单个节点
Redis:
  Host: user-redis-0.user-redis-headless.juwan.svc.cluster.local:6379
  # 问题：Pod 重启 IP 变化，需要更新配置

# ❌ 连接通用 Service（无故障转移）
Redis:
  Host: user-redis.juwan.svc.cluster.local:6379
  # 问题：无法自动转移，故障时应用报错

# ❌ 硬编码 Pod IP
Redis:
  Host: 10.244.0.10:6379
  # 问题：Pod 重启 IP 变化，应用立即不可用
```

---

## 🔌 Service 创建原理

### 为什么会自动创建这么多 Service？

**由 Redis Operator 自动创建：**

```go
// Redis Operator 逻辑（伪代码）
func CreateServicesForRedis(redis *RedisReplication) {
    // 数据层 Service
    CreateService("user-redis", AllRedisNodes)
    CreateService("user-redis-additional", AllRedisNodes)
    CreateService("user-redis-master", [MasterNode])
    CreateService("user-redis-replica", [SlaveNodes])
    CreateHeadlessService("user-redis-headless", AllRedisNodes)
    
    // 监控层 Service
    CreateService("user-redis-sentinel-sentinel", AllSentinelNodes)
    CreateService("user-redis-sentinel-sentinel-additional", AllSentinelNodes)
    CreateHeadlessService("user-redis-sentinel-sentinel-headless", AllSentinelNodes)
}
```

**为什么这样设计？**

| Service | 原因 |
|---------|------|
| 多个 ClusterIP | 不同场景需要不同的 Endpoints 配置 |
| 包含 additional | 网络隔离/多租户支持 |
| 包含 headless | StatefulSet 需要 Pod 间直接通信 |

**类比：**
```
Redis Operator 就像一个完整的产品
└─ 提供多种方式使用 Redis
   ├─ 简单: user-redis
   ├─ 高级: user-redis-master/replica
   ├─ HA: user-redis-sentinel-sentinel
   └─ 内部: headless services
```

---

## 🌐 网络流量路由

### 查询 Service 背后的 Pod

**查看 Service Endpoints：**

```bash
# 查看 user-redis 关联的 Pod
$ kubectl get endpoints user-redis -n juwan
NAME         ENDPOINTS
user-redis   10.244.0.10:6379,10.244.1.20:6379,10.244.2.30:6379

# 查看 user-redis-master 关联的 Pod
$ kubectl get endpoints user-redis-master -n juwan
NAME                ENDPOINTS
user-redis-master   10.244.0.10:6379

# 查看 user-redis-replica 关联的 Pod
$ kubectl get endpoints user-redis-replica -n juwan
NAME                 ENDPOINTS
user-redis-replica   10.244.1.20:6379,10.244.2.30:6379
```

**Pod 和 Service 的映射关系：**

```
Pods (实际运行的实例)          Services (虚拟 IP)
└─ redis-0 (主)              └─ user-redis (所有)
   ├─ 10.244.0.10              ├─ 10.103.91.84
   └─ :6379
                              └─ user-redis-master (仅主)
└─ redis-1 (从)                 ├─ 10.97.120.76
   ├─ 10.244.1.20
   └─ :6379
                              └─ user-redis-replica (仅从)
└─ redis-2 (从)                 ├─ 10.100.213.103
   ├─ 10.244.2.30
   └─ :6379
```

**DNS 解析过程：**

```
应用 DNS 查询
  └─ user-redis-master.juwan.svc.cluster.local
       ↓
CoreDNS (Kubernetes DNS)
  └─ 查询并返回 Service IP:
       ├─ 10.97.120.76 (user-redis-master)
       ├─ 或 10.100.213.103 (user-redis-replica)
       ├─ 或 10.103.91.84 (user-redis)
       └─ 或 Sentinel 的 IP
```

**Sentinel 模式的特殊之处：**

```
应用查询 Sentinel
  └─ user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379
       ↓
Sentinel Service (负载均衡到 3 个 Sentinel 节点)
       ↓
Sentinel 节点 (任选一个)
       ↓
应用询问: "mymaster 主节点 IP 是什么？"
       ↓
Sentinel 回答: "10.244.0.10:6379"
       ↓
应用直接连接 Redis Master: 10.244.0.10:6379
```

---

## 🔧 故障排查

### 问题 1：为什么应用连接失败？

**检查步骤：**

```bash
# 1. 验证 Service 存在
kubectl get svc user-redis-sentinel-sentinel -n juwan

# 2. 验证 Endpoints 不为空
kubectl get endpoints user-redis-sentinel-sentinel -n juwan

# 3. 测试 DNS 解析
kubectl run -it --rm nettest --image=busybox --restart=Never -n juwan -- \
  nslookup user-redis-sentinel-sentinel.juwan.svc.cluster.local

# 4. 测试连接性
kubectl run -it --rm nettest --image=busybox --restart=Never -n juwan -- \
  nc -zv user-redis-sentinel-sentinel.juwan.svc.cluster.local 26379

# 5. 查看应用日志
kubectl logs -f user-rpc-xxx -n juwan
```

### 问题 2：为什么看不到某个 Service？

```bash
# 确保在正确的命名空间
kubectl get svc -n juwan | grep redis

# 如果 Redis Operator 有问题，Service 可能不会创建
# 查看 Operator 日志
kubectl logs -n default deployment/redis-operator
```

### 问题 3：Service IP 经常变化？

```bash
# Service IP 是稳定的（除非被删除和重建）
# 如果频繁变化，说明 Service 被频繁重建

# 检查 Service 创建事件
kubectl describe svc user-redis-sentinel-sentinel -n juwan

# 检查 Operator 是否有异常
kubectl describe redissentinel user-redis-sentinel -n juwan
```

---

## 📚 总结

### 快速理解

| Service | 用途 | 应用是否使用 |
|---------|------|-----------|
| **user-redis-sentinel-sentinel** | ⭐ Sentinel 高可用 | ✅ **生产推荐** |
| user-redis-master | 直连主节点 | ⚠️ 需要读写分离 |
| user-redis-replica | 直连从节点 | ⚠️ 需要读写分离 |
| user-redis | 通用入口 | ❌ 不推荐（无 HA） |
| headless services | 内部通信 | ❌ 应用不用 |

### 为什么有这么多 Service？

**答案：** 为了提供灵活的使用方式

```
Redis Operator 的设计理念：
┌─────────────────────────────────────────┐
│  提供完整的 Redis 高可用解决方案         │
│                                         │
│  ├─ 简单使用场景                       │
│  │  └─ user-redis (所有节点)           │
│  │                                     │
│  ├─ 高级使用场景                       │
│  │  ├─ user-redis-master (写)          │
│  │  └─ user-redis-replica (读)         │
│  │                                     │
│  ├─ 生产场景 (推荐)                    │
│  │  └─ user-redis-sentinel-sentinel    │
│  │                                     │
│  └─ 内部通信                           │
│     └─ headless services               │
└─────────────────────────────────────────┘
```

### 应用该用哪个？

**一句话：使用 `user-redis-sentinel-sentinel:26379` + Sentinel 模式**

```yaml
# 这是最佳实践
Redis:
  Host: user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379
  Type: sentinel
  MasterName: mymaster
```

**为什么？**
- ✅ 自动故障转移
- ✅ 应用无需重启
- ✅ 无需手工干预
- ✅ 行业标准

---

**文档版本：** 1.0  
**创建日期：** 2026年2月22日  
**维护者：** DevOps Team
