StatefulSet核心实现原理StatefulSet是k8s中有状态应用管理的标准实现。今天我们就来了解一下它的设计背后的场景和原理,从而了解它的适用范围和场景。1.基本概念首先介绍一些有状态应用中需要考虑的基本的东西,然后我们会在下一章看statefulSet的关键实现。1.1有状态和无状态在日常开发应用中,通常可以分为两类:有状态和无状态。例如,Web服务通常是无状态的,Web应用数据主要来自后端存储、缓存等中间件。,但不保存数据本身;而它的redis、es等数据也是应用本身的一部分,所以可以看出有状态应用本身会包含应用和数据两部分。1.2一致性和数据一致性是分布式系统中非常普遍的问题。上面提到有状态的应用程序包含数据部分。数据和一致性是一回事吗?答案不一定,在zookeeper等应用中,数据会通过zab协议写入到集群中的大部分节点,而kafka等应用对一致性设计要求比较低,可见一致性有状态的应用数据,更多是由对应场景的系统设计决定的。1.3身份在一些应用中,身份是系统本身的一部分。比如zookeeper通过server的id影响ZAB协议的最终选举,Kafka中partition的分配也是根据对应的id进行分配。1.4单调有序更新一般在分布式系统中,至少要保证分区容错性,防止部分节点失效导致整个系统不可用。k8s中statefulset中Pod的管理策略是尽可能安全地保证Pod一个一个更新,而不是并行启动或停止所有Pod。1.5扩容和故障转移k8s中的水平扩容和缩容很简单,比如删除和添加一个Pod,但是对于有状态的应用,我不知道这些东西,比如扩容后的数据如何平衡,之后如何进行故障转移节点故障,这些都是有状态应用需要自己考虑的。2、StatefulSet实现机制的核心实现整体流程比较简单。下面按照Pod管理、状态计算、状态管理、更新策略等部分依次进行讲解。2.1Pod的release和adoptstatefulSet中pod的名字是按照一定的规则设置的,名字本身是有含义的。k8s在更新statefulset时,会先过滤属于当前statefulset的pod,在K8scontrol中进行如下操作controller与Pod的关系主要通过两个部分:controllerRef和label。statefulset在过滤Pod时,如果发现对应pod的controllerRef是当前statefulset但其label或name不匹配,则会尝试释放对应关系。豆荚。反之,如果发现对应Pod的label和name匹配,但是controllerRef不是当前statefulSet,则将对应controllerRef更新为当前statefulset。此操作称为采用。通过这个过程,你可以保证当前statefulset关联的Pod要么关联当前对象,要么我就release你,这样就可以保持Pod的一致性。即使有人修改了对应的Pod,也会调整到最终一致性。2.2Replica分类经过第一步的Pod状态校正后,statefulset会遍历自己所有的Pod,同时将Pod分为有效副本和无效副本(condemned)两类,前面提到的Pod的名称就是它也是有序的,即具有N个副本的Pod的名称顺序为{0...N-1}。这里区分有效和无效也是根据对应的索引顺序。如果超过当前副本,则为无效副本。2.3单调更新单调更新主要是指当相应的Pod管理策略不是并行管理时,只要当前Replicas(有效副本)中的任何一个Pod被创建、终止或未就绪,就会等待相应的Pod来beready,即当你要更新一个statefulsetPod时,对应的Pod必须是RunningAndReady。funcallowsBurst(set*apps.StatefulSet)bool{returnset.Spec.PodManagementPolicy==apps.ParallelPodManagement}2.4基于计数器的滚动更新滚动更新的实现比较晦涩。主要是通过控制拷贝数来实现的。首先倒序查看对应的Pod的版本是否是很新的版本,如果不是,则直接删除对应的Pod,并将currentReplicacount减一,这样在查看对应的Pod的时候就会发现对应的Pod不存在,需要查看对应的Pod。Pod生成新的Pod信息,将使用较新的副本进行更新。funcnewVersionedStatefulSetPod(currentSet,updateSet*apps.StatefulSet,currentRevision,updateRevisionstring,ordinalint)*v1.Pod{//如果发现当前Pod的index小于当前copycount,说明当前Pod还没有被更新了,但实际上可能是因为其他原因//需要重新生成Pod模板,此时仍然使用旧的replica配置。))||(currentSet.Spec.UpdateStrategy.RollingUpdate!=nil&&ordinal
