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