K8S 生产环境 MariaDB 存储扩容排查实战记录

一、问题背景

今天主要围绕生产环境 MariaDB 集群的存储扩容做了一轮排查和确认。当前环境中的 MariaDB 部署在 K8S 中,使用 StatefulSet 方式,每个副本都有独立的 PVC,底层存储通过 tceinf-csi-loopdevice 提供。

本次排查的直接原因主要有两个:

  1. 数据库当前 PVC 容量偏小,需要为后续上线预留更多空间。
  2. 本次上线涉及血缘关系相关需求,预计会批量写入大量数据,担心业务数据、索引以及 binlog 快速增长,导致磁盘被打满。

此外,历史上在 UAT 环境跑全量数据时,已经出现过磁盘被写满的情况,因此这次生产扩容必须提前做足准备。


二、最开始的误区:节点磁盘有空间,不代表 PVC 能扩

刚开始看节点磁盘时,发现单个节点上的磁盘使用率并不高,例如:

  • /data1 还有大量剩余空间
  • /data 也还有很多可用空间

但从 K8S 存储池角度看,PVC 却已经接近无法继续分配。这里出现了一个典型的认知差异。

1. df -h 看到的是节点文件系统剩余空间

这是操作系统层面的真实剩余空间。

2. kubectl get lsc -A 看到的是 CSI 存储池可分配空间

这是 K8S 存储类当前还能给 PVC 分配多少容量。

也就是说:

节点磁盘还有空闲,不代表 StorageClass 对外还能继续扩容。

这类问题在本地盘、loopdevice、LVM 池化类存储里特别常见。底层盘看着很空,但因为存储池只认某个路径,比如 data1,或者现有 PVC 已经按申请容量把池子占住了,所以可分配空间仍然不足。


三、PVC 扩容前真正该看的几个关键点

这次排查过程里,最终整理出来一个比较实用的检查链路:

Pod -> PVC -> PV -> StorageClass -> 存储池可分配空间 -> 节点底层磁盘

如果要判断数据库能不能扩容,建议按下面几个层次检查。

1. 查看数据库 Pod 分布在哪些节点

先看 StatefulSet 各副本落在哪些节点:

kubectl get pod -n sso -owide | grep mariadb

重点看:

  • Pod 是否正常 Running

  • 每个副本在哪个节点上

  • 三个副本是否各自绑定独立节点

因为 MariaDB 这种有状态服务,每个副本背后通常都是自己的 PVC,扩容时必须保证每个 Pod 所在节点都满足存储条件。

2. 查看 PVC 当前大小

kubectl get pvc -n sso | grep mariadb

重点确认:

  • 当前是否 Bound

  • 容量是多少

  • StorageClass 是什么

例如最开始 MariaDB 每个 PVC 是 50Gi

3. 查看 StorageClass 是否支持扩容

kubectl get sc tceinf-csi-loopdevice -o yaml

要重点确认是否有:

allowVolumeExpansion: true

如果没有这个能力,即使底层节点空间够了,PVC 也不能直接在线扩容。

4. 查看存储池剩余可分配容量

这一步是本次排查里最关键的一步:

kubectl get lsc -A

这里能看到各节点在当前存储类下,还剩多少可继续分配的空间。

最开始看到的是:

  • 某些节点只剩十几 Gi

  • 某些节点二十几 Gi

  • 最多的也不到 50Gi

而目标是把每个 PVC 从 50Gi 扩到 100Gi,意味着每个节点至少还要再提供 50Gi 可分配空间。所以初始状态下显然不满足条件。

5. 查看节点底层磁盘

如果要确认客户底层是否已经扩盘,可以到节点上看:

df -TH

例如查看 /data1 挂载点容量是否已经变大。

但是这里必须明确:

底层磁盘扩好了,只是前置条件之一。

最终能不能扩 PVC,还是要回到 kubectl get lsc -A,看存储池是否同步上涨。


四、本次处理思路:先让客户扩 data1,再谈 PVC

在排查清楚之后,结论其实比较明确:

  • 当前问题不在 K8S YAML 本身

  • 也不在 Pod 是否正常

  • 核心问题是 data1 对应的存储池可分配容量不够

因此这次给客户的建议也比较直接:

先对三个节点的 data1 分别扩容,再考虑 PVC 扩容。

这是一个很稳妥的推进方式,因为它把问题边界切得很清楚:

  • 客户负责底层磁盘扩容

  • 我们只关注 K8S 存储层是否具备扩容条件

