先前介绍过Redis Cluster Operator容器化方案,本次介绍Redis Sentinel Operator容器化。Redis Sentinel容器化与Redis Cluster有相同的地方,如也需要解决节点分布、节点快重启等问题,与此同时,Redis Sentinel包含两类不同角色的节点并且该种模式不涉及数据分片的事情,使得Redis Sentinel容器化在部署架构、服务暴露、异常处理等方面有着其特殊性。
节点分布与节点容器重启问题
节点分布
Redis Sentinel容器化部署同Redis Cluster的一样,也需要将不同Redis节点和Sentinel节点分别置于不同的主机上,防止由于主机故障导致主从或者sentinel功能失效。这一点同样使用Kubernets的Pod反亲和性来配置:
spec:
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- podAffinityTerm:
labelSelector:
matchLabels:
REDIS_POD_LABEL/SENTINEL_POD_LABEL: REDIS_POD_VALUE/SENTINEL_POD_VALUE
topologyKey: kubernetes.io/hostname
Redis 容器快重启
同Redis Cluster一样,Redis Sentinel模式中,Redis master节点容器一旦停止运行很快就会被kubernetes重新拉起,这个时间不足以触发Sentinel进行故障转移,可能会造成Redis数据丢失。会避免这个问题,Redis Sentinel容器化中继续采用了容器启动和进程启动相分离的方法,即默认容器启动时不启动Redis/Sentinel进程,由operator判断在合适的时机启动Redis/Sentinel进程。
对于新的Redis容器:
Case 1:Master节点存在,则启动容器Redis进程加入集群 Case 2:Master节点不存在,但Slave节点存在 Case 2-1:Sentinel可以正常工作,则等待Sentinel启动故障转移提升Slave为Master,然后依Case 1操作 Case 2-2:Sentinel不能正常工作,提升一个Slave节点为主节点,调整Sentinel的主节点指向,然后依Case 1操作 Case 3:Slave和Master节点均不存在,则直接启动Redis进程,同时调整Sentinel指向的master节点为本节点
对于新Sentinel容器:
Case 1:如果Redis Master存在,启动Sentinel进程并指向Master Case 2:如果Redis Master不存在,依新Redis容器启动场景处理,等待Master节点存在后,依Case 1处理
Redis Sentinel Operator
Redis Sentinel容器化部署架构
在Redis Sentinel架构中,Sentinel的功能主要有两个:1. 监控Redis节点,发现Redis故障并进行failover;2. 为客户端提供Redis最新的主从拓扑信息。换而言之,Sentinel对于Redis数据处理并不是必须的,基于此,在设计Redis Sentinel Operator架构的时候可以有两种选择:
方案一:使用原始的Redis Sentinel架构,分别部署Redis和Sentinel节点,并由Operator进行管控 方案二:只部署Redis节点,由Operator完成Sentinel的功能
方案一、二各有其优缺点。方案一优点为使用Redis Sentinel原始部署架构,Operator不需要集成Sentinel的功能,便于版本和功能与社区保持一致。然而,方案一需要对Sentinel进行管控,如维持Sentinel节点的配置一致性和正确性等,而Sentinel对动态配置这块支持很弱,很多场景下更改Sentinel的配置就必须重启Sentinel节点;方案二不需要部署Sentinel节点,节约K8S的资源而且Operator也不需要麻烦的对Sentinel进行管控。但是,方案二最大的问题在于Operator本身实质上是单节点运行,而不是像Sentinel一样实行多节点分散部署多数派共识机制,这样在故障判断的时候可能会由于集群内部节点间的网络断连造成误判。
在架构选择的时候我们选择了方案一。在服务暴露方面,由于Redis Sentinel模式中,各Sentinel之间是对等的,而且Redis节点之间除了角色不一样,数据是对等的,所以也有两个选择:
方式一:对于Sentinel节点,为其建立一个统一的nodeport型的Service,客户端通过该Service连接到任一Sentinel节点上获取主从信息。对于Redis节点,分别为每个Redis节点建立一个nodeport 型Service,并且在Redis中使用如下配置设置暴露的端口为nodeport的取值,暴露的IP为其所在的宿主机的地址。这样客户端从Sentinel获取到的Redis信息就是该Redis节点的nodeport Service信息。
# Redis配置文件中添加
replica-announce-ip HOST_IP
replica-announce-port REDIS_SERVICE-NODEPORT方式二:客户端通过Sentinel获取的是主从信息,所以可以直接建立两个Service:一个写Service指向主节点,一个读Service指向所有Redis节点。并且通过由Operator监听Sentinel的主从变化信息保障这种指向的正确性,那么客户端可以不连接Sentinel,像使用单机Redis一样,按需求连接写Service或者读Service即可。
Redis Sentinel Operator两种服务暴露方式都支持,根据不同的CR Spec内容来选择。如下图所示,一套Redis Sentinel 的部署包含:
一个Redis Statefulset,负责维持部署Redis所需的Pod资源 一个Sentinel Statefulset,负责维持部署Sentinel所需的Pod资源 Secret存储Redis密码 一个负责Redis配置的Configmap和一个负责Sentinel配置的Configmap 一个暴露Sentinel服务的Service 一个指向Redis主节点的写Service和一个指向所有Redis的读Service,或单独为每个Redis Pod建立的Service 负责定期对Redis进行持久化的一个Cronjob

RedisSentinel CRD
建立RedisSentinel CRD资源,首先将Redis Sentinel的需求进行抽象,如下所示:
spec:
redisSize: 2
sentinelSize: 3
rwMode: false
image: redis:latest
dbSize: 4Gi
该spec描述了部署一个Redis Sentinel的基本需求,包含Redis节点数、Sentinel节点数、是否使用读写service模式、使用的redis镜像版本和每个Redis节点的最大内存大小。
然后,我们使用CRD将该需求定义扩展到Kubernetes,成为Kubernetes支持的资源:
apiVersion: apiextensions.k8s.io/v1beta1
kind: CustomResourceDefinition
metadata:
name: redissentinels.redis.cmbc.com.cn
spec:
group: redis.cmbc.com.cn
version: v1alpha1
names:
kind: RedisSentinel
listKind: RedisSentinelList
plural: redissentinels
singular: redissentinel
scope: Namespaced
该yaml文件定义了Kubernetes支持的一个资源,资源的Group是redis.cmbc.com.cn,Version是v1alpha1,Kind是RedisSentinel。
接下来就可以使用如下yaml在Kubernetes中创建RedisSentinel资源的实例:
apiVersion: redis.cmbc.com.cn/v1alpha1
kind: RedisSentinel
metadata:
name: demoredissentinel
namespace: redispaas
spec:
...
作者简介
孟玉立,中国民生银行信息科技部开源软件支持组工程师,目前主要负责Kubernetes、Redis的源码研究和工具开发等相关工作。




