Spark / Flink 跑在 Kubernetes 上真的更香吗聊聊那些没人提前告诉你的性能坑作者 | Echo_Wish这两年大数据圈有个非常明显的趋势Kubernetes 正在逐渐成为新的大数据平台底座。以前我们跑 Spark、Flink大多数是在YARN上。现在很多公司开始迁移Spark on K8sFlink on K8sAirflow / Argo 调度对接对象存储 Lakehouse架构听起来非常优雅Kubernetes │ ├── Spark Job ├── Flink Streaming Job ├── Kafka ├── Trino └── ML Training一套平台统管批处理 流处理 AI。但现实往往是架构很云原生性能却很“离谱”。很多团队在迁移到 Kubernetes 后都会踩到一些非常隐蔽的性能坑。今天咱们就用实战 代码聊聊Spark / Flink 跑在 Kubernetes 上最容易踩的几个坑。一、Spark on Kubernetes资源配置不对性能直接腰斩很多人刚把 Spark 迁移到 Kubernetes 时最常见的问题就是CPU、内存配置看起来没问题但任务就是慢。先看一个常见的提交命令spark-submit\--masterk8s://https://k8s-api:6443\--deploy-mode cluster\--namespark-etl-job\--classcom.echo.etl.Main\--confspark.executor.instances10\--confspark.executor.memory4g\--confspark.executor.cores2\--confspark.kubernetes.container.imageecho/spark:3.5\local:///opt/spark/app.jar看起来很正常对吧但这里有一个隐藏问题executor.memory ≠ pod memory在 Kubernetes 里Pod 还需要额外内存JVM overheadshuffle bufferoff-heap memory如果你只配置spark.executor.memory4gKubernetes Pod 实际可能只给4GB limit。结果就是OOM Kill。正确方式应该这样--confspark.executor.memory4g\--confspark.executor.memoryOverhead1024同时在 K8s 里设置pod memory ≈ executor.memory overhead否则就会出现一个经典现象Spark UI 没报错但 Pod 一直被 Kubernetes 杀掉重启。很多团队排查半天日志才发现是cgroup memory limit。二、Shuffle 在 Kubernetes 上容易“炸盘”Spark 最大的性能瓶颈之一就是Shuffle。在 YARN 时代NodeManager 本地磁盘而在 KubernetesPod 生命周期 临时很多团队最开始会这么配置volumeMounts:-mountPath:/tmpname:spark-local但如果底层是emptyDir问题就来了emptyDir 默认在容器文件系统这意味着Shuffle 数据会写进容器层。后果IO 非常慢容器层膨胀Node 磁盘爆满正确姿势是volumes:-name:spark-localhostPath:path:/data/spark或者local SSDSpark 配置--confspark.local.dir/data/spark否则 Shuffle 稍微大一点性能直接掉 50% 都不奇怪。三、Flink on KubernetesCheckpoint 是个大坑Flink 跑在 Kubernetes 最大的坑之一就是Checkpoint 存储。很多人一开始这么写state.backend:filesystemstate.checkpoints.dir:file:///flink/checkpoints看起来 OK。但问题是Pod 重启 本地状态丢失所以生产环境一定要用S3OSSHDFSMinIO例如state.backend:rocksdbstate.checkpoints.dir:s3://flink-checkpoints/state.savepoints.dir:s3://flink-savepoints/在 Kubernetes 上对象存储是最稳的。否则一旦Pod reschedule状态就没了。四、Flink Slot 和 Kubernetes Pod 不匹配很多团队在 Kubernetes 上跑 Flink 时还有一个经典问题资源利用率非常低。例如TaskManager CPU: 8 Memory: 16GB slots: 1结果7核 CPU 全部闲置正确配置应该让slots ≈ CPU cores例如taskmanager.numberOfTaskSlots:8这样 Flink 才能并行执行 Task。否则你会看到CPU 使用率只有 10%但任务却跑得很慢。五、Kubernetes 调度延迟流处理的隐形杀手Spark 批处理影响不大。但 Flink流处理就不一样了。Kubernetes 调度流程JobManager ↓ K8s API ↓ Scheduler ↓ Node ↓ Container Runtime如果集群很忙Pod Pending 30s那 Flink 扩容就会非常慢。这时候需要Cluster Autoscaler Pod Priority Node Pool例如priorityClassName:flink-high-priority这样关键流任务不会被普通任务挤掉。六、Spark Driver 是单点Spark on Kubernetes 还有一个经常被忽略的问题Driver Pod 单点如果 Driver 挂了整个 Job 直接失败解决方案checkpoint retry例如--confspark.task.maxFailures8--confspark.stage.maxConsecutiveAttempts5或者使用Spark Operator提交 JobapiVersion:sparkoperator.k8s.io/v1beta2kind:SparkApplicationmetadata:name:spark-pispec:type:Scalamode:clusterimage:spark:3.5mainClass:org.apache.spark.examples.SparkPidriver:cores:1memory:2gexecutor:cores:2instances:5memory:4gOperator 会自动重试管理生命周期监控状态七、我对 “大数据 Kubernetes” 的一点真实看法很多公司现在流行一句话“全部云原生。”但我这些年看到的现实是不是所有大数据任务都适合 Kubernetes。适合 K8s 的场景AI 训练Spark ETLAd-hoc 分析多租户但不一定适合的超大 ShufflePB 级离线计算超低延迟流处理有时候Spark on YARN 反而更稳定所以技术选型一定要想清楚我们到底是要“架构好看”还是“系统稳定”这其实是两个完全不同的问题。结尾如果你准备在 Kubernetes 上跑 Spark / Flink我非常建议你提前想清楚三件事第一存储怎么做Shuffle Checkpoint State第二资源如何匹配CPU Memory Slot Pod第三调度延迟是否可接受Batch vs StreamingKubernetes 确实是未来的大势但它不是银弹。很多时候架构越先进踩坑越多。但换个角度想这也是技术最有意思的地方。我们做工程的其实就是不断在这些坑里摔一跤 → 总结经验 → 再爬起来。慢慢的你就会发现原来那些“性能玄学”背后其实都是系统原理。