探索Redis集群:(五)基于K8S搭建Redis集群、客户端访问

探索Redis集群 -(五)基于K8S搭建Redis集群、客户端访问

前情提要:

计划接下来用两周的时间,搞清楚Redis Cluster的相关内容。既然要深入了解集群,自然就需要解答以下几个基本问题:

  1. 集群中各节点的表现形式是什么?节点的增加和减少是怎样进行的?
  2. 数据在集群中是如何分布的?集群是如何处理读写操作的?在节点增减的时候,如何确保读写操作的正常进行?
  3. 集群是如何发现故障的?一旦发现故障,又是怎样进行处理的?
  4. 这种集群方式有没有什么局限?使用时有什么注意事项?
  5. 实际怎么搭建一个Redis集群?怎么使用?

之前完成了Redis集群的第四部分:探索Redis集群:(四)局限与注意事项

今天继续讨论:Redis集群 -(五)基于K8S搭建Redis集群、客户端访问

1. 集群搭建

这部分会使用K8S搭建一个3主3从的redis集群。

使用K8S部署Redis集群是很方便的,K8S可以通过Rancher Desktop很方便的进行安装。

k8s安装好之后信息如下:

bash 复制代码
➜ kubectl get nodes
NAME                   STATUS   ROLES                  AGE   VERSION
lima-rancher-desktop   Ready    control-plane,master   87d   v1.29.3+k3s1
➜ kubectl cluster-info
Kubernetes control plane is running at https://127.0.0.1:6443
CoreDNS is running at https://127.0.0.1:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
Metrics-server is running at https://127.0.0.1:6443/api/v1/namespaces/kube-system/services/https:metrics-server:https/proxy

To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'.

接下来开始编写redis.yaml

1.1 配置文件 - configmap

yaml 复制代码
apiVersion: v1
kind: ConfigMap
metadata:
  name: redis-config
  labels:
    app: redis-cluster
data:
  redis.conf: |
    save ""
    appendonly no
    cluster-enabled yes
    cluster-config-file /var/nodes.conf
    cluster-node-timeout 5000
    port 6379

1.2 创建service - 无头服务和ClusterIP服务

这里创建两个service,可以有不同用途。

a. 无头服务(redis-service):

  • clusterIP: None 表示这是一个无头服务(Headless Service)。
  • 无头服务没有固定的 IP 地址,当 DNS 查询这个服务的时候,会返回后端 Pods 的 IP 地址列表,而不是单个服务 IP。
  • 这种类型的服务通常用于服务发现。它允许其他 Pods 直接连接到服务后端的 Pods,而不是通过负载均衡。
  • 无头服务常用于状态保持的应用程序,每个节点可能需要被单独寻址。

b. ClusterIP服务(redis-access-service):

  • type: ClusterIP 表示这是一个默认类型的服务,提供一个稳定的内部集群 IP 地址来代理访问后端 Pods。
  • 当客户端连接到这个服务时,Kubernetes 会提供简单的负载均衡,将连接分发到匹配选择器的 Pods 上。
  • 这种类型的服务适用于客户端只需要与任意后端实例通信的场景,不需要知道具体是哪个 Pod。

以下是具体yaml配置:

yaml 复制代码
---

apiVersion: v1
kind: Service
metadata:
  name: redis-service
  labels:
    app: redis-cluster
spec:
  ports:
    - name: redis-port
      port: 6379
  clusterIP: None
  selector:
    app: redis-cluster

---

apiVersion: v1
kind: Service
metadata:
  name: redis-access-service
  labels:
    app: redis-cluster
spec:
  type: ClusterIP
  ports:
    - name: redis-port
      protocol: TCP
      port: 6379
      targetPort: 6379
  selector:
    app: redis-cluster

1.3 有状态的应用 - StatefulSet

使用 StatefulSet,每个 Pod 都有一个固定的名称,格式为 -,其中 是从 0 开始的索引。这些 Pods 会按顺序创建和删除,确保有序性和稳定性。每个 Pod 的存储也会保持与 Pod 的绑定,即使 Pod 被重新调度到其他节点上。

yaml 复制代码
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: redis-cluster
  labels:
    app: redis-cluster
spec:
  serviceName: redis-service
  replicas: 6
  selector:
    matchLabels:
      app: redis-cluster
  template:
    metadata:
      labels:
        app: redis-cluster
    spec:
      terminationGracePeriodSeconds: 20
      containers:
        - name: redis
          image: redis:6.2
          command:
            - "redis-server"
          args:
            - "/etc/redis/redis.conf"
            - "--protected-mode"
            - "no"
          resources:
            requests:
              cpu: 100m
              memory: 500Mi
          ports:
            - name: redis
              containerPort: 6379
              protocol: TCP
            - name: cluster
              containerPort: 16379
              protocol: TCP
          volumeMounts:
            - name: redis-config
              mountPath: /etc/redis
      volumes:
        - name: redis-config
          configMap:
            name: redis-config

