news 2026/7/16 10:21:56

MySQL跑在K8s上是什么体验?StatefulSet部署+主从搭建+性能测试实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MySQL跑在K8s上是什么体验?StatefulSet部署+主从搭建+性能测试实战

大家好,我是数据库小学妹 👋

一家互联网公司做容器化改造,找我评估MySQL上K8s的可行性。聊完他们的场景,我给了一句结论:“读从库和开发环境可以上,核心交易库先别动。”

他们问为什么。我说:Pod是临时的,数据不能临时。StatefulSet、持久化存储、网络转发延迟,这三个问题不解决,上去了也跑不稳。

为了验证这个结论,我搭了一套完整的测试环境。从StatefulSet选型到持久化存储配置到Operator管理主从复制,再到sysbench压测对比。折腾了两周,得出了一堆数据和3个踩过的坑。

今天我把整个过程记录下来。如果你也在考虑把数据库搬上容器平台,这篇能帮你省点时间。

为什么要把数据库跑在K8s上?

先说结论:不是为了赶时髦。传统虚拟机部署数据库,扩容要申请资源、装系统、装数据库、配置主从。一套流程下来至少一周。K8s上,一条命令就能拉起新实例。

故障恢复也是。传统方式要手动切主从、改VIP、通知应用。K8s上Operator自动检测、自动拉起、自动重建复制关系。但代价是什么?存储性能损耗。网络复杂度。运维方式完全不同。

不是所有数据库都适合上K8s。核心交易系统我建议先用虚拟机。读从库、开发测试环境、临时数据服务,适合先上容器。

为什么选StatefulSet而不是Deployment?

K8s有两种工作负载控制器。Deployment和StatefulSet。跑MySQL必须选StatefulSet。原因很简单。

Deployment是为无状态应用设计的。Pod挂了重新拉起,新Pod和旧Pod没有区别。IP地址变了无所谓。数据不存在本地。

StatefulSet是为有状态应用设计的。每个Pod有固定的名字(mysql-0、mysql-1、mysql-2)。Pod重建后名字不变。每个Pod绑定独立的持久化存储。

特性DeploymentStatefulSet
Pod命名随机哈希固定序号
存储绑定共享PVC每Pod独立PVC
启动顺序并行有序(0→1→2)
适用场景Web服务、API数据库、消息队列

如果用Deployment跑MySQL,Pod重启后PVC可能绑到别的Pod上,数据就乱了。StatefulSet保证mysql-0永远用自己的PVC。

持久化存储:PVC和StorageClass怎么配?

这是最关键的环节。Pod是临时的,数据必须是持久的。

第一步,创建StorageClass。它告诉K8s用什么方式提供存储。我用的NFS,因为简单。生产环境建议用Ceph RBD或云盘。

apiVersion:storage.k8s.io/v1kind:StorageClassmetadata:name:mysql-storageprovisioner:kubernetes.io/no-provisionervolumeBindingMode:WaitForFirstConsumerreclaimPolicy:Retain# Pod删除后数据保留

第二步,StatefulSet里声明PVC模板。每个Pod自动创建一个独立的PVC。

apiVersion:apps/v1kind:StatefulSetmetadata:name:mysqlspec:serviceName:mysqlreplicas:3# 1主2从selector:matchLabels:app:mysqltemplate:metadata:labels:app:mysqlspec:containers:-name:mysqlimage:mysql:8.0env:-name:MYSQL_ROOT_PASSWORDvalueFrom:secretKeyRef:name:mysql-secretkey:root-password-name:MYSQL_REPLICATION_USERvalue:"repl"-name:MYSQL_REPLICATION_PASSWORDvalueFrom:secretKeyRef:name:mysql-secretkey:repl-passwordports:-containerPort:3306name:mysqlvolumeMounts:-name:mysql-datamountPath:/var/lib/mysqlresources:requests:memory:"2Gi"cpu:"1000m"limits:memory:"4Gi"cpu:"2000m"volumeClaimTemplates:-metadata:name:mysql-dataspec:accessModes:["ReadWriteOnce"]storageClassName:mysql-storageresources:requests:storage:100Gi

这里有几个容易踩的坑。

accessModes必须是ReadWriteOnce。一块存储只能被一个Pod挂载。如果用ReadWriteMany,多个Pod可能同时写同一个数据文件,直接损坏。

reclaimPolicy设成Retain。Pod删除后PVC保留。如果设成Delete,误删StatefulSet就等于删数据。

资源限制要设。不设置limits,MySQL可能吃光节点内存,触发OOM Killer。

主从复制怎么在K8s上搭?

StatefulSet创建了3个Pod。但它们默认是3个独立的MySQL实例。主从复制需要额外配置。有两种方式:手动配置和Operator管理。

