订阅更新

内存模型与调优:OOM了先别加内存

Flink 实时计算 20 天 · 第 9 讲 进阶 约 5 分钟读完

内存划分 · JVM/堆外 · RocksDB内存 · 调优实战

本文目录
  1. 📋 面试题
  2. TaskManager内存全景
  3. 关键配置
  4. 三种OOM场景 + 解法
  5. 调优经验
  6. 面试加分提示
  7. 📌 总结

📋 面试题

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限制后解决。

刷题进度保存在当前浏览器