Redis的哨兵模式通过多个哨兵实例共同去检测Redis实例的存活,并在达成共识后选出共同的主实例来做到故障检测、通知和故障转移。一个三节点的哨兵模式部署简图如下图所示:
图中R代表Redis实例,一主两备;S代表Sentinel实例,三个Sentinel实例共同工作,去对Redis主实例和备实例进行存活检测。
在进行Sentinel方案进行部署时,要点在于:
- 每个节点上部署一个sentinel实例和一个redis实例;
- redis实例采用Pod反亲和性实现Redis实例之间的互斥,避免了多个Redis实例在机器宕机后迁移到同一个节点上;
- sentinel实例采用Pod反亲和性实现Sentinel实例之间的互斥,确保在集群出现节点宕机后,不会出现sentinel实例位于相同节点上的情况,因为如果出现这种情况,后续有多个sentinel实例的master节点宕机了,此时集群中会因为sentinel数量不足导致无法进行故障切换,进而直接导致集群不可用。
Kubernetes的调度策略
一般情况下,我们在Kubernetes上部署服务的时候,会通过标签的方式,让Kubernetes集群基于其内部自动调度策略去选择节点完成节点选择完成应用部署。但也存在一些情况,需要进行更加细粒度的调度,这些情况下可能需要动态的去实现调度,而不像标签一样是静态的,打上标签后就不怎么变,比如上面我们所讲的Sentinel部署的例子,Redis实例和Sentinel实例需要保持一定的实例反亲和,以避免后续一些奇奇怪怪的部署拓扑发生,导致集群不可用。
亲和性调度策略包括了node和pod两个维度,每一种又包括了亲和性(Affinity)和反亲和性(AntiAffinity)。此外吗,在亲和性和反亲和性之下,还包括了软策略和硬策略:软策略(preferredDuringSchedulingIgnoredDuringExecution)表示尽量来满足定义的亲和性或者反亲和性策略,如果不满足,也没关系,可以继续完成调度;硬策略(requiredDuringSchedulingIgnoredDuringExecution)则表示,如果不满足定义的亲和性或者反亲和性策略,该应用就无法完成调度获取执行的资格。
节点的亲和性(nodeAffinity)一般用于使应用调度到期望节点上,以上面讲的Sentine方案部署为例,我们希望Redis和Sentinel实例都只能部署在打了“dev.midware.redis=true”标签的开发机器上,那么配置方式就可以如下所示:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: dev.midware.redis
operator: In
values:
- "true"
上述配置中,operator可以有多种选择:
操作符 | 含义 |
In | 表示标签在values下定义的字符串集合中 |
NotIn | 表示标签不在values下定义的字符串集合中 |
Exists | 表示Pod或者Node上存在values下定义的字符串 |
DoesNotExist | 表示Pod或者Node上不存在values下定义的字符串 |
Gt | values中定义的整数小于标签中的数值时,满足调度 |
Lt | values中定义的整数大于标签中的数值时,满足调度 |
Pod的亲和性(podAffinity)和节点的亲和性使用方式类似,主要是解决pod之间是否需要部署在同一个部署拓扑中的问题。
在Sentinel的部署示例中,我们主要采用的是Node的亲和性和Pod的反亲和性(podAntiAffinity)来实现。一方面保证,Sentinel能够找到一个Redis实例并与之部署到一块,另一方面要保证,Sentinel不要和其他Sentinel实例部署到了同一个节点上。具体实现思路如下:为每个Redis Pod打上一个Redis实例标签:test.redis=true,表示是redis实例;同时为每个Sentinel Pod打上一个sentinel实例标枪:test.sentinel=true,表示该Pod是sentinel。这样以后,Sentinel和Redis的Pod反亲和性需要配置成:同时具有redis实例和sentinel实例的节点,则执行硬性策略,禁止向该节点上调度。具体配置如下:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: test.sentinel
operator: In
values:
- "true"
- key: test.redis
operator: In
values:
- "true"
本文结合Redis的Sentinel高可用方案,结合Kubernetes来进行部署,基于Kubernetes的node和pod的亲和性完成哨兵模式部署,并对Kubernetes的亲和性调度策略进行了更深度的学习和理解。