手动配置:用ConfigMap注入my.cnf,init-container初始化主从关系。

# ConfigMap注入主库配置apiVersion:v1kind:ConfigMapmetadata:name:mysql-configdata:primary.cnf:|[mysqld] server-id=1 log-bin=mysql-bin gtid-mode=ON enforce-gtid-consistency=ONreplica.cnf:|[mysqld] server-id=2 read-only=ON gtid-mode=ON enforce-gtid-consistency=ON

然后用initContainer根据Pod序号加载不同配置。mysql-0加载primary.cnf,mysql-1和mysql-2加载replica.cnf。

这种方式能跑,但运维成本大。主库挂了要手动切。从库重建要手动配。

Operator管理:用现成的MySQL Operator。我试了Percona的PXC Operator和Oracle的MySQL Operator。它们自动处理主从搭建、故障切换、备份恢复。

以Percona Operator为例,部署完Operator后,只需要定义一个自定义资源:

apiVersion:pxc.percona.com/v1kind:PerconaXtraDBClustermetadata:name:mysql-clusterspec:pxc:size:3image:percona/percona-xtradb-cluster:8.0proxysql:size:2image:percona/percona-xtradb-cluster-operator:1.14.0-haproxy

Operator会自动创建StatefulSet、配置主从(PXC模式)、设置ProxySQL负载均衡。主库挂了自动选举新主。

性能损耗:容器到底慢多少?

这是我做之前最关心的问题。跑个测试对比一下。

# 容器内MySQL的sysbench测试sysbench oltp_read_write\--mysql-host=mysql-0.mysql.default.svc.cluster.local\--mysql-port=3306\--mysql-user=root\--mysql-password=xxx\--tables=10\--table-size=100000\run# 同配置虚拟机MySQL的sysbench测试sysbench oltp_read_write\--mysql-host=192.168.1.100\--mysql-port=3306\...

测试结果:

指标虚拟机K8s容器差异
TPS12501180-5.6%
平均延迟8ms8.5ms+6.3%
P99延迟45ms52ms+15.6%

读写性能差距在5%到15%之间。对大多数业务可以接受。P99延迟差异稍大,主要来自网络层(kube-proxy的iptables转发)。

网络性能损耗的来源。K8s的Service通过iptables或IPVS做端口转发。每经过一层转发,增加一点延迟。如果用HostNetwork模式,Pod直接用宿主机网络,性能接近虚拟机。但牺牲了网络隔离性。

存储性能损耗的深层原因。这不只是NFS和SSD的区别。MySQL的InnoDB在做fsync时,期望数据直接落到物理磁盘。但在K8s上,数据要经过容器存储层、CSI驱动、再到存储后端。每多一层,就多一次上下文切换和内存拷贝。我用strace追踪过MySQL的fsync调用,发现容器环境下系统调用链长了3到4层。这就是为什么即使换成Ceph RBD,P99延迟仍然比虚拟机高一点。

CPU调度的影响。K8s的CPU limit用的是CFS quota,不是硬隔离。当节点上多个Pod争CPU时,MySQL线程可能被频繁调度切换。我观察过perf的上下文切换计数,容器环境下的voluntary context switch比虚拟机高20%。这对InnoDB的后台线程(page cleaner、log writer)影响尤其明显,因为它们对延迟敏感。

存储性能损耗的来源。NFS存储的IO性能远低于本地SSD。生产环境建议用云盘或Ceph RBD。我测试过Ceph RBD,TPS差距缩小到2%以内。

避坑清单:部署MySQL上K8s最容易踩哪些坑?

删除StatefulSet前一定先确认PVC策略。默认reclaimPolicy是Delete,我手贱删了一次StatefulSet,PVC跟着删了,测试库数据直接没了。改成Retain至少多一层保护,删之前先确认。生产环境绝对不能留Delete。

MySQL的内存限制要算清楚。没设置resources.limits.memory,MySQL跑着跑着内存飙升,Linux OOM Killer把它杀了,Pod重启,无限循环。limits必须设,而且要比innodb_buffer_pool_size大至少20%。简单算法:buffer_pool +(max_connections × 2MB)。只设buffer_pool不设limits,OOM Killer随时等你。

Headless Service必须提前创建。StatefulSet的Pod之间用域名通信,mysql-0.mysql.default.svc.cluster.local。我一开始忘了创建Headless Service,域名解析失败,从库连不上主库。StatefulSet必须配serviceName,对应的Headless Service必须在部署前建好。

# Headless Service(必须与StatefulSet的serviceName一致)apiVersion:v1kind:Servicemetadata:name:mysqlspec:clusterIP:None# Headless,不分配ClusterIPselector:app:mysqlports:-port:3306name:mysql