后面客户完成扩容后,再看:

kubectl get lsc -A

最终三个目标节点的 AVAILABLE 都明显提升到了 120Gi+ / 140Gi+,这时才说明:

从存储池可分配空间角度,MariaDB PVC 已经具备扩容条件。


五、为什么最终把 PVC 目标容量从 100G 调整到了 120G

最开始的扩容目标是 100G,但结合本次上线内容,后面又把目标改成了 120G

这个调整并不是拍脑袋,而是基于几个现实判断。

1. 本次上线涉及血缘关系需求

血缘类需求往往会带来大量关系数据写入,尤其是初始化阶段、批量构建阶段、批量刷关系阶段,数据增长可能是瞬时放大的。

2. 数据库写入增长不只是业务表

磁盘占用不只是业务数据本身,还包括:

  • 表数据

  • 索引

  • 临时文件

  • binlog

  • relay log

  • 慢日志 / 错误日志

  • 更新、删除带来的额外空间膨胀

3. 已经有过 UAT 全量数据跑满磁盘的历史

这一点非常关键。既然 UAT 已经踩过坑,那生产就不能只按“理论最小值”来配。

所以把 PVC 从 100G 提高到 120G,本质上是在给上线阶段预留更大的 buffer,防止因为批量写入和 binlog 膨胀导致磁盘再次被打满。


六、MariaDB binlog 风险为什么要重点盯

这次讨论里,一个重点担忧就是:

binlog 会不会把磁盘刷满。

这个担忧是合理的,尤其是在批量数据写入场景下。

虽然当前 binlog 只保留 3 天回滚,但这并不意味着绝对安全。因为 binlog 是否会打满磁盘,取决于两个因素:

  1. 保留时间有多长

  2. 这 3 天内写入量到底有多大

如果上线当天写入非常集中,比如:

  • 批量插入血缘关系数据

  • 批量更新和回灌

  • 反复补跑任务

  • 大事务集中提交

那么即使只保留 3 天,binlog 增长也可能非常快。特别是在数据文件和 binlog 都落在同一块 PVC 上时,更容易一起把磁盘顶满。

而前面已经提到:

UAT 跑全量数据时,磁盘就是被干满的。

这其实已经说明风险是真实存在的,而不是假设。

所以这次扩容到 120G,是合理的防御性动作。当然,从长期看,仅靠扩盘不是根治,后续仍然建议结合以下几个方面一起控制风险:

  • binlog 保留策略

  • 上线窗口期间磁盘监控

  • 大批量任务执行节奏

  • 必要时分批写入


七、进入 MariaDB Pod 的一个细节:不是“集群方式”,而是“指定 galera 容器”

今天还有一个容易混淆的点,就是进入 Pod 时执行:

kubectl exec -it -n sso mariadb-ape-mariadb-si-ss-0 -- sh

执行时发现不太对,怀疑是不是要“通过 Galera 方式进入”。

实际上这里要区分两个概念。

1. Pod 内可能有多个容器

MariaDB Galera 这类 Pod,经常不止一个容器,可能包含:

  • galera

  • exporter / metrics

  • init 容器等

所以直接 kubectl exec 不指定容器时,可能进不到想要的数据库主容器。

正确做法通常是先看容器名:

kubectl get pod -n sso mariadb-ape-mariadb-si-ss-0 -o jsonpath='{.spec.containers[*].name}'

然后明确指定进入 galera 容器:

kubectl exec -it -n sso mariadb-ape-mariadb-si-ss-0 -c galera -- sh

2. 这不是“Galera 集群参数”,而是“指定 Pod 中的 galera 容器”

所以不是所谓的“加上 --galera 方式”,而是:

-c galera

这只是 kubectl exec 的容器选择参数。


八、Galera 集群下,哪些操作是“直接进 Pod”就行,哪些需要看集群状态

因为这个库是 MariaDB Galera 集群,所以排查时也要注意操作边界。

1. 看磁盘、看挂载、看文件大小

这类操作直接进具体 Pod 就行,因为每个 Pod 都有自己独立的 PVC。

例如:

kubectl exec -it -n sso mariadb-ape-mariadb-si-ss-0 -c galera -- df -h
kubectl exec -it -n sso mariadb-ape-mariadb-si-ss-0 -c galera -- df -h /var/lib/mysql

2. 看数据库参数

可以进入某个 Pod 后连本地数据库,查询参数:

  • log_bin

  • expire_logs_days

  • datadir

  • log_bin_basename

