Dataproc configures memory settings to fit 2 Spark executors per machine, so each container should be expected to be half the capacity of each NodeManager.
You can optionally override spark.executor.memory
and maybe spark.yarn.executor.memoryOverhead
along with spark.executor.cores
to change how you want to pack executors onto each machine. spark.executor.cores
will default to half the machine's cores, since half the machine's memory is given to each executor. In your case this means each Spark executor tries to run 8 tasks in parallel in the same process.
You can effectively increase memory-per-task by reducing executor cores but keeping everything else the same, for example spark.executor.cores=6
will increase per-task memory by 33% even if you leave everything else the same. These can be specified at job-submission time:
gcloud dataproc jobs submit spark --properties spark.executor.cores=6