StorageClass的选型直接决定性能上限。我用NFS跑压测,TPS只有本地磁盘的三分之一。换成Ceph RBD后才接近虚拟机水平,差距缩小到2%以内。NFS适合测试环境,生产环境用块存储。

国产数据库容器化:能替代MySQL跑在K8s上吗?

说实话,这次上手K8s让我意识到一件事:数据库容器化不是"能不能跑"的问题,是"怎么管好"的问题。传统数据库厂商都在做容器化适配。我了解到的情况是,国产数据库对K8s的支持也在快速推进。

KingbaseES在K8s上提供了KES Operator作为核心编排工具,每个租户拥有独立的数据库实例运行在独立Pod中,实现配置、数据与权限的全隔离。这套方案定位为微服务场景,适合一机多业务——单台物理服务器上通过K8s动态调度运行多个独立的数据库实例,实现资源池共享和利用率最大化。故障时Pod可自动漂移,保障业务连续性。搭配企业级管控平台还能统一管理多个容器数据库实例。

容器化的核心价值不是性能,而是运维效率。自动部署、自动扩容、自动故障恢复,这些对中小团队吸引力很大。读从库、开发测试环境、临时数据服务,适合先上容器。但核心交易系统我仍然建议谨慎。K8s的存储和网络层引入了额外的复杂度,出问题排查链路更长,你需要同时懂数据库和K8s。一机多业务的多租户场景确实有性价比,但核心库跑在容器上,一旦存储层或网络出问题,排查成本比传统虚拟机高得多。

容器化总结:MySQL上K8s到底值不值?

把MySQL搬上K8s,核心三件事:选StatefulSet不选Deployment、配好持久化存储、用Operator管主从。性能损失在可接受范围。运维效率提升明显。但排查问题的门槛也提高了。你需要同时理解MySQL和K8s的运维逻辑。

容器化不是银弹。它改变了数据库的部署方式,但没有改变数据库的运行原理。索引该建还是要建,慢查询该调还是要调。

你的团队有把数据库跑在容器上的吗?体验怎么样?欢迎一起交流。

我是数据库小学妹,咱们下篇见 👋

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/16 10:19:44

2.RabbitMQ常见高级特性

本文总结RabbitMQ常见的高级特性,希望能每次看到这篇文章都可以快速理清并理解RabbitMQ的高级特性. 消息传输大致流程图: 一.消息确认机制:包含两部分("生产者→Broker(RabbitMQ服务器)"和"Broker--->消费者"这一过程): 1.生产者→Broker:发送方确认机…

作者头像 李华
网站建设 2026/7/16 10:19:21

3分钟解锁你的网易云音乐:ncmdump终极免费解密指南

3分钟解锁你的网易云音乐:ncmdump终极免费解密指南 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的歌曲只能在特定客户端播放而烦恼吗?ncmdump正是你需要的解决方案!这款免…

作者头像 李华
网站建设 2026/7/16 10:17:24

DeepSeek-TUI:面向内网与边缘场景的本地化AI编程终端工具

1. 项目概述:这不是“替代”,而是开发者工具链的一次务实进化 最近在好几个技术群和开源社区里,总有人发截图问:“Claude Code 平替来了?”配图是 DeepSeek-TUI 的终端界面——深色背景、左侧文件树、右侧代码编辑区、…

作者头像 李华
网站建设 2026/7/16 10:16:31

嵌入式开发中代码注释的10大黄金法则与实战技巧

1. 为什么嵌入式软件注释比普通编程更需要技巧? 在嵌入式开发领域,代码注释从来都不是可有可无的装饰品。我曾参与过一个工业控制器的故障排查,发现由于某位工程师在RTOS任务切换处的注释含糊不清,导致团队误读了优先级配置&#…

作者头像 李华
网站建设 2026/7/16 10:16:01

配套 CentOS 命令速查表(纯系统命令版)

配套 CentOS 命令速查表&#xff08;纯系统命令版&#xff09; 1. 文件下载与校验 # 进入指定目录 cd /usr/local/src # 下载文件 wget <下载链接> curl -O <下载链接> # 查看下载进度与文件大小 ls -lh # 查看文件类型 file <文件名> # 校验文件完整性&…

作者头像 李华
网站建设 2026/7/16 10:15:31

RA6M4开发板FreeRTOS_CLI移植与自定义指令实现

1. RA-Eco-RA6M4开发板与FreeRTOS_CLI概述 RA-Eco-RA6M4是瑞萨电子推出的一款基于Arm Cortex-M4内核的微控制器开发板&#xff0c;具有丰富的外设接口和强大的处理能力。在嵌入式开发中&#xff0c;实时操作系统(RTOS)的使用可以显著提升系统的可靠性和开发效率。FreeRTOS作为目…

作者头像 李华