Skip to content

Commit 71a5e5b

Browse files
ahmadelyousseffacebook-github-bot
authored andcommitted
Updating Spark JVM to Graal VM and to 4.0-spark-hadoop (#210)
Summary: Spark now runs with GraalVM Java 17 and Spark is updated to 4.0-hadoop Reviewed By: excelle08 Differential Revision: D81242805
1 parent 31c9bbb commit 71a5e5b

7 files changed

Lines changed: 177 additions & 55 deletions

File tree

packages/spark_standalone/README.md

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ to run your systems exclusively with IPv6. If your systems only support IPv4,
148148
we now provide a flag to enable support for it.
149149

150150
* `JAVA_HOME`: You may need to manually set the environment variable `JAVA_HOME`
151-
to be the path of the JDK if Spark benchmark fails.
151+
to be the path of the JDK: /usr/lib/jvm/graalvm-jdk-17.0.12+8.1/ if Spark benchmark fails.
152152

153153
## Also Note
154154

@@ -398,7 +398,7 @@ please remove the data from previous runs so that SparkBench can rebuild databas
398398
399399
```bash
400400
rm -rf /flash23/warehouse
401-
rm -rf <benchpressPath>/benchmarks/spark_standalone/spark-2.4.5-bin-hadoop2.7/metastore_db
401+
rm -rf <benchpressPath>/benchmarks/spark_standalone/spark-4.0.0-bin-hadoop3/metastore_db
402402
```
403403

404404
4. Create the `/flash23` folder. Copy `bpc_t93586_s2_synthetic_5GB`
@@ -408,7 +408,7 @@ Note that SparkBench mini does not require the high I/O throughput
408408

409409
5. Run `spark_standalone_remote_mini` job on a real machine.
410410
This will create data in `/flash23/warehouse`
411-
and `<benchpressPath>/benchmarks/spark_standalone/spark-2.4.5-bin-hadoop2.7/metastore_db`.
411+
and `<benchpressPath>/benchmarks/spark_standalone/spark-4.0.0-bin-hadoop3/metastore_db`.
412412
Create a backup of these two folders. By default, this job uses the 5GB dataset.
413413
If you want to use the 1GB dataset, run the job with specifying the
414414
`dataset_name` parameter like this:
@@ -425,12 +425,12 @@ with the same commands and options.
425425
Building database takes a considerable amount of time, so it's advisable to consider
426426
using the same set of storage nodes and NVMe drives when running SparkBench on another
427427
compute node server. If you choose to reuse the Spark database in `/flash23/warehouse`,
428-
please also make sure to copy the folder `metastore_db` under `benchmarks/spark_standalone/spark-2.4.5-bin-hadoop2.7`
428+
please also make sure to copy the folder `metastore_db` under `benchmarks/spark_standalone/spark-4.0.0-bin-hadoop3`
429429
to the new machine's same location, for example:
430430

431431
```
432432
# Under the DCPerf folder
433-
rsync -a benchmarks/spark_standalone/spark-2.4.5-bin-hadoop2.7/metastore_db root@<target-hostname>:~/DCPerf/benchmarks/spark_standalone/spark-2.4.5-bin-hadoop2.7/
433+
rsync -a benchmarks/spark_standalone/spark-4.0.0-bin-hadoop3/metastore_db root@<target-hostname>:~/DCPerf/benchmarks/spark_standalone/spark-4.0.0-bin-hadoop3/
434434
```
435435

436436
If you do not copy over the `metastore_db` folder, you will see errors like the following
@@ -454,10 +454,10 @@ the better, Spark benchmark also reports `queries_per_hour` which is 3600 divide
454454
by the execution time. `score` denotes the relative Sparkbench performance to
455455
DCPerf's baseline.
456456
For CPU performance analysis, it is
457-
also helpful to use `execution_time_test_93586-stage-2.0` because Stage 2.0
457+
also helpful to use `execution_time_test_93586-stage-4.0` because Stage 4.0
458458
is a compute intensive phase and is much less influenced by I/O. We expect the
459459
average CPU utilization during the entire benchmark to be around 55~75%. The
460-
CPU utilization during Stage 2.0 full batch period could reach nearly 100%.
460+
CPU utilization during Stage 4.0 period could reach nearly 100%.
461461

462462
```
463463
{
@@ -493,8 +493,7 @@ CPU utilization during Stage 2.0 full batch period could reach nearly 100%.
493493
"execution_time_test_93586": 288.3,
494494
"execution_time_test_93586-stage-0.0": 10.0,
495495
"execution_time_test_93586-stage-1.0": 67.0,
496-
"execution_time_test_93586-stage-2.0": 205.0,
497-
"execution_time_test_93586-stage-2.0-fullbatch": 181.0,
496+
"execution_time_test_93586-stage-4.0": 205.0,
498497
"queries_per_hour": 12.4869927159,
499498
"score": 3.121748179,
500499
"worker_cores": 172,
@@ -506,7 +505,7 @@ CPU utilization during Stage 2.0 full batch period could reach nearly 100%.
506505
```
507506

508507
In the reported metrics, `execution_time_test_93586` is the overall execution time,
509-
`execution_time_test_93586-stage-2.0` is the execution time of Spark's
508+
`execution_time_test_93586-stage-4.0` is the execution time of Spark's
510509
compute-intensive phase.
511510

512511
Spark benchmark will also put its runtime logs into `benchmark_metrics_<run_id>/work` folder.

packages/spark_standalone/install_spark_standalone.sh

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,25 @@ SPARK_PKG_ROOT="$(dirname "$(readlink -f "$0")")"
1111
TEMPLATES_DIR="${SPARK_PKG_ROOT}/templates"
1212
LINUX_DIST_ID="$(awk -F "=" '/^ID=/ {print $2}' /etc/os-release | tr -d '"')"
1313

14+
# Detect architecture
15+
ARCH=$(uname -m)
16+
GRAALVM_ARCH="x64"
17+
if [ "$ARCH" = "aarch64" ]; then
18+
GRAALVM_ARCH="aarch64"
19+
fi
20+
1421
# Install system dependencies
1522
if [ "$LINUX_DIST_ID" = "ubuntu" ]; then
16-
apt install -y openjdk-8-jdk fio
17-
apt install -y git-lfs
23+
apt install -y git-lfs fio
24+
wget https://download.oracle.com/graalvm/17/archive/graalvm-jdk-17.0.12_linux-${GRAALVM_ARCH}_bin.tar.gz
25+
mkdir -p /usr/lib/jvm/
26+
tar -xzf graalvm-jdk-17.0.12_linux-${GRAALVM_ARCH}_bin.tar.gz -C /usr/lib/jvm/
27+
1828
elif [ "$LINUX_DIST_ID" = "centos" ]; then
19-
dnf install -y java-1.8.0-openjdk fio
20-
dnf install -y git-lfs
29+
dnf install -y git-lfs fio
30+
wget https://download.oracle.com/graalvm/17/archive/graalvm-jdk-17.0.12_linux-${GRAALVM_ARCH}_bin.tar.gz
31+
mkdir -p /usr/lib/jvm/
32+
tar -xzf graalvm-jdk-17.0.12_linux-${GRAALVM_ARCH}_bin.tar.gz -C /usr/lib/jvm/
2133
fi
2234

2335
# copy over directory
@@ -30,10 +42,10 @@ fi
3042

3143
# download spark
3244
pushd "${OUT}" || exit 1
33-
if [ ! -f spark-2.4.5-bin-hadoop2.7.tgz ]; then
34-
wget https://archive.apache.org/dist/spark/spark-2.4.5/spark-2.4.5-bin-hadoop2.7.tgz
45+
if [ ! -f spark-4.0.0-bin-hadoop3.tgz ]; then
46+
wget https://archive.apache.org/dist/spark/spark-4.0.0/spark-4.0.0-bin-hadoop3.tgz
3547
fi
36-
tar xzf spark-2.4.5-bin-hadoop2.7.tgz
48+
tar xzf spark-4.0.0-bin-hadoop3.tgz
3749
popd || exit 1
3850

3951
# create sub directories

packages/spark_standalone/templates/proj_root/scripts/run_perf_common.py

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def run_spark_sql(
5555
if database:
5656
cmd.extend(["--database", database])
5757
log_file = sql_file.replace(".sql", ".log")
58-
env = {}
58+
env = key_environ.copy()
5959
if node0_only:
6060
cmd = ["numactl", "--cpunodebind=0", "--membind=0"] + cmd
6161
run_cmd(cmd, SPARK_HOME, log_file, env, for_real)
@@ -248,7 +248,7 @@ def start(args) -> None:
248248
# driver
249249
cmd = ["sbin/start-master.sh"]
250250
log_file = joinpath(WORK_PATH, "start_master.log")
251-
env = {}
251+
env = key_environ.copy()
252252
write_spark_env(args, worker_idx=-1)
253253
if args.numa == "node0_only":
254254
cmd = ["numactl", "--cpunodebind=0", "--membind=0"] + cmd
@@ -301,27 +301,28 @@ def start(args) -> None:
301301
# shuffle server
302302
cmd = ["sbin/start-shuffle-service.sh"]
303303
log_file = joinpath(WORK_PATH, "start_shuffle_service.log")
304-
env = {}
304+
env = key_environ.copy()
305305
if args.numa == "node0_only":
306306
cmd = ["numactl", "--cpunodebind=0", "--membind=0"] + cmd
307307
run_cmd(cmd, SPARK_HOME, log_file, env, args.real)
308308

309309

310310
def stop(args) -> None:
311311
# workers
312-
cmd = ["sbin/stop-slave.sh"]
313-
log_file = joinpath(WORK_PATH, "stop_slave.log")
314-
env = {"SPARK_WORKER_INSTANCES": str(args.num_workers)}
312+
cmd = ["sbin/stop-worker.sh"]
313+
log_file = joinpath(WORK_PATH, "stop-worker.log")
314+
env = key_environ.copy()
315+
env["SPARK_WORKER_INSTANCES"] = str(args.num_workers)
315316
run_cmd(cmd, SPARK_HOME, log_file, env, args.real, check=False)
316317
# shuffle server
317318
cmd = ["sbin/stop-shuffle-service.sh"]
318319
log_file = joinpath(WORK_PATH, "stop_shuffle_service.log")
319-
env = {}
320+
env = key_environ.copy()
320321
run_cmd(cmd, SPARK_HOME, log_file, env, args.real, check=False)
321322
# drvier
322323
cmd = ["sbin/stop-master.sh"]
323324
log_file = joinpath(WORK_PATH, "stop_master.log")
324-
env = {}
325+
env = key_environ.copy()
325326
run_cmd(cmd, SPARK_HOME, log_file, env, args.real, check=False)
326327

327328

@@ -405,6 +406,8 @@ def setup(args, init: bool = False) -> None:
405406
SPARK_CONFIGS = get_standalone_configs(platform)
406407
# add warehouse directory
407408
SPARK_CONFIGS["spark.sql.warehouse.dir"] = os.path.abspath(args.database_location)
409+
# Add legacy assignment policy for Spark 4.0.0 compatibility
410+
SPARK_CONFIGS["spark.sql.storeAssignmentPolicy"] = "LEGACY"
408411
if init:
409412
print(f"set database location at {os.path.abspath(args.database_location)}/")
410413
# update total core count
@@ -430,6 +433,25 @@ def setup(args, init: bool = False) -> None:
430433
shutil.copy(
431434
start_slave_srcfile, joinpath(SPARK_HOME, "sbin", "start-slave-fb.sh")
432435
)
436+
# copy custom shuffle service scripts
437+
start_shuffle_srcfile = joinpath(
438+
PROJ_ROOT, "scripts", "start-shuffle-service.sh"
439+
)
440+
stop_shuffle_srcfile = joinpath(PROJ_ROOT, "scripts", "stop-shuffle-service.sh")
441+
if args.real:
442+
shutil.copy(
443+
start_shuffle_srcfile,
444+
joinpath(SPARK_HOME, "sbin", "start-shuffle-service.sh"),
445+
)
446+
shutil.copy(
447+
stop_shuffle_srcfile,
448+
joinpath(SPARK_HOME, "sbin", "stop-shuffle-service.sh"),
449+
)
450+
log4j2_srcfile = joinpath(CONF_PATH, "log4j2.properties")
451+
if args.real:
452+
shutil.copy(
453+
log4j2_srcfile, joinpath(SPARK_HOME, "conf", "log4j2.properties")
454+
)
433455

434456

435457
def init_parser():
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#!/usr/bin/env bash
2+
3+
#
4+
# Licensed to the Apache Software Foundation (ASF) under one or more
5+
# contributor license agreements. See the NOTICE file distributed with
6+
# this work for additional information regarding copyright ownership.
7+
# The ASF licenses this file to You under the Apache License, Version 2.0
8+
# (the "License"); you may not use this file except in compliance with
9+
# the License. You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing, software
14+
# distributed under the License is distributed on an "AS IS" BASIS,
15+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
# See the License for the specific language governing permissions and
17+
# limitations under the License.
18+
#
19+
20+
# Starts the external shuffle server on the machine this script is executed on.
21+
#
22+
# Usage: start-shuffle-server.sh
23+
#
24+
# Use the SPARK_SHUFFLE_OPTS environment variable to set shuffle server configuration.
25+
#
26+
27+
if [ -z "${SPARK_HOME}" ]; then
28+
export SPARK_HOME="$(cd "`dirname "$0"`"/..; pwd)"
29+
fi
30+
31+
. "${SPARK_HOME}/sbin/spark-config.sh"
32+
. "${SPARK_HOME}/bin/load-spark-env.sh"
33+
34+
exec "${SPARK_HOME}/sbin"/spark-daemon.sh start org.apache.spark.deploy.ExternalShuffleService 1
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#!/usr/bin/env bash
2+
3+
#
4+
# Licensed to the Apache Software Foundation (ASF) under one or more
5+
# contributor license agreements. See the NOTICE file distributed with
6+
# this work for additional information regarding copyright ownership.
7+
# The ASF licenses this file to You under the Apache License, Version 2.0
8+
# (the "License"); you may not use this file except in compliance with
9+
# the License. You may obtain a copy of the License at
10+
#
11+
# http://www.apache.org/licenses/LICENSE-2.0
12+
#
13+
# Unless required by applicable law or agreed to in writing, software
14+
# distributed under the License is distributed on an "AS IS" BASIS,
15+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
# See the License for the specific language governing permissions and
17+
# limitations under the License.
18+
#
19+
20+
# Stops the external shuffle service on the machine this script is executed on.
21+
22+
if [ -z "${SPARK_HOME}" ]; then
23+
export SPARK_HOME="$(cd "`dirname "$0"`"/..; pwd)"
24+
fi
25+
26+
"${SPARK_HOME}/sbin"/spark-daemon.sh stop org.apache.spark.deploy.ExternalShuffleService 1

packages/spark_standalone/templates/proj_root/scripts/utils.py

Lines changed: 3 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -98,35 +98,8 @@ def read_sys_configs() -> Dict[str, int]:
9898

9999

100100
def find_java_home() -> str:
101-
# Try finding a home path for java 8
102-
candidates = [
103-
"/usr/lib/jvm/java-1.8.0-openjdk",
104-
"/usr/lib/jvm/java-1.8.0-jre",
105-
"/usr/lib/jvm/java-8-openjdk",
106-
"/usr/lib/jvm/java-8-jre",
107-
"/usr/lib/jvm/openjdk-8",
108-
"/usr/lib/jvm/jre-1.8.0",
109-
"/usr/lib/jvm/jre-1.8.0-openjdk",
110-
]
111-
archname = platform.machine()
112-
if archname == "x86_64":
113-
archname = "amd64"
114-
elif archname == "aarch64":
115-
archname = "arm64"
116-
for path in candidates:
117-
if os.path.exists(f"{path}/bin/java"):
118-
return path
119-
path_with_arch = f"{path}-{archname}"
120-
if os.path.exists(f"{path_with_arch}/bin/java"):
121-
return path_with_arch
122-
# If none of the candidate exists, try find through `java` command
123-
try:
124-
java_path = subprocess.check_output(["which", "java"], text=True).strip()
125-
java_home = str(pathlib.Path(os.path.realpath(java_path)).parents[1])
126-
except subprocess.CalledProcessError:
127-
java_home = ""
128-
129-
return java_home
101+
# Always use the specific GraalVM JDK 17.0.12 path
102+
return "/usr/lib/jvm/graalvm-jdk-17.0.12+8.1"
130103

131104

132105
def read_environ() -> Dict[str, str]:
@@ -135,7 +108,7 @@ def read_environ() -> Dict[str, str]:
135108
env_vars["PROJ_ROOT"] = "/".join(os.path.abspath(__file__).split("/")[:-2])
136109
env_vars["JAVA_HOME"] = find_java_home()
137110
env_vars["SPARK_HOME"] = os.path.join(
138-
env_vars["PROJ_ROOT"], "spark-2.4.5-bin-hadoop2.7"
111+
env_vars["PROJ_ROOT"], "spark-4.0.0-bin-hadoop3"
139112
)
140113
# read from actual environment
141114
for k in env_vars:
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#
2+
# Licensed to the Apache Software Foundation (ASF) under one or more
3+
# contributor license agreements. See the NOTICE file distributed with
4+
# this work for additional information regarding copyright ownership.
5+
# The ASF licenses this file to You under the Apache License, Version 2.0
6+
# (the "License"); you may not use this file except in compliance with
7+
# the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
#
17+
# Set everything to be logged to the console
18+
rootLogger.level = info
19+
rootLogger.appenderRef.stdout.ref = console
20+
# In the pattern layout configuration below, we specify an explicit `%ex` conversion
21+
# pattern for logging Throwables. If this was omitted, then (by default) Log4J would
22+
# implicitly add an `%xEx` conversion pattern which logs stacktraces with additional
23+
# class packaging information. That extra information can sometimes add a substantial
24+
# performance overhead, so we disable it in our default logging config.
25+
# For more information, see SPARK-39361.
26+
appender.console.type = Console
27+
appender.console.name = console
28+
appender.console.target = SYSTEM_ERR
29+
appender.console.layout.type = PatternLayout
30+
appender.console.layout.pattern = %d{yy/MM/dd HH:mm:ss} %p %c{1}: %m%n%ex
31+
# Set the default spark-shell/spark-sql log level to WARN. When running the
32+
# spark-shell/spark-sql, the log level for these classes is used to overwrite
33+
# the root logger's log level, so that the user can have different defaults
34+
# for the shell and regular Spark apps.
35+
logger.repl.name = org.apache.spark.repl.Main
36+
logger.repl.level = info
37+
logger.thriftserver.name = org.apache.spark.sql.hive.thriftserver.SparkSQLCLIDriver
38+
logger.thriftserver.level = info
39+
# Settings to quiet third party logs that are too verbose
40+
logger.jetty1.name = org.sparkproject.jetty
41+
logger.jetty1.level = warn
42+
logger.jetty2.name = org.sparkproject.jetty.util.component.AbstractLifeCycle
43+
logger.jetty2.level = error
44+
logger.replexprTyper.name = org.apache.spark.repl.SparkIMain$exprTyper
45+
logger.replexprTyper.level = info
46+
logger.replSparkILoopInterpreter.name = org.apache.spark.repl.SparkILoop$SparkILoopInterpreter
47+
logger.replSparkILoopInterpreter.level = info
48+
logger.parquet1.name = org.apache.parquet
49+
logger.parquet1.level = error
50+
logger.parquet2.name = parquet
51+
logger.parquet2.level = error
52+
# SPARK-9183: Settings to avoid annoying messages when looking up nonexistent UDFs in SparkSQL with Hive support
53+
logger.RetryingHMSHandler.name = org.apache.hadoop.hive.metastore.RetryingHMSHandler
54+
logger.RetryingHMSHandler.level = fatal
55+
logger.FunctionRegistry.name = org.apache.hadoop.hive.ql.exec.FunctionRegistry
56+
logger.FunctionRegistry.level = error

0 commit comments

Comments
 (0)