有状态应用 vs 无状态应用

在学习Kubernetes的控制器的时候,我们知道"Deployment控制器适用于无状态应用,StatefulSet控制器适用于有状态的应用",那么,什么是有状态,什么又是无状态?一起来看看他们的区别。

1.直击核心问题:"状态"到底指什么?

在K8s语境中,"状态"其实就两件事:

数据:应用重启之后,之前存的东西还在不在?

身份:应用重启之后,别人还能不能用同一个地址找到它?

如果一个应用对这两样都不在乎,那就是无状态;如果它在乎其中任何一样,那就是有状态。

举个例子:你去便利店买瓶水,收银员扫完码收了钱,这笔交易就结束了。下一位顾客来了,他不需要记得你买过什么,收银员也不需要在脑子里存着上一单的数据。这是无状态。但如果你办了张会员卡,余额存在系统里,下次来还能接着用,这个"余额"就是状态,系统必须把它记住。

对应到K8s里,一个Pod是"干完活就走"还是"得带着家当干活",直接决定了该用哪个控制器来管它。

2.无状态应用:Deployment轻松搞定

平时我们见到的大多数业务应用,比如用Spring Boot写的API服务、前端的Vue或React应用,本质上都是无状态的。它们收到请求,处理,返回结果,不往本地磁盘存什么重要东西,也不关心自己到底是集群里的第几号选手。

这类应用的核心特点 就是可替换。

  • Pod挂了?直接重建一个新的,哪怕IP变了、名字变了,完全没关系,新Pod和旧Pod等价,能照常干活。

  • 流量大了?从3个副本直接扩到10个副本,新增的Pod马上就能加入工作。

  • 版本升级?滚动更新走起,新的起来几个,老的停掉几个,整个过程不讲究顺序,并行操作就行。

在K8s里,负责管这类应用的控制器就是Deployment。Deployment的设计哲学很简单:你怎么定义,我就怎么执行。扩容、缩容、升级、回滚,统统几句话的事。它生成的Pod名字也是随机的,比如 order-api-6d8f9c7b-xt2k5,看名字就知道,这些Pod没什么特殊身份,谁跟谁都一样。

总之,无状态应用不存数据在本地,数据都在外面(Redis、MySQL、对象存储等)存着,所以Pod本身可以随意处置。

3.有状态应用:StatefulSet精心布置

跟无状态相比,有状态应用有额外的要求。像MySQL、Kafka、Zookeeper、Elasticsearch,它们在K8s里跑的时候,要遵循两个规则:

  1. 数据不能丢:数据库的Pod如果挂了,等它再起来,之前存的数据必须还在。这就需要给每个Pod挂上独立的PVC(持久化存储卷),人走数据不走。

  2. 身份要固定:比如MySQL主从集群,从库得一直能通过固定的名字找到主库。如果主库重启之后IP变了,从库就不认识了。所以每个Pod得有唯一且稳定的网络标识。

就像便利店收银员可以随便换人,谁站那儿都能干;快递柜就不一样了,每个格子有固定编号,你取件的时候得对着那个编号去开。而且格子里的包裹不能丢,那是人家的东西。这就是有状态。

K8s专门为这类应用定制了StatefulSet。跟 Deployment的"随便"不同,StatefulSet的规矩很细:

  • 有序启停:创建时从0到N按顺序来,mysql-0 跑起来了,才启动 mysql-1。缩容时反过来,先删编号大的。不能乱插队。

  • 固定名字和存储:mysql-0 永远叫 mysql-0,它用的PVC也永远跟着它。就算Pod被删了重建,新的mysql-0还是会挂上原来的盘,找回原来的数据。

  • 稳定网络地址:配合 Headless Service(无头服务),每个Pod都有一个不会变的DNS域名,比如 mysql-0.database.svc.cluster.local。无论Pod怎么重启、IP怎么变,用这个域名永远能找到它。

