Ceph+K8s 中间件实战 | 第 5 天:K8s 部署 Redis Cluster 集群(Ceph RBD + 架构设计 + 巡检命令)

第 5/15 天

经过前四天的铺垫,我们已经完成了 Ceph 分布式存储的回顾、K8s 存储体系的梳理,并成功将 Ceph RBD 块存储和 CephFS 共享文件存储接入 K8s 集群。从今天开始,我们正式进入「中间件部署实战」阶段,首站便是高吞吐、低延迟的内存数据库——Redis。

本篇将使用 Bitnami 官方维护的 bitnami/redis-cluster Helm Chart,在 K8s 上部署一个 6 节点的 Redis Cluster(3 主 3 从),并通过 Ceph RBD StorageClass 实现数据持久化。我们将覆盖架构设计、values 配置、部署验证、登录连接和日常巡检的完整闭环。

一、Redis Cluster 设计架构

1.1 为什么选择 Redis Cluster

单实例 Redis 虽然性能强劲,但存在两个瓶颈:单节点内存上限和数据丢失风险。Redis Sentinel(下篇讲解)解决了高可用问题,但仍然是单 Master 写入,无法水平扩展。Redis Cluster 则在此基础上引入了数据分片(Sharding)机制,将数据分散到多个 Master 节点上,既解决了容量瓶颈,又保留了高可用能力。

Redis Cluster 的核心特性:

特性 说明
数据分片 16384 个哈希槽(hash slot)均匀分配到各 Master
自动故障转移 Master 宕机后,对应 Replica 自动提升为新 Master
去中心化 节点间通过 Gossip 协议互相通信,无中心代理
客户端路由 客户端通过 MOVED/ASK 重定向访问正确节点
多键操作限制 跨 slot 的多键操作需使用 hash tag {} 保证同 slot

K8s Logo

1.2 组件拓扑

本次部署的 Redis Cluster 拓扑如下:

💻 代码示例

┌─────────────────────────────────────┐

│ Kubernetes Cluster │

│ │

│ ┌─────────────────────────────┐ │

│ │ redis-cluster Service │ │

│ │ (ClusterIP: None – Headless)│ │

│ └──────────┬──────────────────┘ │

│ │ │

│ ┌──────────┴──────────────────┐ │

│ │ │ │

│ Master0 Master1 Master2 │ │

│ slot0 slot1 slot2 │ │

│ │ │ │ │ │

│ Replica0 Replica1 Replica2 │ │

│ (slave) (slave) (slave) │ │

│ │ │

└─────┬───────────────────────────────┘

│ PVC (ReadWriteOnce)

▼

┌─────────────┐

│ Ceph RBD │

│ StorageClass│

│ (csi-rbd) │

└─────────────┘

部署规模:6 个 Pod(3 Master + 3 Replica),每个 Pod 绑定一个独立的 Ceph RBD PVC,使用 Headless Service 提供稳定的网络标识(StatefulSet 特性)。

1.3 数据流向

💻 代码示例

客户端请求

│

▼

任一节点接收命令

│

├─ key 所在 slot 在本节点 → 直接执行并返回

│

└─ key 所在 slot 不在本节点 → 返回 MOVED 重定向

│

▼

客户端缓存 slot → node 映射表

后续请求直接访问正确节点

哈希槽计算公式:slot = CRC16(key) mod 16384。每个 Master 负责一部分槽位区间,例如 6 节点集群中每个 Master 约负责 5461 个槽位。

1.4 高可用机制

Redis Cluster 的高可用依赖以下机制协同工作:

  • 心跳检测:节点间持续发送 PING/PONG 消息,超过 cluster-node-timeout(默认 15 秒)未响应则标记为 PFAIL(疑似下线)
  • 故障判定:超过半数 Master 节点报告某节点 PFAIL,则升级为 FAIL(确定下线)
  • 副本选举:故障 Master 的 Replica 发起选举,获得多数 Master 投票后提升为新 Master
  • 槽位迁移:新 Master 继承原 Master 的全部哈希槽,集群继续提供服务

1.5 存储规划

Redis 是内存数据库,持久化(RDB/AOF)数据落盘到 Ceph RBD 卷:

存储项 类型 大小 StorageClass 说明
Redis 数据卷 RBD (RWO) 10Gi/节点 ceph-rbd-sc 存储 dump.rdb / appendonly.aof
备份快照 Ceph snapshot 按需 – 利用 RBD 快照能力做定时备份

选择 RBD 而非 CephFS 的原因:Redis 每个节点只需单 Pod 读写(RWO),RBD 的块设备性能更贴近本地磁盘,延迟更低,适合 AOF 追加写入场景。

二、部署实战(Bitnami Helm Chart)

2.1 添加 Bitnami Helm 仓库

