在 Kubernetes 中部署 MySQL,且资源限制为 2核4G,属于典型的“资源受限”场景。MySQL 默认配置通常假设拥有更多内存和 CPU,因此直接运行会导致性能瓶颈、OOM(内存溢出)或频繁 Swap。
以下是针对该场景的系统性优化方案,分为:K8s层面优化、MySQL配置优化、架构与使用建议三部分。
一、Kubernetes 层面优化
1. 合理的 Resource Requests & Limits
- Requests:确保至少分配足够的资源让 MySQL 启动并稳定运行。
resources: requests: memory: "2Gi" # 保证 MySQL 至少有 2GB 可用 cpu: "1000m" # 保证至少 1 个完整核心 limits: memory: "3.5Gi" # 留一点余量给 OS 和缓存,避免 OOM cpu: "2000m" # 允许突发使用全部 CPU - 为什么 limits < 4G?
Linux 内核本身需要 ~500MB–1GB 内存,Kubelet、容器运行时等也需要空间。若设limits: 4Gi,一旦 MySQL + OS 超过 4G,会被 OOM Kill。
2. 使用本地持久化存储(Local PV)而非网络存储
- 避免 NFS/云盘 I/O 延迟:如果可能,使用
local-pv或hostPath(仅限单节点测试),减少磁盘 I/O 开销。 - 若必须用云盘,选择高 IOPS 类型(如 AWS gp3、阿里云 ESSD PL1)。
3. 启用 CPU Manager Static Policy(可选高级优化)
# 在 kubelet 配置中启用
cpuManagerPolicy: static
reservedSystemCPUs: 1
这可以将一个 CPU 核心独占给 MySQL,减少上下文切换,提升实时性。
4. 设置 QoS 类为 Burstable 或 Guaranteed
- 推荐使用
Guaranteed(requests = limits),但受限于 4G 总内存,难以实现。 - 实际中常用
Burstable,并通过上述 requests/limits 控制。
二、MySQL 配置优化(my.cnf / my.ini)
这是最关键的部分!以下是适用于 2C4G 的典型 my.cnf 片段:
[mysqld]
# === 基础设置 ===
max_connections = 100 # 默认 151,降低以节省连接开销
innodb_buffer_pool_size = 1.5G # 核心优化:占物理内存的 30%-50%
innodb_log_file_size = 256M # 增大 redo log,提升写入性能
innodb_flush_method = O_DIRECT # 避免双重缓冲,减少 I/O 开销
innodb_flush_log_at_trx_commit = 1 # 保持 ACID,若可接受数据丢失风险可设为 2
sync_binlog = 1 # 保证 binlog 同步,若非主从可设为 0
# === InnoDB 其他关键参数 ===
innodb_buffer_pool_instances = 2 # 分块管理,减少锁竞争
innodb_thread_concurrency = 0 # 自动调整,适合多核
innodb_read_io_threads = 4
innodb_write_io_threads = 4
# === 查询缓存(MySQL 5.7+ 已移除,8.0 完全移除,勿设)===
# query_cache_type = 0
# query_cache_size = 0
# === 临时表与排序 ===
tmp_table_size = 64M
max_heap_table_size = 64M
sort_buffer_size = 2M
join_buffer_size = 2M
read_rnd_buffer_size = 1M
# === 日志 ===
slow_query_log = 1
long_query_time = 2
log_error_verbosity = 3
关键参数解释:
| 参数 | 推荐值 | 说明 |
|---|---|---|
innodb_buffer_pool_size |
1.5G~2G | 最重要参数,决定多少数据能缓存在内存中。设为 1.5G~2G,预留足够给 OS 和其他进程。 |
max_connections |
50~100 | 每个连接消耗 ~10MB 内存,100 连接 ≈ 1GB,需平衡。 |
innodb_log_file_size |
256M | 默认仅 48M,增大可减少 checkpoint 频率,提升写入吞吐。 |
tmp_table_size / max_heap_table_size |
64M | 防止大查询占用过多内存导致 OOM。 |
✅ 验证 Buffer Pool 命中率:
SHOW STATUS LIKE 'Innodb_buffer_pool_hit_ratio'; -- 或计算: SELECT (1 - Innodb_buffer_pool_reads / Innodb_buffer_pool_read_requests) * 100 AS hit_ratio;目标应 > 95%,若低于 90%,考虑增加
innodb_buffer_pool_size(需重启 K8s Pod)。
三、架构与使用建议
1. 避免在主库上做重型操作
- 禁止:全表扫描、未加索引的 JOIN、大批量 INSERT/UPDATE、复杂报表查询。
- 推荐:
- 所有查询必须有索引。
- 使用
EXPLAIN分析慢查询。 - 将只读报表查询路由到副本(即使只有一个实例,也可通过读写分离中间件模拟)。
2. 使用 ProxySQL 或 MyCAT 做连接池与路由
- MySQL 原生不支持连接复用,每个新连接都创建线程。
- 引入 ProxySQL 可实现:
- 连接池复用
- SQL 路由(写主读从)
- 查询缓存(ProxySQL 层)
- 屏蔽异常查询
3. 定期维护
- 每周执行
OPTIMIZE TABLE(针对 MyISAM 或碎片严重的 InnoDB 表)。 - 监控
SHOW ENGINE INNODB STATUSG查看死锁、锁等待。
4. 监控与告警
- 使用 Prometheus + Grafana 监控:
- QPS/TPS
- 连接数
- Buffer Pool 命中率
- 磁盘 I/O 延迟
- CPU 使用率
- 告警阈值:CPU > 80% 持续 5 分钟、Buffer Pool 命中率 < 90%、慢查询 > 10 条/分钟。
四、替代方案考虑(如果性能仍不足)
| 方案 | 适用场景 |
|---|---|
| 升级资源配置 | 若业务增长,最直接的方案是升到 4C8G |
| 使用 Percona Server for MySQL | 自带性能诊断工具,优化更好 |
| 迁移至 TiDB / CockroachDB | 分布式数据库,弹性扩缩容,适合未来扩展 |
| 使用云托管 MySQL(如 RDS) | 无需运维,自动优化,性价比高 |
总结 checklist
✅ K8s 设置合理 requests/limits(memory ≤ 3.5Gi)
✅ innodb_buffer_pool_size 设为 1.5G~2G
✅ 禁用 query cache(MySQL 8.0 已移除)
✅ 所有查询加索引,避免全表扫描
✅ 使用 ProxySQL 做连接池
✅ 开启 slow query log 并定期分析
✅ 监控 Buffer Pool 命中率 > 95%
通过以上优化,2C4G 的 MySQL 在中小规模应用(日均百万级 PV、并发 < 50)下可以稳定运行。若负载更高,建议尽早扩容或迁移至分布式数据库。
轻量云Cloud