AWS 于 2022 年 5 月宣布推出 Graviton3,使用 ARM Neoverse 内核定制设计的 ARM 架构构建,针对提供高性能和能效进行了优化,与 Graviton2 相比,AWS Graviton3 的计算性能提高了 25%;并于 2023 年 11 月 16 日宣布在中国区域推出 C7g、M7g 和 R7g 实例。
客户在评估将他们的大数据工作负载转移到 AWS Graviton3 的过程中,许多人询问,在典型的批处理作业引擎 Spark 工作负载中,是否可以实现比同等配置 x86 实例更具性能和成本优势。
在这篇文章将比较 5 种相同配置的 EC2 实例在执行 TPC-DS Benchmark 时的性能和成本。
性能对比:
- r6g.2xlarge 相比 r5.2xlarge,完成时间上升 5%
- r7g.2xlarge 相比 r5.2xlarge,完成时间节省 22%
- r7g.2xlarge 相比 r6i.2xlarge,完成时间节省 1%
成本对比:
以上述 5 种实例在 us-east-2 区域的 1 年期无预付 RI 价格的有效小时费率为基础,计算执行 TPC-DS Benchmark 所需的成本:
进一步,以 r5.4xlarge 的 Benchmark 成本为基准进行归一化处理,得到如下比较结果:
其中:
- r6g.2xlarge 相比 r5.2xlarge ,成本节省 16%
- r7g.2xlarge 相比 r5.2xlarge ,成本节省 30%
- r7g.2xlarge 相比 r6i.2xlarge ,成本节省 17%
本文后续内容将详细描述如何搭建 Spark Local 模式集群和执行 TPC-DS Benchmark 测试。
Benchmark 工具介绍
TPC-DS 是一个由 Transaction Processing Performance Council(TPC)组织发布的决策支持基准测试。它旨在模拟现实世界中的决策支持系统的工作负载和查询模式,用于评估数据仓库系统的性能和功能。
TPC-DS 具有以下主要特点:
TPC-DS 定义了一个复杂的数据模型,包括 7 个事实表和 17 个维度表,涵盖了零售产品供应链的各个方面。它还提供了 99 个预定义的 SQL 查询,涉及各种决策支持场景,如销售分析、库存管理、促销效果评估等。
TPC-DS 支持多种数据规模,从 1GB 到 100TB 不等,以满足不同测试需求。数据是由数据生成器根据一定规则生成的,具有很好的可扩展性。
TPC-DS 支持并发测试,模拟多个用户同时运行查询的场景,更贴近真实的数据仓库工作负载。
TPC-DS 定义了多种性能指标,包括查询响应时间、综合查询吞吐量(QphDS)、功率测试等,全面评估系统的性能表现。
TPC-DS 基准测试具有良好的可移植性,可以在不同的数据库管理系统和硬件平台上运行,方便进行跨平台性能对比。
TPC-DS 基准测试被广泛应用于数据仓库系统的性能评估和优化,用户可以更好地了解数据仓库系统在真实场景下的性能表现,为系统选型和优化提供依据。
Benchmark 组网
在本文采用 r7g.4xlarge 搭建 Spark Local 集群并执行 TPC-DS Benchmark。
- 节点数:1 * r7g.4xlarge
- EBS 磁盘:200GB GP3(500MB/s 吞吐,10,000 IOPS)
- 操作系统:Amazon Linux 2
- 主要软件版本:
- Open JDK 1.8
- Scala 2.12.18
- Hadoop 3.3.1
- Hive 3.1.3
- Spark 3.3.1
部署 Spark 单节点
创建 EC2 实例
本次 Benchmark 中使用单节点 Spark Local 模式,所有软件均部署在该节点。您可以参考教程:Amazon EC2 Linux 实例入门,完成这台 EC2 实例的创建。
安装基础软件包
通过 SSH 登录到 EC2 实例,使用 ec2-user用户,执行下面命令安装必要的基础软件。
提示:整个安装配置过程可能耗时较长,建议通过 screen 或 tmux 等工具创建一个新的会话执行后续过程。
设置软件栈版本:
echo "export HADOOP_VERSION=3.3.1" >> ~/.bashrc
echo "export HIVE_VERSION=3.1.3" >> ~/.bashrc
echo "export SPARK_VERSION=3.3.1" >> ~/.bashrc
echo "export SCALA_VERSION=2.12.18" >> ~/.bashrc
安装 OpenJDK:
sudo amazon-linux-extras install -y epel
sudo yum install -y java-1.8.0-openjdk java-1.8.0-openjdk-devel git gcc gcc-c++ patch htop dstat nload
JAVA_HOME="/usr/lib/jvm/jre"
echo "export JAVA_HOME=${JAVA_HOME}" >> ~/.bashrc
echo "export PATH=${JAVA_HOME}/bin/:${PATH}" >> ~/.bashrc
source ~/.bashrc
java -version
安装 Scala:
cd ~
wget https://downloads.lightbend.com/scala/${SCALA_VERSION}/scala-${SCALA_VERSION}.tgz
tar zxf scala-${SCALA_VERSION}.tgz
ln -s $HOME/scala-${SCALA_VERSION} scala
echo "export SCALA_HOME=$HOME/scala" >> ~/.bashrc
echo "export PATH=$PATH:$HOME/scala/bin" >> ~/.bashrc
source ~/.bashrc
安装 Maven:
wget https://dlcdn.apache.org/maven/maven-3/3.9.6/binaries/apache-maven-3.9.6-bin.tar.gz
tar zxf apache-maven-3.9.6-bin.tar.gz
ln -s ~/apache-maven-3.9.6 maven
MAVEN_HOME="/home/ec2-user/maven"
echo "export MAVEN_HOME=${MAVEN_HOME}" >> ~/.bashrc
echo "export PATH=${PATH}:${MAVEN_HOME}/bin" >> ~/.bashrc
source ~/.bashrc
mvn -v
安装 mysql 客户端,主要用于 Hive 组件:
wget https://repo.mysql.com/mysql80-community-release-el7-7.noarch.rpm
sudo rpm -Uvh mysql80-community-release-el7-7.noarch.rpm
sudo yum install -y mysql-community-client mysql-community-server --nogpgcheck
sudo systemctl start mysqld
sudo systemctl status mysqld
# 修改 MySQL 数据库 root 用户初始密码
cat << EOF > create_remote_login_user.sql
alter user 'root'@'localhost' identified with mysql_native_password by 'DoNotChangeMe@@123';
set global validate_password.policy=0;
alter user 'root'@'localhost' identified with mysql_native_password by 'gv2mysql';
create user 'root'@'%' identified with mysql_native_password by 'gv2mysql';
grant all privileges on *.* to 'root'@'%' with grant option;
flush privileges;
EOF
MYSQL_INIT_PASSWORD=$(sudo grep 'temporary password' /var/log/mysqld.log | tail -1 | awk '{print $NF}')
MYSQL_CMD_OPTIONS="--connect-expired-password -uroot -p${MYSQL_INIT_PASSWORD}"
mysql $MYSQL_CMD_OPTIONS < create_remote_login_user.sql
# 验证登录
mysql -uroot -p'gv2mysql' -e "show databases;"
# 创建 MySQL 数据库的 hive 用户
cat << EOF > create_hive_user.sql
CREATE DATABASE hive;
USE hive;
CREATE USER 'hive'@'localhost' IDENTIFIED BY 'Hive313Mysql';
GRANT ALL ON *.* TO 'hive'@'localhost';
FLUSH PRIVILEGES;
EOF
mysql -uroot -p'gv2mysql' < create_hive_user.sql
安装和配置 Hadoop 软件
首先确定实例的架构(x86_64 或 aarch64),后续会下载对应架构的 Hadoop 软件包:
cd ~
ARCH=$(arch)
if [[ "$ARCH" == "aarch64" ]]; then
ARCH="-aarch64"
elif [[ "$ARCH" == "x86_64" ]]; then
ARCH=""
else
echo "$ARCH not supported"
exit 1
fi
下载指定架构的 Hadoop 软件包:
wget https://archive.apache.org/dist/hadoop/common/hadoop-$HADOOP_VERSION/hadoop-$HADOOP_VERSION$ARCH.tar.gz
tar zxf hadoop-$HADOOP_VERSION$ARCH.tar.gz
ln -s hadoop-$HADOOP_VERSION $HOME/hadoop
echo "export HADOOP_HOME=$HOME/hadoop" >> ~/.bashrc
echo "export PATH=$PATH:$HOME/hadoop/bin:$HOME/hadoop/sbin" >> ~/.bashrc
source ~/.bashrc
mkdir $HADOOP_HOME/tmp
mkdir $HADOOP_HOME/hdfs
mkdir $HADOOP_HOME/hdfs/name
mkdir $HADOOP_HOME/hdfs/data
hadoop version
生成密钥用于无密码登录:
ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
chmod 0600 ~/.ssh/authorized_keys
ssh localhost
exit
配置 Hadoop 环境,首先修改 Hadoop-env.sh 脚本:
IPADDR=localhost
cp $HADOOP_HOME/etc/hadoop/hadoop-env.sh $HADOOP_HOME/etc/hadoop/hadoop-env.sh.bak
echo "export JAVA_HOME=${JAVA_HOME}" >> $HADOOP_HOME/etc/hadoop/hadoop-env.sh
修改 core-site.xml 配置文件:
cp $HADOOP_HOME/etc/hadoop/core-site.xml $HADOOP_HOME/etc/hadoop/core-site.xml.bak
cat << EOF > $HADOOP_HOME/etc/hadoop/core-site.xml
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://$IPADDR:9000</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/home/ec2-user/hadoop/tmp</value>
</property>
<property>
<name>hadoop.proxyuser.hive.hosts</name>
<value>*</value>
</property>
<property>
<name>hadoop.proxyuser.hive.groups</name>
<value>*</value>
</property>
</configuration>
EOF
修改 hdfs-site.xml 配置文件:
cp $HADOOP_HOME/etc/hadoop/hdfs-site.xml $HADOOP_HOME/etc/hadoop/hdfs-site.xml.bak
cat << EOF > $HADOOP_HOME/etc/hadoop/hdfs-site.xml
<?xml version="1.0"?>
<configuration>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
<property>
<name>dfs.name.dir</name>
<value>$HADOOP_HOME/hdfs/name</value>
</property>
<property>
<name>dfs.data.dir</name>
<value>$HADOOP_HOME/hdfs/data</value>
</property>
</configuration>
EOF
修改 yarn-site.xml 配置文件:
cp $HADOOP_HOME/etc/hadoop/yarn-site.xml $HADOOP_HOME/etc/hadoop/yarn-site.xml.bak
cat << EOF > $HADOOP_HOME/etc/hadoop/yarn-site.xml
<?xml version="1.0"?>
<configuration>
<property>
<name>yarn.resourcemanager.hostname</name>
<value>${IPADDR}</value>
</property>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
</configuration>
EOF
修改 mapred-site.xml 配置文件:
cp $HADOOP_HOME/etc/hadoop/mapred-site.xml $HADOOP_HOME/etc/hadoop/mapred-site.xml.bak
cat << EOF > $HADOOP_HOME/etc/hadoop/mapred-site.xml
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
<property>
<name>yarn.app.mapreduce.am.env</name>
<value>HADOOP_MAPRED_HOME=/home/ec2-user/hadoop</value>
</property>
<property>
<name>mapreduce.map.env</name>
<value>HADOOP_MAPRED_HOME=/home/ec2-user/hadoop</value>
</property>
<property>
<name>mapreduce.reduce.env</name>
<value>HADOOP_MAPRED_HOME=/home/ec2-user/hadoop</value>
</property>
</configuration>
EOF
初始化 HDFS 节点,启动 DFS 和 Yarn:
$HADOOP_HOME/bin/hdfs namenode -format
$HADOOP_HOME/sbin/start-dfs.sh
grep clusterID $(find $HADOOP_HOME/ -name VERSION)
$HADOOP_HOME/sbin/start-yarn.sh
jps
安装和配置 Hive 软件
下载和安装 Hive 软件:
cd ~
wget https://dlcdn.apache.org/hive/hive-$HIVE_VERSION/apache-hive-$HIVE_VERSION-bin.tar.gz
tar zxf apache-hive-$HIVE_VERSION-bin.tar.gz
ln -s $HOME/apache-hive-$HIVE_VERSION-bin hive
echo "export HIVE_HOME=$HOME/hive" >> ~/.bashrc
echo "export PATH=$PATH:$HOME/hive/bin:$HOME/hive/sbin" >> ~/.bashrc
source ~/.bashrc
修改 hive-site.xml 配置文件:
cp $HIVE_HOME/conf/hive-default.xml.template $HIVE_HOME/conf/hive-site.xml
sed -i "s/system:java.io.tmpdir/java.io.tmpdir/g" $HIVE_HOME/conf/hive-site.xml
sed -i "s/system:user.name/user.name/g" $HIVE_HOME/conf/hive-site.xml
在配置 hive-site.xml 中,有一部分配置项不便通过 Shell 脚本自动完成,请通过下面指导手工完成。
vi $HIVE_HOME/conf/hive-site.xml
请按照下表中 <name> 查找到对应的对应的 <property> 配置项,再对 <value> 值进行修改适配:
<name> |
<value> |
hive.exec.scratchdir |
/home/ec2-user/hive/tmp |
hive.metastore.warehouse.dir |
/home/ec2-user/hive/warehouse |
hive.querylog.location |
/home/ec2-user/hive/log |
javax.jdo.option.ConnectionURL |
jdbc:mysql://localhost:3306/hive?createDatabaseIfNotExist=true&characterEncoding=UTF-8&useSSL=false&allowPublicKeyRetrieval=true |
javax.jdo.option.ConnectionDriverName |
com.mysql.jdbc.Driver |
javax.jdo.option.ConnectionUserName |
hive |
javax.jdo.option.ConnectionPassword |
Hive313Mysql |
datanucleus.schema.autoCreateAll |
true |
hive.metastore.schema.verification |
false |
hive.server2.enable.doAs |
false |
hive.server2.thrift.bind.host |
localhost |
同时,删除文件/home/ec2-user/apache-hive-3.1.3-bin/conf/hive-site.xml 中 3215 行的特殊字符【】。
配置 MySQL Connector
cd ~
wget https://downloads.mysql.com/archives/get/p/3/file/mysql-connector-java-5.1.49.tar.gz
tar zxf mysql-connector-java-5.1.49.tar.gz
cp mysql-connector-java-5.1.49/mysql-connector-java-5.1.49.jar $HIVE_HOME/lib/
sudo ln -s $HIVE_HOME/lib/mysql-connector-java-5.1.49.jar /usr/share/java/mysql-connector-java.jar
$HIVE_HOME/bin/schematool -dbType mysql -initSchema
启动 Hive 服务
nohup hive --service metastore &
nohup hive --service hiveserver2 &
可通过 jps 查看启动的进程,并通过 hive 命令查看目前存在的数据库:
jps
hive -e "show databases;"
验证结果如下图所示:
安装和配置 Spark 软件
安装 Spark 软件:
cd ~
wget https://archive.apache.org/dist/spark/spark-$SPARK_VERSION/spark-$SPARK_VERSION-bin-hadoop3.tgz
tar zxf spark-$SPARK_VERSION-bin-hadoop3.tgz
ln -s spark-$SPARK_VERSION-bin-hadoop3 spark
echo "export SPARK_HOME=$HOME/spark" >> ~/.bashrc
echo "export PATH=$PATH:$HOME/spark/bin:$HOME/spark/sbin" >> ~/.bashrc
source ~/.bashrc
配置 Spark 软件:
cp $HIVE_HOME/conf/hive-site.xml $SPARK_HOME/conf/
cp $HADOOP_HOME/etc/hadoop/core-site.xml $HADOOP_HOME/etc/hadoop/hdfs-site.xml $SPARK_HOME/conf/
cp $SPARK_HOME/conf/log4j2.properties.template $SPARK_HOME/conf/log4j2.properties
sed -i "s/rootLogger.level = info/rootLogger.level = error/g" $SPARK_HOME/conf/log4j2.properties
ln -s /usr/share/java/mysql-connector-java.jar $SPARK_HOME/jars/mysql-connector-java.jar
启动 Spark Local 集群
在成功完成前面各组件的安装配置后,通过下面命令启动 Spark Local 集群:
$SPARK_HOME/sbin/start-all.sh
通过下面命令进行初步验证,spark-example 将完成指定位数的 Pi 值计算。
spark-sql -e "show databases;"
spark-submit --class org.apache.spark.examples.SparkPi \
$SPARK_HOME/examples/jars/spark-examples_2.12-3.3.1.jar 100
在 Spark 成功启动之后,可以得到如下验证结果:
安装和配置 Benchmark 工具
cd ~
git clone https://github.com/hortonworks/hive-testbench.git
cd $HOME/hive-testbench
./tpcds-build.sh
在 TPC-DS Benchmark 工具邮件完成之后,界面如下提示:
配置 benchmark 工具:
IPADDR=localhost
sed -i "s/localhost:2181\/;serviceDiscoveryMode=zooKeeper;zooKeeperNamespace=hiveserver2?tez.queue.name=default/${IPADDR}:10000\//" $HOME/hive-testbench/tpcds-setup.sh
sed -i "s/hive.optimize.sort.dynamic.partition.threshold=0/hive.optimize.sort.dynamic.partition=true/" $HOME/hive-testbench/settings/*.sql
生成测试数据集
通过指定 SF 的值,设置程序需要生成的数据量,本文中 SF=100 表示生成 100GB 的数据量。根据生成的数据量大小差异,此过程可能会持续数分钟到数小时不等。
cd $HOME/hive-testbench
SF=100
./tpcds-setup.sh $SF
生成数据过程如下图所示:
数据生成步骤完成后,如下图所示:
执行全部的 SQL 分析任务
待数据全部完成之后,预先准备 Benchmark 过程中需要的一些结果目录:
cd ~
SUT_NAME="spark-tpcds"
PN=$(sudo dmidecode -s system-product-name | tr ' ' '_')
DATA_DIR=~/${PN}_${SUT_NAME}
CFG_DIR=$DATA_DIR/system-infomation
TPCDS_RESULT_DIR=$DATA_DIR/spark-tpcds-result
LOG_DIR=$DATA_DIR/logs
mkdir -p $DATA_DIR $CFG_DIR $TPCDS_RESULT_DIR $LOG_DIR
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
RESULT_PATH="$TPCDS_RESULT_DIR/$TIMESTAMP"
mkdir -p $RESULT_PATH
RESULT_SUMMARY="$RESULT_PATH/result_summary_spark_tpc-ds.txt"
采用逐个执行 *.sql 文件的方式执行 Benchmark:
echo "[$TIMESTAMP] Start Spark TPC-DS Benchmark(SF=$SF) on $PN ...... " > $RESULT_SUMMARY
cd $HOME/hive-testbench/spark-queries-tpcds
LIST=$(ls *.sql)
for i in $LIST; do
RESULT_LOG="$RESULT_PATH/$i.log"
RESULT_OUT="$RESULT_PATH/$i.out"
spark-sql --driver-memory 4G --database tpcds_bin_partitioned_orc_$SF -f $i \ 1>$RESULT_OUT 2>$RESULT_LOG
execution_time=$(grep "Time taken" $RESULT_LOG)
echo "[$(date +%Y%m%d-%H%M%S)] $i : $execution_time " >> $RESULT_SUMMARY
done
查看 Benchmark 执行结果
当每一个 SQL 文件在执行时,可以通过下面步骤查看执行进程:
在这个目录中,有 3 类文件:
- *.log:表示某一个 SQL 文件执行信息,主要记录了该 SQL 文件执行完成的时间;
- *.out :表示某一个 SQL 文件在执行完成后,所返回的记录;
- result_summary_spark_tpc-ds.txt :记录了本次 Benchmark 执行过程中所有的 SQL 文件的执行时间。
你可以通过 tail/more/cat 等命令查看 Benchmark 执行结果,如下图所示:
在所有 SQL 文件都完成之后,您可以将 result_summary_spark_tpc-ds.txt 下载到本地电脑,通过 Excel 等工具对数据进行处理,例如计算所有 SQL 文件的总完成时间。
查看 Benchmark 执行时的监控信息
在 Benchmark 执行时,你可以这台 EC2 实例上,通过 top/htop 等监控命令查看 CPU/内存利用率等信息。
在 Benchmark 结束后,可以 在 EC2 控制台查看 EC2 实例的 CPU 利用率等监控指标。
本篇作者