一句话总结:StatefulSet里的每个Pod都是有"身份证"的,序号、存储、域名都是它的专属配置,不能搞混。

4. 他们不是对立关系,是黄金搭档

初学的时候,我把他们看作对立的关系,这个理解是错误的。在实际项目里,它们通常是配合使用的。

云原生架构有一个黄金原则:计算层尽量无状态,存储层做有状态**。**

什么意思呢?你把业务逻辑代码(计算层)做成无状态的,用Deployment部署,随便扩缩容,尽情享受K8s的弹性红利。但这些业务跑起来要存数据吧?那就把数据交给底层专业的中间件(存储层),用StatefulSet部署,让它们稳稳当当地保存。

举个例子,如果我要写一个订单服务(无状态,Deployment),它收到请求后处理业务逻辑,但最终的订单数据存在底层的MySQL数据库里(有状态,StatefulSet)。这样就会形成一个四层结构:无状态的前端页面、无状态的订单API服务、有状态的Redis缓存和有状态的MySQL数据库。每一层各司其职,各用各的控制器。

5.一张表格看懂区别

对比维度 无状态应用(Deployment) 有状态应用(StatefulSet)
数据存哪 不存本地,重启就丢 必须挂PVC,数据跟盘走
Pod身份 完全等价,名字随机生成 有固定序号,比如mysql-0、mysql-1
扩缩容 随便扩、随便缩,不讲究顺序 必须有序,逐个启动或删除
升级策略 并行滚动更新 逆序滚动更新,从最大编号开始逐个升
网络标识 靠Service的虚拟IP,不固定 靠Headless Service,有稳定的DNS域名
对应控制器 Deployment StatefulSet
典型应用 Nginx、Spring Boot API、前端应用 MySQL、Kafka、Zookeeper、Elasticsearch

6.运维场景的差异

1.Pod挂了之后的恢复速度不一样。

Deployment管的Pod挂了,K8s几乎是立刻拉起一个新的,速度很快。StatefulSet的Pod挂了,重建的时候得等PVC重新挂载,这个过程会慢一些,这属于正常现象。

2. 删StatefulSet不会删PVC!

这是个特别容易忽略的点。当你执行 kubectl delete statefulset,Pod会被删掉,但那些PVC(硬盘)会留着。K8s这么设计是为了保护数据,防止误删。但如果你不手动清理,时间长了那些PVC会一直占着集群的存储资源。

3. 无状态≠没数据。

无状态应用不是说它不能处理数据,而是说数据不在Pod本地存。一个订单API处理订单数据,最后存到MySQL里,这个API本身依然是无状态的,因为数据不在它身上。数据在MySQL那里,MySQL才是有状态的。

相关推荐
虎头金猫3 天前
4K 视频总卡在公网带宽?用 N1 + OpenList 把网盘播放链路重新理顺
运维·服务器·网络·python·容器·beautifulsoup·pandas
分布式存储与RustFS3 天前
MinIO 官方 Docker 镜像被移除:依赖它的项目该怎么办
docker·云原生·devops·对象存储·minio·分布式存储
AI职业加油站3 天前
AI智能体应用工程师证书:政策红利下的职业新风口
大数据·运维·人工智能·学习·职场发展
codeejun3 天前
每日一Go·MySQL-5、锁机制全解析
云原生·golang
此冬歌咏3 天前
K8s 节点故障实战:优雅驱逐 31 秒,硬故障 331 秒,以及那个永远 Pending 的 Pod
运维·k8s
玉&心3 天前
通过Arthas在线诊断K8S中的内存及JVM等使用情况
docker·k8s·arthas
-梅3 天前
linux(8) 软硬链接
linux·运维·服务器
张洛闻Eren3 天前
k8s云原生【第十课】:水平 Pod 自动扩缩容
运维·数据库·云原生·kubernetes·github
流烟默3 天前
K8s StatefulSet 详解:有状态应用的“身份证”与“固定住址”
k8s·statefulset
其实防守也摸鱼3 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透