数据库为什么不适合跑在容器
这是一个非常“值钱”的问题。
不是“能不能”,而是 “为什么在工程上不适合”。
用 硬件 / NUMA / cgroups / Linux 内核 / 容器模型 梳理。
数据库不是“不能”跑在容器里,而是:在大多数生产场景下,容器的抽象层与数据库的性能模型是“反向的”。
换句话说:
- 数据库追求确定性
- 容器追求弹性与共享
两者天生冲突。
数据库(MySQL / PostgreSQL / Oracle / Redis)真正吃的不是“CPU 核数”,而是:
- 内存确定性
- IO 延迟稳定性
- NUMA 本地性
- fsync 语义可靠
- 调度可预期
以 MySQL / PostgreSQL 为例:
- Buffer Pool / Shared Buffers
- 长时间常驻
- 自己管理淘汰
📌 数据库不希望内核插手
memory.max
memory.high
问题来了:
| 行为 | 后果 |
|---|---|
| memory.high | 频繁回收 |
| memory.max | 直接 OOM kill |
| swap | 延迟爆炸 |
数据库最怕:
- 被 OOM kill
- 被强制回收 page cache
📌 数据库宁可慢,也不接受“突然死”
容器里 MySQL 看似稳定,高峰期突然被 kill,主从全挂。
- CPU ↔ 内存
- 锁、latch、buffer
裸机:
numactl --cpunodebind=0 --membind=0 mysqld
- 默认 不感知 NUMA
- cgroups 不自动绑 mems
- K8S NUMA 需要高级配置
📌 跨 NUMA = 延迟抖动 + QPS 不稳定
- vNUMA
- Guest OS 感知 NUMA
- 数据库可控
DB -> FS -> Block -> Disk
2️⃣ 容器 IO
DB -> overlay2 -> VFS -> Block -> Disk
overlay2 的问题:
- copy-on-write
- metadata 放大
- fsync 成本更高
📌 数据库是 fsync 密集型应用
- shared storage
- IO 抢占
- noisy neighbor
- 长时间运行
- cache 热
- 锁敏感
- CPU quota
- CFS 调度
- throttling
cpu.max=100000 100000
📌 throttling = TPS 抖动
- 无状态
- 可重建
- 快速销毁
- 强状态
- 数据一致性
- 故障恢复优先
📌 数据库重启 ≠ 应用重启
因为:
| 场景 | 看起来没问题 |
|---|---|
| 测试环境 | 压力不够 |
| 小规模 | NUMA 未显现 |
| SSD | 掩盖 IO 问题 |
| 单节点 | 没有争抢 |
📌 一上生产就暴雷
因为:
| 特性 | Redis |
|---|---|
| 内存模型 | 简单 |
| IO | 少 |
| NUMA 敏感 | 低 |
| 恢复 | 快 |
📌 不是所有“数据库”一样
勉强可接受的条件
- 专用节点
- 独占 CPU / 内存
- 禁用 swap
- HugePages
- local PV
- static pod
📌 此时已经 不像容器,更像轻量 VM
| 场景 | 推荐 |
|---|---|
| 核心 OLTP | 裸机 |
| 金融 / 交易 | 裸机 |
| 云数据库 | VM |
| 辅助库 / 测试 | 容器 |
| Redis / Kafka | 视规模 |
容器的本质是“共享”,而数据库的本质是“独占”。
只要记住这句话,在架构评审里就不会输。