💻 代码示例

# 添加 Bitnami 官方 Chart 仓库

helm repo add bitnami https://charts.bitnami.com/bitnami

helm repo update

 

# 验证 redis-cluster chart 可用

helm search repo bitnami/redis-cluster

# 预期输出:

# NAME CHART VERSION APP VERSION DESCRIPTION

# bitnami/redis-cluster 11.x.x 7.x.x Redis(R) is an open source, …

 

# 查看支持的 values 参数(可选)

helm show values bitnami/redis-cluster > /tmp/redis-cluster-default-values.yaml

2.2 编写 values.yaml 自定义配置

核心配置要点:指定 Ceph RBD StorageClass、设置 6 节点集群、配置密码、调整资源限制。

💻 代码示例

# /tmp/redis-cluster-values.yaml

# Redis Cluster Helm Chart 自定义配置

 

cluster:

# 6 节点集群:3 Master + 3 Replica

nodes: 6

replicas: 1 # 每个 Master 1 个副本

# 集群初始化超时

initTimeout: 300

 

# 全局镜像配置

global:

imageRegistry: ""

imagePullSecrets: []

redis:

password: "Redis#Cluster@2026"

 

# Redis 镜像

image:

registry: docker.io

repository: bitnami/redis-cluster

tag: 7.4.1-debian-12-r0

pullPolicy: IfNotPresent

 

# 持久化配置 —— 关键:指向 Ceph RBD StorageClass

persistence:

enabled: true

storageClass: "ceph-rbd-sc" # 第 2 天创建的 Ceph RBD StorageClass

accessModes:

– ReadWriteOnce

size: 10Gi

# 数据子目录

path: /bitnami/redis/data

 

# 每个节点的资源限制

resources:

requests:

cpu: 250m

memory: 512Mi

limits:

cpu: 1000m

memory: 1Gi

 

# 网络配置

service:

type: ClusterIP

ports:

redis: 6379

bus: 16379 # 集群总线端口,用于节点间 Gossip 通信

 

# Headless Service —— StatefulSet 稳定网络标识

serviceAccount:

create: true

name: ""

 

# Pod 安全上下文

podSecurityContext:

enabled: true

fsGroup: 1001

 

containerSecurityContext:

enabled: true

runAsUser: 1001

runAsNonRoot: true

 

# 持久化参数

redis:

# 开启 AOF 持久化

configmap: |

appendonly yes

appendfsync everysec

save 900 1

save 300 10

save 60 10000

maxmemory 512mb

maxmemory-policy allkeys-lru

cluster-node-timeout 15000

 

# 指标导出(配合 Prometheus 监控)

metrics:

enabled: true

image:

registry: docker.io

repository: bitnami/redis-exporter

tag: 1.x.x

serviceMonitor:

enabled: false # 后续监控篇统一开启

 

# Pod 反亲和 —— 让 6 个节点分散到不同节点

podAntiAffinityPreset: soft

2.3 执行 Helm 部署

💻 代码示例

# 创建独立命名空间

kubectl create namespace middleware

 

# 部署 Redis Cluster

helm install redis-cluster bitnami/redis-cluster

–namespace middleware

-f /tmp/redis-cluster-values.yaml

–version 11.4.0

 

# 预期输出:

# NAME: redis-cluster

# LAST DEPLOYED: Sun Sep 27 00:35:00 2026

# NAMESPACE: middleware

# STATUS: deployed

# REVISION: 1

# NOTES:

# Redis Cluster can be accessed via port 6379 on the following DNS name…

# To get your password run:

# export REDIS_PASSWORD=$(kubectl get secret –namespace middleware redis-cluster -o jsonpath="{.data.redis-password}" | base64 -d)

2.4 验证部署状态

💻 代码示例

# 查看 StatefulSet Pod 状态(6 个 Pod 依次启动)

kubectl get pods -n middleware -l app.kubernetes.io/instance=redis-cluster -w

 

# 预期输出:

# NAME READY STATUS RESTARTS AGE

# redis-cluster-0 1/1 Running 0 2m

# redis-cluster-1 1/1 Running 0 2m

# redis-cluster-2 1/1 Running 0 2m

# redis-cluster-3 1/1 Running 0 2m

# redis-cluster-4 1/1 Running 0 2m

# redis-cluster-5 1/1 Running 0 2m

 

# 查看 Service

kubectl get svc -n middleware -l app.kubernetes.io/instance=redis-cluster

# 预期输出:

# NAME TYPE CLUSTER-IP PORT(S) AGE

# redis-cluster ClusterIP None 6379/TCP,16379/TCP 3m

# redis-cluster-headless ClusterIP None 6379/TCP,16379/TCP 3m

 

# 查看 PVC(6 个 PVC,均绑定 Ceph RBD)