1.4 应用到K8S

把以上的配置内容拼接到redis.yaml中后,执行kubectl apply -f redis.yaml进行集群部署:

bash 复制代码
➜ kubectl apply -f redis.yaml
configmap/redis-config created
service/redis-service created
service/redis-access-service created
statefulset.apps/redis-cluster created

通过kubectl get all | grep redis查看创建情况,最终会成功创建一个statefulset,两个service,六个pod,如下:

bash 复制代码
➜ kubectl get all | grep redis
pod/redis-cluster-0                     1/1     Running   0          17s
pod/redis-cluster-1                     1/1     Running   0          16s
pod/redis-cluster-2                     1/1     Running   0          15s
pod/redis-cluster-3                     1/1     Running   0          14s
pod/redis-cluster-4                     1/1     Running   0          13s
pod/redis-cluster-5                     1/1     Running   0          12s
service/redis-service          ClusterIP   None            <none>        6379/TCP   17s
service/redis-access-service   ClusterIP   10.xx.xx.xx   <none>        6379/TCP   17s
statefulset.apps/redis-cluster   6/6     17s

1.5 集群初始化

通过执行以下命令进行集群初始化:

bash 复制代码
kubectl exec -it redis-cluster-0 -- redis-cli -p 6379 --cluster create --cluster-replicas 1 $(kubectl get pods -l app=redis-cluster -o jsonpath='{range .items[*]}{.status.podIP}:6379 {end}')

解释下这个命令:

  • redis-cluster-0:由于是statefulset启动的pod,因此pod会按数字顺序来命名,redis-cluster-0就是启动的6个pod的第一个,也就是第一个redis实例。
  • kubectl exec -it redis-cluster-0 -- redis-cli -p 6379: 这部分使用kubectl exec命令在名为redis-cluster-0的Pod中执行redis-cli命令行工具,-p 6379指定了Redis服务器监听的端口。
  • --cluster create --cluster-replicas 1: 这部分是传递给redis-cli的参数,告诉redis-cli要创建一个Redis集群,并且每个主节点都有一个副本(从节点)。
  • $(kubectl get pods -l app=redis-cluster -o jsonpath='{range .items[*]}{.status.podIP}:6379 {end}'): 这部分是一个命令替换,使用kubectl get pods命令获取默认命名空间中所有带有标签app=redis-cluster的Pods的IP地址,并且将这些地址格式化为redis-cli需要的格式(即:)。-o jsonpath='{...}'指定了如何从返回的JSON对象中提取数据。
    • 这个命令最终会输出每个pod的ip及端口,类似内容:10.xx.0.101:6379 10.xx.0.102:6379 10.xx.0.103:6379 10.xx.0.104:6379 10.xx.0.105:6379 10.xx.0.106:6379

执行集群初始化命令之后会自动建议主从分配及槽分配,直接输入yes就会自动配置:

bash 复制代码
➜ kubectl exec -it redis-cluster-0 -- redis-cli -p 6379 --cluster create --cluster-replicas 1 $(kubectl get pods -l app=redis-cluster -o jsonpath='{range .items[*]}{.status.podIP}:6379 {end}')
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 10.xx.0.102:6379 to 10.xx.0.106:6379
Adding replica 10.xx.0.103:6379 to 10.xx.0.105:6379
Adding replica 10.xx.0.101:6379 to 10.xx.0.104:6379
M: m1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 10.xx.0.106:6379
   slots:[0-5460] (5461 slots) master
M: m2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 10.xx.0.105:6379
   slots:[5461-10922] (5462 slots) master
M: m3xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 10.xx.0.104:6379
   slots:[10923-16383] (5461 slots) master
S: s3xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 10.xx.0.101:6379
   replicates m3xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
S: s1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 10.xx.0.102:6379
   replicates m1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
S: s2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 10.xx.0.103:6379
   replicates m2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
.
>>> Performing Cluster Check (using node 10.xx.0.106:6379)
M: m1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 10.xx.0.106:6379
   slots:[0-5460] (5461 slots) master
   1 additional replica(s)
S: s2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 10.xx.0.103:6379
   slots: (0 slots) slave
   replicates m2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
S: s3xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 10.xx.0.101:6379
   slots: (0 slots) slave
   replicates m3xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
S: s1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 10.xx.0.102:6379
   slots: (0 slots) slave
   replicates m1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
M: m2xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 10.xx.0.105:6379
   slots:[5461-10922] (5462 slots) master
   1 additional replica(s)
