23 KiB
23 KiB
Redis Kubernetes Service 详细解析
问题: 为什么 Redis 有 8 个 Service,但应用配置中只使用 user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379?
日期: 2026年2月22日
📋 目录
📊 Service 概览
当前 Redis 的 8 个 Service
$ 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)
基本信息:
名称: user-redis
类型: ClusterIP (有负载均衡)
Cluster IP: 10.103.91.84
端口: 6379/TCP, 9121/TCP
DNS: user-redis.juwan.svc.cluster.local
Endpoints 信息:
$ 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)
基本信息:
名称: 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)
基本信息:
名称: user-redis-headless
类型: ClusterIP (Headless Service)
Cluster IP: None ← 关键:无虚拟 IP
端口: 6379/TCP
DNS: user-redis-headless.juwan.svc.cluster.local
特殊之处:无虚拟 IP
# 正常 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)
基本信息:
名称: 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
特点:只指向主节点
$ 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)
基本信息:
名称: 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
特点:只指向从节点,支持负载均衡
$ 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)⭐⭐⭐
基本信息:
名称: 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
→ 自动连接新主节点
为什么这是最佳选择?
-
自动故障转移
主节点宕机 (✗) → Sentinel 自动选举新主 → 应用自动连接 -
高可用
Sentinel 集群(3 个) → 任意 1-2 个故障仍可用 -
应用无感知
应用只需配置 MasterName: mymaster 无需关心主从地址变化 -
标准做法
✅ 业界公认的 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 模式(生产推荐)
# 应用配置
Redis:
Host: user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379
Type: sentinel
MasterName: mymaster
Pass: ${REDIS_PASSWORD}
优势:
- ✅ 自动故障转移(RTO < 30 秒)
- ✅ 应用无需重启
- ✅ 自动发现新主节点
- ✅ 生产标准做法
⭐⭐ 主从分离模式(可选)
# 应用配置(需要两个 host)
Redis:
Master:
Host: user-redis-master.juwan.svc.cluster.local:6379
Slave:
Host: user-redis-replica.juwan.svc.cluster.local:6379
适用场景:
- 读写分离显著
- 对读性能有极高要求
缺点:
- 主从故障需手动切换
- 应用层复杂度高
❌ 不推荐的做法
# ❌ 直接连接单个节点
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 自动创建:
// 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:
# 查看 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:为什么应用连接失败?
检查步骤:
# 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?
# 确保在正确的命名空间
kubectl get svc -n juwan | grep redis
# 如果 Redis Operator 有问题,Service 可能不会创建
# 查看 Operator 日志
kubectl logs -n default deployment/redis-operator
问题 3:Service IP 经常变化?
# 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 模式
# 这是最佳实践
Redis:
Host: user-redis-sentinel-sentinel.juwan.svc.cluster.local:26379
Type: sentinel
MasterName: mymaster
为什么?
- ✅ 自动故障转移
- ✅ 应用无需重启
- ✅ 无需手工干预
- ✅ 行业标准
文档版本: 1.0
创建日期: 2026年2月22日
维护者: DevOps Team