有状态应用 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-0mysql-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才是有状态的。

相关推荐
mohesashou3 小时前
k8s的service
云原生·容器·kubernetes
starzy19903 小时前
虚拟化解决方案全景:软件虚拟化、硬件虚拟化与 Docker 的位置
运维·docker·容器
Neighbor_OldY4 小时前
云上安全配置审计与误配置修复实战:从安全组、OSS、RAM到数据库的全栈排查复盘
大数据·运维·安全·云计算
开心大爆炸5 小时前
xrdp 连接 登录对话框输入密码后闪退
linux·运维·服务器
阿里云云原生5 小时前
Agent 开发范式演进:在通用智能与业务深度之间寻找“正交”平衡点
云原生
苏生Susheng6 小时前
【软件实施】Linux系统Shell脚本教程
linux·运维·服务器·chrome·spring boot·学习·实施
2601_962304916 小时前
把出片接进自动化流水线:2026 年批量 AI 视频生成工具的脚本契约与同类项目对照
运维·人工智能·自动化
Ruiery6 小时前
Linux 6.6内核 IOMMU 深度解析(七):DMA API 与 IOMMU 集成 — 从 dma_map_single 到 iommu_map
linux·运维·服务器
源代码•宸6 小时前
前置准备:定时微服务背景和现状
开发语言·经验分享·后端·微服务·云原生·架构·golang