M: m3xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 10.xx.0.104:6379
   slots:[10923-16383] (5461 slots) master
   1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

1.6 访问集群

访问任一个pod打开redis-cli -p 6379 -c查看集群。

可以看到集群当前已知的节点总数为6个,包括3个主节点和3个从节点:

bash 复制代码
➜  kubectl exec -it redis-cluster-0 -- redis-cli -p 6379 -c
127.0.0.1:6379> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6

设置一个值会重定向到另一个节点:

bash 复制代码
127.0.0.1:6379> set a 1
-> Redirected to slot [15495] located at 10.xx.0.105:6379
OK

集群节点信息:

bash 复制代码
127.0.0.1:6379> cluster nodes
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 10.xx.0.xxx:6379@16379 slave xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 0 xxxxx 2 connected
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 10.xx.0.xxx:6379@16379 slave xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 0 xxxxx 3 connected
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 10.xx.0.xxx:6379@16379 slave xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 0 xxxxx 1 connected
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 10.xx.0.xxx:6379@16379 myself,master - 0 xxxxx 1 connected 0-5460
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 10.xx.0.xxx:6379@16379 master - 0 xxxxx 2 connected 5461-10922
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 10.xx.0.xxx:6379@16379 master - 0 xxxxx 3 connected 10923-16383

2. 客户端访问

2.1 命令行访问

进入任一pod:

bash 复制代码
kubectl exec -it <redis-pod-name> -- redis-cli -c

2.2 SpringBoot访问

SpringBoot应用和redis集群部署在同一个namespace下(当前是default),就可以通过redis-access-service:6379直接访问Redis集群:

yml 复制代码
spring:
  redis:
    cluster:
      max-redirects: 3
      nodes:
        - redis-access-service:6379
    lettuce:
      pool:
        max-active: 2
        max-wait: -1

当然,也可以配置多个node节点,类似下面:

yml 复制代码
spring:
  redis:
    cluster:
      nodes:
        - redis-node-1:6379
        - redis-node-2:6379
        - redis-node-3:6379

2.3 Python访问

启动一个Python的pod:

bash 复制代码
➜ kubectl run python-pod --image=python:3 -- sleep 3600 

pod/python-pod created

进入Python pod:

bash 复制代码
kubectl exec -it python-pod -- /bin/bash

在Python pod安装Redis库:

bash 复制代码
pip install redis-py-cluster 

在Python pod中打开python命令行,测试访问集群、执行set操作、输出集群信息:

  • 访问集群使用集群service: startup_nodes = [{"host":"redis-access-service","port": "6379"}]
bash 复制代码
root@python-pod:/# python3
Python 3.12 [GCC 12.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from rediscluster import RedisCluster
>>> startup_nodes = [{"host":"redis-access-service","port": "6379"}]
>>> redis_cluster = RedisCluster(startup_nodes=startup_nodes, decode_responses=True)
>>> redis_cluster.set("key", "value")
True
>>> redis_cluster.get("key")
'value'
>>> redis_cluster.cluster_info()
{'10.42.0.108:6379': {'cluster_state': 'ok', 'cluster_slots_assigned': 16384, 'cluster_slots_ok': 16384, 'cluster_slots_pfail': 0, 'cluster_slots_fail': 0, 'cluster_known_nodes': 6, 'cluster_size': 3, ...}}
相关推荐
爱吃泡芙的小白白1 小时前
爬虫学习——使用HTTP服务代理、redis使用、通过Scrapy实现分布式爬取
redis·分布式·爬虫·http代理·学习记录
纪元A梦2 小时前
Redis最佳实践——性能优化技巧之监控与告警详解
数据库·redis·性能优化
hnlucky4 小时前
redis 数据类型新手练习系列——Hash类型
数据库·redis·学习·哈希算法
AnsenZhu5 小时前
2025年Redis分片存储性能优化指南
数据库·redis·性能优化·分片
李菠菜7 小时前
非SpringBoot环境下Jedis集群操作Redis实战指南
java·redis
我的golang之路果然有问题7 小时前
快速了解redis,个人笔记
数据库·经验分享·redis·笔记·学习·缓存·内存
躺不平的理查德8 小时前
General Spark Operations(Spark 基础操作)
大数据·分布式·spark
talle20218 小时前
Zeppelin在spark环境导出dataframe
大数据·分布式·spark
渣渣盟8 小时前
大数据开发环境的安装,配置(Hadoop)
大数据·hadoop·分布式
道友老李8 小时前
【存储中间件】Redis核心技术与实战(五):Redis缓存使用问题(BigKey、数据倾斜、Redis脑裂、多级缓存)、互联网大厂中的Redis
redis·缓存·中间件