在K8S环境部署tidb集群,tidb server节点为什么是以statefulset形式部署的?

【TiDB 使用环境】生产环境 /测试环境
【TiDB 版本】
【部署方式】虚拟机部署
【操作系统/CPU 架构/芯片详情】
【机器部署详情】
【集群数据量】
【集群节点数】3
【问题复现路径】
【遇到的问题:问题现象及影响】
按照官网文档,使用TiDB Operator 部署3节点TiDB集群,tidb server节点为什么是以statefulset形式而不是deployment部署的?而且service类型是NodePort而不是ClusterIP?
PD和TiKV以这种方式部署我可以理解,tidb server似乎没有必要。

【资源配置】
【复制黏贴 ERROR 报错的日志】
【其他附件:截图/日志/监控】

StatefulSet 为了稳定有序管理,NodePort 为了对外提供访问。

Deployment 管无状态,无序、可替换;StatefulSet 管有状态,有序、身份固定。

因为上面有事务,并且要求一致性操作啊

我问的不是pd和tikv,而是tidb server,它本身是无状态的啊,为什么不以deployment方式部署?

个人感觉还是为了架构考虑,技术统一,管理方便吧

虽然 TiDB Server 是 无状态组件 ,但 TiDB Operator 依然用 StatefulSet

是这个原因

这不等于没说嘛,我就是想知道TiDB Operator 为什么用 StatefulSet?

结合源码解读,AI 总结:

一、StatefulSet vs Deployment:TiDB 为什么用 StatefulSet?

核心区别

特性 StatefulSet Deployment
Pod 标识 固定序号 tidb-0, tidb-1, tidb-2 随机后缀 tidb-7f8b9c-xxxx
网络标识 稳定 DNS tidb-0.tidb-headless.ns.svc Pod 重建后 DNS 变化
存储卷 每个 Pod 绑定独立 PVC 所有 Pod 共享 PVC 模板
扩缩顺序 有序:0→1→2,缩容 2→1→0 并发,无序
滚动更新 按序号逆序逐个更新 并发替换(可控制 maxSurge)

TiDB 必须用 StatefulSet 的原因(v1 架构)

  1. 稳定网络身份:TiDB Server 是无状态节点,但客户端(如 TiDB Spark Connector、JDBC)通过 JDBC URL 连接,需要稳定的 DNS 名称。StatefulSet 提供的 <pod-name>.<headless-svc> DNS 是 TiDB 组件间互相发现的基础。

  2. 有序滚动更新:TiDB 升级需要按序逐个重启,确保集群始终有可用节点。Deployment 的并发更新策略可能导致同时重启多个 TiDB 实例。

  3. 独立 PVC 绑定:虽然 TiDB Server 本身不存数据,但 v1 架构中 StatefulSet 的 volumeClaimTemplates 为每个 Pod 独立创建 PVC,便于日志持久化等场景。

如果换成 Deployment 会怎样?

  • Pod 重建后 DNS 变化:客户端连接中断,需要重新解析服务地址(虽然有 Service 做负载均衡,但定向连接场景会受影响)
  • 扩缩容不可控:无法保证 TiDB 节点按序启停,对依赖启动顺序的场景有风险
  • 无法按序号操作单个 Pod:比如想单独重启 tidb-2,Deployment 不支持

有趣的是:TiDB Operator v2 已经移除了 StatefulSet

v2 架构采用了 Instance CR 模式,每个 TiDB 实例直接管理独立 Pod,不再依赖 StatefulSet。原因在 docs/why.md 中有明确说明:

StatefulSet has significant limitations as a low-level abstraction for effectively managing TiDB:

  • Cannot scale specific pod by index
  • No pre/post hooks for lifecycle events
  • Cannot modify volume template after creation

v2 通过 Pod Subdomain + Headless Service 手动实现了稳定的网络身份,绕过了 StatefulSet 的限制。


二、NodePort vs ClusterIP:Service 类型选择

核心区别

特性 NodePort ClusterIP
访问范围 集群外部可通过 <NodeIP>:<Port> 访问 仅集群内部可访问
端口范围 30000-32767 任意端口
适用场景 开发测试、无 LoadBalancer 环境 生产环境 + Ingress/LB
安全性 暴露节点端口,风险较高 集群内隔离,更安全

为什么帖子上看到的是 NodePort?

这很可能是 TiDB Operator v1 的默认行为。在 v1 源码 pkg/controllers/tidbgroup/tasks/svc.go 中,Internal Service 的类型是硬编码为 ClusterIP 的,但 External Service(用于外部访问 TiDB)使用的是 NodePort。

实际上这取决于部署配置中的 spec.tidb.service.type 字段:

  • 生产环境推荐 ClusterIP + LoadBalancer/Ingress
  • 测试环境或无 LB 支持的环境使用 NodePort

实际影响

  1. NodePort 的隐患

    • 端口范围有限(30000-32767),集群规模大时端口可能冲突
    • 暴露节点 IP,安全边界扩大
    • 节点 IP 变化时客户端需要更新连接地址
  2. ClusterIP 的局限

    • 集群外无法直接访问,需要额外网关层
    • 适合生产环境配合 Ingress Controller 或云厂商 LoadBalancer 使用
  3. v2 的做法:v2 中 TiDB 的 Service 直接硬编码为 ClusterIP,不再提供 NodePort 选项,强制使用更安全的内部访问方式。


总结

问题 结论
为什么用 StatefulSet 不用 Deployment? 稳定网络身份 + 有序管理 + 独立 PVC,但 v2 已改用 Instance CR 方案
为什么用 NodePort 不用 ClusterIP? 便于外部访问,但生产推荐 ClusterIP + LB/Ingress,v2 已默认 ClusterIP
实际影响? StatefulSet 保证运维可控性;NodePort 便于测试但不适合生产

帖子上用的 v8.5.3 对应的是 v1 Operator 架构(StatefulSet + 可选 NodePort),如果是新部署可以考虑 v2 架构。

k8s上的部署方式还是需要statefullset类型pod操作的

TiDB Server 是 无状态组件