3. 看 Galera 集群状态

这时就要查 wsrep 相关状态变量,例如:

  • wsrep_cluster_size

  • wsrep_cluster_status

  • wsrep_local_state_comment

  • wsrep_ready

这些能帮助判断当前节点是否处于 Synced 状态、集群是否处于 Primary

所以:

  • 看磁盘:直接进具体 Pod

  • 看集群健康:通过 SQL 看 wsrep 状态

  • 高风险变更:不能只凭“随便进了一个 Pod”就操作


九、今天这轮问题的最终结论

今天这轮问题梳理下来,可以总结成几点。

1. K8S PVC 能不能扩,不是只看节点磁盘剩余

必须同时看:

  • StorageClass 是否支持扩容

  • 存储池是否还有可分配空间

  • 节点底层盘是否已扩

2. 节点底层盘扩完,不代表 PVC 立刻能扩

必须通过:

kubectl get lsc -A

确认可分配空间已经同步增加。

3. 对 MariaDB 这类数据库,容量规划不能只按“当前数据量”来算

还必须预留:

  • binlog 空间

  • 上线批量写入增长

  • 血缘数据初始化增长

  • 异常补跑带来的重复写入

4. 从 100G 提到 120G 是合理的

尤其是在有 UAT 跑满磁盘前车之鉴的情况下,这种预留是必要的。

5. Galera Pod 的进入方式要注意指定容器

通常应使用:

kubectl exec -it -n sso mariadb-ape-mariadb-si-ss-0 -c galera -- sh

而不是误以为需要什么特殊“集群方式”。


十、后续建议

结合今天的情况,后续可以补充几项长期措施。

1. 对 MariaDB PVC 做标准化容量基线

不要等到上线前才临时扩容,可以对数据库、ES、ClickHouse 这类有状态组件预先设定安全基线。

2. 对 binlog 增长建立监控

至少上线窗口期间,要能看到:

  • PVC 使用率

  • 数据目录增长

  • binlog 目录增长

  • 节点磁盘剩余空间

3. 对批量任务做节奏控制

如果血缘数据初始化量很大,建议分批执行,避免瞬时把 binlog 和数据盘一起压爆。

4. 对 UAT 跑满盘的问题做复盘

既然之前出现过,就值得把那次全量任务的写入量、binlog 增速、峰值空间占用做一次复盘,给后续容量规划提供依据。


十一、常用命令汇总

1. 查看 MariaDB Pod 和所在节点

kubectl get pod -n sso -owide | grep mariadb

2. 查看 PVC

kubectl get pvc -n sso | grep mariadb
kubectl describe pvc data-mariadb-ape-mariadb-si-ss-0 -n sso

3. 查看 StorageClass

kubectl get sc tceinf-csi-loopdevice -o yaml

4. 查看存储池

kubectl get lsc -A

5. 查看节点磁盘

df -TH

6. 进入 Galera 容器

kubectl exec -it -n sso mariadb-ape-mariadb-si-ss-0 -c galera -- sh

7. 查看容器内磁盘

kubectl exec -it -n sso mariadb-ape-mariadb-si-ss-0 -c galera -- df -h
kubectl exec -it -n sso mariadb-ape-mariadb-si-ss-0 -c galera -- df -h /var/lib/mysql

十二、总结

这次问题的核心并不在于 K8S 配置本身,而在于对数据库存储扩容链路的完整理解。真正影响 PVC 扩容成功与否的,不只是节点磁盘是否有剩余,而是要同时关注:

  • Pod 与 PVC 的绑定关系

  • StorageClass 是否支持扩容

  • CSI 存储池当前可分配容量

  • 节点底层盘是否真正扩到位

  • 数据库上线期间 binlog 与批量写入带来的空间压力

对于 MariaDB Galera 这类有状态数据库组件,扩容时更要把“底层盘、存储池、PVC、容器、数据库参数”作为一条完整链路去看,而不是只盯某一层。

本次从 100G 提升到 120G 的决策,是基于实际业务压力、历史 UAT 跑满盘经验以及 binlog 风险做出的更稳妥容量预留,整体判断是合理的。

本作品采用《CC 协议》,转载必须注明作者和本文链接
每天一点小知识,到那都是大佬,哈哈
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!
php @ 远程
文章
101
粉丝
16
喜欢
77
收藏
88
排名:522
访问:1.6 万
私信
所有博文
社区赞助商