kubectl get pvc -n middleware -l app.kubernetes.io/instance=redis-cluster

# 预期输出:

# NAME STATUS VOLUME CAPACITY STORAGECLASS AGE

# data-redis-cluster-0 Bound pvc-xxxx-xxxx 10Gi ceph-rbd-sc 3m

# data-redis-cluster-1 Bound pvc-yyyy-yyyy 10Gi ceph-rbd-sc 3m

# …

# data-redis-cluster-5 Bound pvc-zzzz-zzzz 10Gi ceph-rbd-sc 3m

三、登录验证

3.1 获取集群密码并连接

💻 代码示例

# 提取集群密码

export REDIS_PASSWORD=$(kubectl get secret –namespace middleware redis-cluster

-o jsonpath="{.data.redis-password}" | base64 -d)

echo "Password: $REDIS_PASSWORD"

 

# 进入 Pod 内执行 redis-cli 连接集群

kubectl exec -it -n middleware redis-cluster-0 — redis-cli

-a "$REDIS_PASSWORD" –cluster check

127.0.0.1:6379

 

# 预期输出:

# >>> Performing Cluster Check (using node 127.0.0.1:6379)

# ……

# [OK] All nodes agree about slots configuration.

# [OK] All 16384 slots covered.

# [OK] All 16384 slots covered.

# [OK] 0 keys out of 0 are in the cluster.

3.2 查看集群节点信息

💻 代码示例

# 查看集群节点拓扑(角色、槽位分配、主从关系)

kubectl exec -it -n middleware redis-cluster-0 — redis-cli

-a "$REDIS_PASSWORD" cluster nodes

 

# 预期输出:

# <id> 10.x.x.x:6379@16379 master – 0 xxxx myself,master – 0 1700000000000 1 connected 0-5460

# <id> 10.x.x.x:6379@16379 master – 0 xxxx master – 0 1700000000000 2 connected 5461-10922

# <id> 10.x.x.x:6379@16379 master – 0 xxxx master – 0 1700000000000 3 connected 10923-16383

# <id> 10.x.x.x:6379@16379 slave <master_id> 0 xxxx slave 0-5460

# <id> 10.x.x.x:6379@16379 slave <master_id> 0 xxxx slave 5461-10922

# <id> 10.x.x.x:6379@16379 slave <master_id> 0 xxxx slave 10923-16383

3.3 验证数据读写

💻 代码示例

# 写入测试数据(redis-cli 自动路由到正确节点)

kubectl exec -it -n middleware redis-cluster-0 — redis-cli

-a "$REDIS_PASSWORD" -c set testkey "hello-ceph-k8s"

 

# 读取验证

kubectl exec -it -n middleware redis-cluster-0 — redis-cli

-a "$REDIS_PASSWORD" -c get testkey

# 预期输出: "hello-ceph-k8s"

 

# 查看集群槽位分配概况

kubectl exec -it -n middleware redis-cluster-0 — redis-cli

-a "$REDIS_PASSWORD" cluster slots

注意:-c 参数启用集群模式,遇到 MOVED 重定向时自动跳转。不加 -c 则手动重定向会报错。

四、日常巡检命令

4.1 集群健康检查

💻 代码示例

# 一键检查集群完整性

kubectl exec -n middleware redis-cluster-0 — redis-cli

-a "$REDIS_PASSWORD" –cluster check

redis-cluster-0.redis-cluster-headless.middleware.svc.cluster.local:6379

 

# 查看集群信息

kubectl exec -n middleware redis-cluster-0 — redis-cli

-a "$REDIS_PASSWORD" cluster info

# 关键指标:

# cluster_state:ok <- 集群状态必须为 ok

# cluster_slots_assigned:16384 <- 槽位全部已分配

# cluster_slots_ok:16384 <- 槽位全部正常

# cluster_known_nodes:6 <- 已知节点数

# cluster_size:3 <- Master 分片数

4.2 节点状态与内存巡检

💻 代码示例

# 逐节点查看内存使用情况

for i in 0 1 2 3 4 5; do

echo "=== redis-cluster-$i ==="

kubectl exec -n middleware redis-cluster-$i — redis-cli

-a "$REDIS_PASSWORD" info memory | grep -E "used_memory_human|maxmemory_human|mem_fragmentation_ratio"

done

 

# 预期输出:

# === redis-cluster-0 ===

# used_memory_human:1.2M

# maxmemory_human:512.0M

# mem_fragmentation_ratio:1.05

 

# 查看各节点 Key 数量

kubectl exec -n middleware redis-cluster-0 — redis-cli

-a "$REDIS_PASSWORD" –cluster call

redis-cluster-0.redis-cluster-headless.middleware.svc.cluster.local:6379 dbsize

4.3 Pod 与 PVC 巡检

