innodb_buffer_pool_size必须与K8S容器memory limits严格对齐,推荐设为limits的50%–70%,且为innodb_buffer_pool_instances整数倍;需禁用buffer pool dump/load、使用PV+fsGroup、O_DIRECT刷盘,并分层管控IO。

容器内存限制与innodb_buffer_pool_size必须严格对齐
MySQL在K8S里OOM Killed,往往不是因为RSS爆了,而是innodb_buffer_pool_size设得太大、又没和容器resources.limits.memory协同。Linux允许malloc成功但不立即分配物理页,等InnoDB真去touch那几G内存时,cgroup才触发OOM Killer——此时SHOW ENGINE INNODB STATUS里Innodb_buffer_pool_wait_free可能已经持续非零,Buffer pool hit rate跌破95%。
安全配法是:
-
innodb_buffer_pool_size= 容器limits.memory× 0.5 ~ 0.7,且必须是innodb_buffer_pool_instances的整数倍(推荐设为K8S Pod的CPU limit核数) - 务必同时配置
resources.requests.memory和resources.limits.memory,避免节点调度失准 - 禁用
innodb_buffer_pool_dump_at_shutdown和innodb_buffer_pool_load_at_startup:K8S Pod重启太快,预热反而阻塞连接池初始化
挂载存储必须用emptyDir或PersistentVolume,禁用hostPath默认权限
K8S里用hostPath挂载宿主机目录,MySQL启动时会反复执行chown——因为容器内mysql用户UID和宿主机文件UID不匹配,导致初始化卡住或日志报Permission denied。更隐蔽的问题是:hostPath默认挂载选项隐含:z或:Z(SELinux标签),强制同步写入,IO吞吐直接腰斩。
正确做法:
- 生产环境一律用
PersistentVolume+storageClassName指向SSD类存储(如AWS gp3、阿里云ESSD) - 若临时测试用
emptyDir,确保emptyDir.medium: Memory仅用于tmp_table_size小场景,不可存数据文件 - 所有PV必须显式设置
fsGroup: 1001(对应MySQL容器内gid),避免启动时chown
innodb_flush_method在K8S里不能拍脑袋设
这个参数决定InnoDB如何刷redo log和数据页,选错会导致双重缓存或写放大。K8S环境尤其敏感:底层可能是云盘+虚拟化层+文件系统三层缓存叠加。
判断依据看存储硬件特性:
- 用NVMe/本地SSD且无BBU/Flash-Backed Write Cache → 必须设
innodb_flush_method = O_DIRECT,绕过OS page cache - 用带BBU的物理RAID卡(少见于K8S)→ 可设
O_DSYNC - 云盘(如AWS gp3、阿里云ESSD)→ 实测
O_DIRECT通常更稳;default或空值大概率引发Innodb_os_log_written增速远超Innodb_dblwr_writes,说明日志被OS缓存又落盘,双写放大
验证方法:压测时跑iostat -x 1,看%util是否持续>80%,await是否>20ms;再查SHOW GLOBAL STATUS LIKE 'Innodb_os_log_written'和Innodb_dblwr_writes比值,明显偏离1:1就是缓存策略出问题。
IO限速别只靠resources.limits.ephemeral-storage
K8S的ephemeral-storage只管磁盘空间,不管IOPS或吞吐。MySQL写redo log、刷脏页、排序溢出临时表,都可能突发打满IO带宽,拖垮同节点其他Pod。
真正有效的IO隔离要分两层:
- 节点层:用
RuntimeClass绑定containerd的blkio.weight或blkio.throttle.write_iops_device(需提前在/etc/containerd/config.toml启用blkio cgroup v1/v2) - MySQL层:根据实际磁盘能力设
innodb_io_capacity(SSD设2000~4000)、innodb_io_capacity_max(设为1.5~2倍),防止后台线程刷脏页失控 - 绝对不要依赖
sync_binlog=1+innodb_flush_log_at_trx_commit=1组合做“强一致”——它会让每事务两次fsync,在K8S共享IO路径下极易毛刺;业务能容忍1秒丢失就改用=2+sync_binlog=1000
最易被忽略的是:K8S里emptyDir和hostPath的IO性能完全取决于节点磁盘,但监控指标(如container_fs_usage_bytes)根本看不出IO饱和。必须进Pod执行iostat -x 1,盯住await和%util,否则调优全是盲操作。


















