home:concepts:stackable_resource_requests.adoc
If no resources are configured explicitly, the operator uses the following defaults for SparkApplication
resources:
job:
config:
resources:
cpu:
min: '100m'
max: "400m"
memory:
limit: '512Mi'
driver:
config:
resources:
cpu:
min: '250m'
max: "1"
memory:
limit: '1Gi'
executor:
config:
resources:
cpu:
min: '250m'
max: "1"
memory:
limit: '1Gi'
For `SparkHistoryServer`s the following defaults are used:
nodes:
resources:
cpu:
min: '250m'
max: "1"
memory:
limit: '512Mi'
Warning
|
The default values are most likely not sufficient to run a proper cluster in production. Please adapt according to your requirements. For more details regarding Kubernetes CPU limits see: Assign CPU Resources to Containers and Pods. |
Spark allocates a default amount of non-heap memory based on the type of job (JVM or non-JVM). This is taken into account when defining memory settings based exclusively on the resource limits, so that the "declared" value is the actual total value (i.e. including memory overhead). This may result in minor deviations from the stated resource value due to rounding differences.
Note
|
It is possible to define Spark resources either directly by setting configuration properties listed under sparkConf , or by using resource limits. If both are used, then sparkConf properties take precedence. It is recommended for the sake of clarity to use either one or the other. See below for examples.
|
To illustrate resource configuration consider the use-case where resources are defined using CRD fields (which are then parsed internally to be passed to Spark as spark.conf settings).
CPU request and limit will be used as defined in the custom resource resulting in the following:
CRD | spark.kubernetes.{driver/executor} cores | spark.{driver/executor} cores (rounded up) |
---|---|---|
1800m |
1800m |
2 |
100m |
100m |
1 |
1.5 |
1.5 |
2 |
2 |
2 |
2 |
spark.kubernetes.{driver,executor}.{request|limit}.cores
determine the actual pod CPU request and are taken directly from the manifest as defined by the user.
spark.{driver|executor}.cores}
are set to the rounded(-up) value of the manifest settings.
Task parallelism (the number of tasks an executor can run concurrently), is determined by spark.executor.cores
.
Memory values are not rounded as is the case with CPU. Values for spark.{driver|executor}.memory}
- this is the amount of memory to use for the driver process (i.e. where SparkContext is initialized) and executor processes respectively - are passed to Spark in such as a way that the overheads added by Spark are already implicitly declared: this overhead will be applied using a factor of 0.1 (JVM jobs) or 0.4 (non-JVM jobs), being not less than 384MB, the minimum overhead applied by Spark. Once the overhead is applied, the effective value is the one defined by the user. This keeps the values transparent: what is defined in the CRD is what is actually provisioned for the process.
An alternative is to do define the spark.conf settings explicitly and then let Spark apply the overheads to those values.
A SparkApplication defines the following resources:
...
job:
config:
resources:
cpu:
min: 250m # (1)
max: 500m # (2)
memory:
limit: 512Mi # (3)
driver:
config:
resources:
cpu:
min: 200m # (4)
max: 1200m # (5)
memory:
limit: 1024Mi # (6)
executor:
config:
resources:
cpu:
min: 250m # (7)
max: 1000m # (8)
memory:
limit: 1024Mi # (9)
...
This will result in the following Pod definitions:
For the job:
spec:
containers:
- name: spark-submit
resources:
limits:
cpu: 500m # (2)
memory: 512Mi # (3)
requests:
cpu: 250m # (1)
memory: 512Mi # (3)
For the driver:
spec:
containers:
- name: spark
resources:
limits:
cpu: "2" # (5)
memory: 1Gi # (6)
requests:
cpu: "1" # (4)
memory: 1Gi # (6)
For each executor:
spec:
containers:
- name: spark
limits:
cpu: "1" # (7)
memory: 1Gi # (9)
requests:
cpu: "1" # (8)
memory: 1Gi # (9)
-
CPU request (unchanged as this is the Job pod)
-
CPU limit (unchanged as this is the Job pod)
-
Memory is assigned to both request and limit values
-
CPU request, rounded up from
200m
to1
-
CPU limit, rounded up from
1200m
to2
-
Memory after reduction and re-addition of Spark overhead (so the declared value matches what is provisioned)
-
CPU request, rounded up from
250m
to1
-
CPU limit, unchanged after rounding:
1000m
to1
-
Memory after reduction and re-addition of Spark overhead (so the declared value matches what is provisioned)
The spark.conf values derived from the above can be inspected in the job Pod definition:
...
--conf "spark.driver.cores=1"
--conf "spark.driver.memory=640m"
--conf "spark.executor.cores=1"
--conf "spark.executor.memory=640m"
--conf "spark.kubernetes.driver.limit.cores=1"
--conf "spark.kubernetes.driver.request.cores=2"
--conf "spark.kubernetes.executor.limit.cores=1"
--conf "spark.kubernetes.executor.request.cores=1"
--conf "spark.kubernetes.memoryOverheadFactor=0.0"
...
These correspond to the resources listed above for the job/driver/executor Pods, with the exception of spark.{driver|executor}.memory
where indeed the Spark internal overhead of 384MB has been deducted from 1024MB.