Google Cloud Dataproc Spark作业仅主节点运行,Worker节点利用率极低的原因及优化
碰到Worker节点完全躺平、只有主节点在干活的情况,我之前也踩过不少坑,下面给你拆解下最常见的原因和对应的解决办法:
1. 作业不小心跑在了单线程/本地模式
如果你的代码里硬编码了local[*]或者spark://localhost这类配置,Spark会直接在Driver(也就是主节点)上处理所有任务,根本不会用到Worker节点。另外如果你的数据集太小,Spark可能觉得没必要分布式计算,直接在Driver端完成了。
解决办法:
- 检查代码中的SparkSession初始化部分,确保没有指定
master为local开头的地址,Dataproc集群会自动帮你配置集群模式的master地址; - 用稍大一点的测试数据触发分布式计算逻辑,比如把数据集扩大到至少能拆分出多个task的量级。
2. 资源配置不合理,没给Worker分配足够的任务
你提交命令里指定了spark.executor.cores=10,但如果没设置spark.executor.instances,Spark可能只会在少数Worker上启动executor,甚至只在主节点启动(虽然Dataproc默认会避免,但配置不对也可能出现)。另外如果Driver占用了过多资源,也会挤压Worker的可用资源。
解决办法:
- 在提交命令里加上
spark.executor.instances=N,N根据你的Worker节点数和每个Worker的核心数来定,比如你有3个Worker,每个Worker有16核,那可以设spark.executor.instances=6,每个Worker跑2个executor,每个executor用8核; - 合理设置Driver资源,比如
spark.driver.cores=2、spark.driver.memory=4g,不要让Driver抢占太多集群资源; - 可以用
gcloud dataproc clusters describe your-cluster-name查看集群的硬件配置,再对应调整executor参数。
3. 数据分区数太少,task数量跟不上集群核心数
Spark的task是分配到executor上运行的,如果你的RDD/DataFrame分区数远小于集群的总核心数,那么只有少量task在跑,大部分Worker的核心都会闲置。比如集群总共有30个核心,但你的数据只有3个分区,那最多只能跑3个task,剩下27个核心都没事做。
解决办法:
- 在代码里用
df.rdd.getNumPartitions()查看当前分区数,建议把分区数调整为集群总核心数的2-3倍; - 用
df.repartition(new_num)或者rdd.repartition(new_num)重新分区,如果是大数据量,也可以在读取数据时就指定分区数(比如读Hive表时配合动态分区配置); - 如果存在数据倾斜(某个分区数据量特别大),要单独处理,比如给热点键加盐拆分、过滤异常数据等,避免单个task占用大量资源导致其他task无法调度。
4. 作业提交命令有遗漏或错误
你提交命令里的--clu...没写完,要确认是不是没指定目标集群?如果没加--cluster your-cluster-name,可能作业提交到了默认集群或者本地(虽然概率低,但也有可能)。另外有没有误加--master local这类参数?
解决办法:
- 补全提交命令,确保指定了正确的集群:
gcloud dataproc jobs submit spark --properties spark.executor.cores=10,spark.executor.instances=6 --cluster your-cluster-name --class com.your.package.YourJob --jars your-job.jar - 不要手动指定
--master参数,Dataproc会自动配置集群的master地址。
5. Worker节点状态异常或集群资源被抢占
有时候不是作业的问题,而是Worker节点本身出问题了,比如节点挂了、处于维护状态,或者集群被其他高优先级作业占用了资源。
解决办法:
- 登录Dataproc控制台,查看Worker节点的状态,确保所有Worker都是
RUNNING状态; - 查看集群的资源监控面板,确认Worker的CPU、内存有没有被其他作业占用;
- 如果是共享集群,可以调整作业的优先级,或者等待其他作业完成后再测试。
内容的提问来源于stack exchange,提问作者Vadapalli Adithya