💻 代码示例

# Pod 状态巡检

kubectl get pods -n middleware -l app.kubernetes.io/instance=redis-cluster

-o wide

 

# PVC 使用率(Ceph RBD 卷)

kubectl get pvc -n middleware -l app.kubernetes.io/instance=redis-cluster

 

# 查看最近事件(排查 Pod 异常)

kubectl get events -n middleware –sort-by='.lastTimestamp' | tail -20

 

# 查看 AOF 持久化文件

kubectl exec -n middleware redis-cluster-0 — ls -lh /bitnami/redis/data

# 预期输出:

# -rw-r–r– 1 1001 1001 512 Sep 27 00:40 dump.rdb

# -rw-r–r– 1 1001 1001 1.2K Sep 27 00:40 appendonly.aof

4.4 日志查看

💻 代码示例

# 查看单个节点日志

kubectl logs -n middleware redis-cluster-0 –tail=50

 

# 查看所有节点最近日志

for i in 0 1 2 3 4 5; do

echo "=== redis-cluster-$i ==="

kubectl logs -n middleware redis-cluster-$i –tail=10

done

4.5 性能压测(可选)

💻 代码示例

# 使用 redis-benchmark 压测集群性能

kubectl exec -n middleware redis-cluster-0 — redis-benchmark

-a "$REDIS_PASSWORD" -h redis-cluster-0.redis-cluster-headless.middleware.svc.cluster.local

-p 6379 -t set,get -n 10000 -c 50 -q

 

# 预期输出(参考值,实际取决于节点规格):

# SET: 85000.00 requests per second

# GET: 92000.00 requests per second

K8s Logo

五、常见问题

Q1:Pod 启动报错 CLUSTERDOWN Hash slot not served?

这是因为集群初始化尚未完成,槽位未全部分配。解决方法:等待所有 6 个 Pod 就绪后,手动触发集群初始化:

💻 代码示例

kubectl exec -n middleware redis-cluster-0 — redis-cli

-a "$REDIS_PASSWORD" –cluster create

redis-cluster-0.redis-cluster-headless:6379

redis-cluster-1.redis-cluster-headless:6379

redis-cluster-2.redis-cluster-headless:6379

redis-cluster-3.redis-cluster-headless:6379

redis-cluster-4.redis-cluster-headless:6379

redis-cluster-5.redis-cluster-headless:6379

–cluster-replicas 1 –cluster-yes

Q2:PVC 一直 Pending,StorageClass 名称写什么?

请确认第 2 天创建的 Ceph RBD StorageClass 名称。执行 kubectl get sc 查看集群中实际可用的 StorageClass,将 values.yaml 中 persistence.storageClass 改为实际名称(如 ceph-rbd-sc 或 csi-ceph-rbd)。RBD 默认只支持 ReadWriteOnce,切勿使用 ReadWriteMany。

Q3:跨节点多键操作报错 CROSSSLOT Keys in request don't hash to the same slot?

Redis Cluster 要求多键操作(MGET、MSET、事务等)的所有 Key 必须映射到同一哈希槽。解决方法:使用 Hash Tag {} 强制同槽,例如 user:{1001}:name 和 user:{1001}:age 会被分配到同一槽位,从而支持多键操作。

六、总结

本篇我们使用 Bitnami 官方 bitnami/redis-cluster Helm Chart,在 K8s 上完成了 6 节点 Redis Cluster 的部署,核心要点回顾:

  1. 架构设计:Redis Cluster 通过 16384 个哈希槽实现数据分片,3 主 3 从保证高可用,Gossip 协议维护集群状态
  2. 存储规划:每个 Pod 绑定独立 Ceph RBD PVC(RWO),存储 RDB/AOF 持久化文件,利用 RBD 块设备低延迟特性
  3. 部署方式:helm repo add + values.yaml 自定义 + helm install 三步完成,storageClass 指向 Ceph RBD 实现开箱持久化
  4. 验证巡检:cluster check 检查集群完整性、cluster info 查看集群状态、逐节点 info memory 巡检内存

Redis Cluster 适合数据量大、需要水平扩展的场景。如果业务量不大但需要高可用,下篇我们将讲解更轻量的 Redis Sentinel 哨兵模式。

下期预告

第 6 天:K8s 部署 Redis Sentinel 哨兵模式(高可用架构 + 登录验证) —— 当你只需要高可用而不需要分片时,Sentinel 模式是更简洁的选择。我们将使用 bitnami/redis Chart 部署 1 主 2 从 3 哨兵的架构,对比 Cluster 与 Sentinel 的适用场景。

系列目录

微信二维码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发
头像 - 恒星
欢迎您留下宝贵的见解!
提交
头像 - 恒星

昵称

取消
昵称表情代码图片快捷回复

    暂无评论内容