内存模型与调优:OOM了先别加内存
内存划分 · JVM/堆外 · RocksDB内存 · 调优实战
📋 面试题
Flink的内存模型是怎样的?TaskManager的内存是怎么划分的?OOM了怎么排查?
💡 先想30秒,再往下看答案
TaskManager内存全景
TaskManager Total Memory
├── Framework Memory — Flink框架自身(默认128MB)
├── Task Memory — 用户代码使用(默认占40%)
│ ├── Heap — 堆内存(Java对象)
│ └── Off-Heap — 堆外内存
├── Managed Memory — Flink管理的内存(State/排序等,默认占40%)
│ └── RocksDB就用这块
├── Network Memory — 网络Buffer(默认占10%,min 64MB max 1GB)
└── JVM Metaspace + Overhead — JVM元空间和额外开销
面试一句话:TaskManager的内存分给了框架、用户代码、托管内存(State用)、网络Buffer四大块。
关键配置
# TaskManager总内存
taskmanager.memory.process.size: 4096m
# 或者只指定Flink管的部分(推荐)
taskmanager.memory.flink.size: 3072m
# 托管内存比例(RocksDB State用)
taskmanager.memory.managed.fraction: 0.4
# 网络Buffer
taskmanager.memory.network.fraction: 0.1
taskmanager.memory.network.min: 64mb
taskmanager.memory.network.max: 1gb
三种OOM场景 + 解法
场景一:Java Heap OOM
java.lang.OutOfMemoryError: Java heap space
原因:用户代码里创建了太多Java对象
- 窗口用ProcessWindowFunction攒了所有数据
- HashMap缓存太大
- 用了HashMapStateBackend但State太大
解法:
1. 换RocksDB State Backend(State不占堆内存)
2. ProcessWindowFunction改成AggregateFunction(增量不攒数据)
3. 加大Task Heap:taskmanager.memory.task.heap.size
场景二:Direct Memory OOM
java.lang.OutOfMemoryError: Direct buffer memory
原因:网络Buffer不够
- 并行度高+算子链长 → Network Buffer需求大
解法:
加大Network Memory比例或范围
taskmanager.memory.network.fraction: 0.15
场景三:RocksDB OOM(容器被Kill)
容器被杀(exit code 137)但没有Java OOM日志
原因:RocksDB使用Native内存超出容器限制
RocksDB的Block Cache + Write Buffer + Index等占用Native内存
解法:
1. 限制RocksDB内存:
state.backend.rocksdb.memory.managed: true # 用Managed Memory限制
2. 加大容器内存或JVM Overhead
我遇到过容器被Kill但没有OOM日志的情况。查了很久才发现是RocksDB的Native内存超了Kubernetes的limits。设置了managed=true让RocksDB只用Managed Memory那部分后解决。
调优经验
| 场景 | 建议配置 |
|---|---|
| State小(<1GB) | 4GB TM,HashMapBackend |
| State中等(1-10GB) | 8GB TM,RocksDB,managed 40% |
| State大(>10GB) | 16GB+ TM,RocksDB,managed 50%+ |
| 算子链长、并行度高 | Network调到15-20% |
面试加分提示
💡 讲内存模型+OOM排查经验:
「TaskManager内存分四块:框架、用户代码、托管内存(RocksDB用)、网络Buffer。
OOM分三种:Java Heap(换RocksDB或减少攒数据)、Direct Memory(加Network Buffer)、容器被Kill(RocksDB Native内存超限,设managed=true)。
我遇到过容器被Kill没OOM日志的情况,排查发现是RocksDB Native内存超了K8s limits。」
📌 总结
| 记忆点 | 内容 |
|---|---|
| 四大块 | 框架 + 用户代码 + 托管内存 + 网络Buffer |
| RocksDB用 | Managed Memory(托管内存) |
| Heap OOM | 换RocksDB / 增量聚合 / 加堆 |
| 容器被Kill | RocksDB Native内存超限,设managed=true |
| 调优原则 | State大→加Managed,算子多→加Network |
▶ 下一篇预告:DAY 10 Flink SQL实战
Wood聊大数据 | 9年大数据老兵,聊技术、聊职场、聊成长
小红书正文
Flink OOM了先别急着加内存,先搞清楚是哪块内存炸了。
TaskManager内存分四块:框架内存、用户代码堆内存、托管内存(RocksDB State用)、网络Buffer。
三种OOM:① Java Heap OOM——用户代码对象太多,换RocksDB或用增量聚合 ② Direct Memory——网络Buffer不够,加Network比例 ③ 容器被Kill无OOM日志——RocksDB Native内存超了容器限制。
我被第三种坑过。容器被K8s杀掉但没有任何Java错误日志。查了很久发现RocksDB的Native内存超了limits。设了managed=true限制后解决。