4. 资源分配策略:并行度设置、内存配置、CPU与网络资源的动态调整
资源分配这事儿,说白了就是「给多少、怎么给、何时给」。很多团队把并行度设死、内存写死,结果流量一波动,要么资源空转烧钱,要么任务 OOM 挂掉。我这些年踩过的坑,大多跟「静态配置」有关。
这一章,咱们就聊聊怎么让资源分配变得有弹性。核心就三个字:动态调。
4.1 并行度设置:从拍脑袋到按需分配
并行度是实时任务最直接的资源杠杆。设高了浪费 slot,设低了背压爆炸。
我的经验公式:
- Source 并行度:跟分区数对齐。Kafka 有 12 个分区,并行度就设 12。多了没用,少了拉不满。
- KeyBy 后的算子:看数据倾斜程度。我曾经遇到一个任务,某个 key 占了 70% 流量,并行度设再高也没用,得先做
rebalance或rescale。 - Sink 并行度:看下游写入能力。HBase 批次写 5000 条最稳,并行度 = 预估 TPS / 5000。
核心原则:并行度不是越大越好。每增加一个并行度,网络 shuffle 和状态后端压力都会上升。我习惯用「每核心每秒处理 5000 条事件」作为基准线,再根据实际压测微调。
4.2 内存配置:Heap 与 Off-Heap 的博弈
内存是实时任务最容易出问题的地方。Flink 的 TM 内存分三块:JVM Heap、Managed Memory、Network Buffer。
| 内存区域 | 用途 | 我常用的比例 |
|---|---|---|
| JVM Heap | 用户代码、状态后端(RocksDB 除外) | 40% |
| Managed Memory | 排序、缓存、RocksDB 块缓存 | 40% |
| Network Buffer | 网络数据交换、反压缓冲区 | 20% |
避坑指南:
- 我曾经把 Managed Memory 设得太小,导致 RocksDB 频繁刷盘,读写延迟飙升到 200ms。后来调到 40%,延迟降到 20ms。
- Network Buffer 不足时,背压会直接导致 Checkpoint 超时。我建议至少留 20%,如果网络抖动频繁,可以提到 25%。
注意:不要给 JVM Heap 留太多。GC 停顿是实时任务的大敌。我见过有人给 Heap 分了 80%,结果 Full GC 一次 5 秒,任务直接重启。留 40% 给 Managed Memory,让 RocksDB 自己管理内存,反而更稳。
4.3 CPU 与网络资源的动态调整
静态配置最大的问题,就是扛不住流量毛刺。你想想看,双十一流量是平时的 10 倍,但资源不能按峰值配,否则平时浪费太多。
我的做法:
- CPU 弹性:使用 Kubernetes 的
Vertical Pod Autoscaler,根据 CPU 使用率动态调整 request 和 limit。阈值我设 70%,超过就扩容。 - 网络带宽:在 Flink 层面开启
auto-watermark-interval和backpressure-monitoring。当背压超过 0.8 时,自动降低 source 的消费速率,或者临时增加 sink 并行度。 - 动态并行度:Flink 1.15+ 支持
reactive mode,可以根据 slot 数量自动调整并行度。我试过,效果不错,但要注意状态重分布的开销。
小技巧:网络资源调整时,别只盯着带宽。TCP 连接数、连接池大小、序列化方式,这些细节往往才是瓶颈。我曾经把一个 JSON 序列化改成 Protobuf,网络开销直接降了 60%。
4.4 动态调整的落地框架
光有策略不行,得能落地。我画了一张图,把整个动态调整的闭环串起来:
这个闭环的核心是「监控 → 分析 → 决策 → 执行 → 评估」。我一般在决策引擎里加一个冷却期,比如调整后至少等 2 分钟再触发下一次调整,防止震荡。
4.5 实战案例:一次双十一的资源配置
去年双十一,我负责的一个实时风控任务,平时 TPS 是 5 万,峰值预估 50 万。如果按峰值配资源,需要 200 个 slot,平时浪费 75%。
我的方案:
- 平时:40 个 slot,并行度 8,内存 4GB/TM。
- 动态策略:当背压超过 0.6 持续 30 秒,自动扩容到 80 个 slot,并行度翻倍,内存升到 8GB/TM。
- 回缩策略:背压低于 0.2 持续 5 分钟,逐步回缩到 40 个 slot。
结果:峰值时资源刚好够用,平时成本降低了 60%。
关键点:动态调整不是无限弹性。我设了上限 80 个 slot,超过这个数说明架构有问题,得从源头优化,而不是硬扛。
4.6 避坑清单
- 不要频繁调整并行度:每次调整都会触发状态重分布,频繁操作会导致任务不稳定。我建议调整间隔至少 5 分钟。
- 内存不要设成整数:比如 4GB,JVM 会分配 4GB + 元空间,容易超限。我习惯设 3.5GB 或 4.2GB,留点余量。
- 网络 buffer 不要用默认值:默认 64MB 太小,高吞吐场景建议 256MB 起步。
- 动态调整要加熔断:如果连续 3 次调整后指标反而恶化,立即回滚到上一版配置,并告警。