将Hadoop的计算引擎从MapReduce (MR) 替换为Spark是一个非常常见且合理的架构演进。Spark以其卓越的内存计算、DAG执行引擎和友好的API,在大多数场景下性能远超MR。
以下是详细的替换步骤、考量因素以及最佳实践。
核心思想:Spark on YARN
最关键的一点是:替换MR并不意味着要卸载或移除Hadoop。恰恰相反,Spark与Hadoop生态系统结合得非常紧密,最佳部署模式是 Spark on YARN。
- Hadoop YARN:作为统一的资源管理和调度平台,同时为MR、Spark以及其他计算框架(如Tez, Flink)提供服务。
- Hadoop HDFS:作为稳定的数据存储层。
- 计算引擎:从MapReduce 替换为 Spark。
所以,你的Hadoop集群(YARN和HDFS)仍然是至关重要的基础设施,你只是换了一个更高效的计算引擎来在上面运行。
替换步骤详解
第一步:环境准备与Spark部署
-
安装Spark:
- 从Apache Spark官网下载与你的Hadoop版本(如Hadoop 3.x)预编译的版本。
- 将Spark解压到集群所有节点的相同目录下,例如
/opt/module/spark。
-
配置Spark(关键步骤):
进入$SPARK_HOME/conf目录,进行以下配置:spark-env.sh(复制spark-env.sh.template)# 配置JAVA_HOME export JAVA_HOME=/path/to/your/jdk # 配置Hadoop配置目录,让Spark能找到YARN和HDFS的配置 export HADOOP_CONF_DIR=${HADOOP_HOME}/etc/hadoop export YARN_CONF_DIR=${HADOOP_HOME}/etc/hadoop # (可选) 指定Spark History Server,便于查看历史任务日志 export SPARK_HISTORY_OPTS="-Dspark.history.fs.logDirectory=hdfs://mycluster/spark-history"spark-defaults.conf(复制spark-defaults.conf.template)# 指定Spark任务运行在YARN上 spark.master yarn # (可选) 设置事件日志目录,用于History Server spark.eventLog.enabled true spark.eventLog.dir hdfs://mycluster/spark-history # (可选) 配置一些默认资源,如Executor内存、核心数 spark.executor.memory 4g spark.executor.cores 2slaves(复制slaves.template): 这个文件在Standalone模式下有用,在YARN模式下不需要配置,因为由YARN管理节点。
-
分发Spark:
使用rsync或scp将配置好的Spark目录分发到所有工作节点。 -
启动Spark History Server (可选):
如果需要查看已完成任务的历史日志,可以启动它。$SPARK_HOME/sbin/start-history-server.sh
第二步:任务迁移 - 重写代码
这是最主要的工作量所在。你需要将原有的MR任务用Spark的API重写。
| 组件 | MapReduce (Java) | Spark (Scala/Python/Java) | 说明 |
|---|---|---|---|
| Driver | 无直接对应 | SparkSession/SparkContext | Spark任务的入口点,负责协调和调度。 |
| Mapper | Mapper Class | map, flatMap, filter 等转换操作 | 对初始数据进行处理,一对一的转换。 |
| Reducer | Reducer Class | reduceByKey, groupByKey, agg 等聚合操作 | 对Shuffle后的数据进行聚合。 |
| Job | 一个MR Job | 一个Spark Application | |
| Shuffle | 显式且昂贵 | 隐式(由算子触发)但优化得更好 | Spark的Shuffle管理更高效。 |
迁移示例:WordCount
-
MapReduce (Java):
// 代码较长,需要定义Mapper, Reducer, Job类,设置各种参数... public class WordCountMapper extends Mapper<...> { protected void map(...) { // split line and output (word, 1) } } public class WordCountReducer extends Reducer<...> { protected void reduce(...) { // sum values and output (word, count) } } // ... main 方法中组装的代码很长 -
Spark (Scala):
val sc = SparkSession.builder().appName("WordCount").getOrCreate().sparkContext val textFile = sc.textFile("hdfs://.../input.txt") val wordCounts = textFile.flatMap(line => line.split(" ")) .map(word => (word, 1)) .reduceByKey(_ + _) wordCounts.saveAsTextFile("hdfs://.../output") sc.stop()Spark (Python):
from pyspark.sql import SparkSession spark = SparkSession.builder.appName("WordCount").getOrCreate() sc = spark.sparkContext text_file = sc.textFile("hdfs://.../input.txt") word_counts = text_file.flatMap(lambda line: line.split(" ")) \ .map(lambda word: (word, 1)) \ .reduceByKey(lambda a, b: a + b) word_counts.saveAsTextFile("hdfs://.../output") sc.stop()
可以看到,Spark代码简洁明了,表达力更强。
第三步:提交与运行
迁移完成后,使用 spark-submit 脚本来提交任务到YARN集群。
$SPARK_HOME/bin/spark-submit \
--class org.apache.spark.examples.SparkPi \ # 你的主类
--master yarn \
--deploy-mode cluster \ # 或者 client,通常用cluster
--driver-memory 2g \
--executor-memory 4g \
--executor-cores 2 \
--num-executors 10 \
/path/to/your/spark-job.jar \
[application-arguments]
关键参数:
--master yarn: 指定运行在YARN上。--deploy-mode cluster/client:cluster模式将Driver端运行在YARN的ApplicationMaster中,更适合生产环境;client模式Driver运行在提交任务的机器上,常用于调试。- 其他资源参数(
--executor-memory等)会传递给YARN,YARN会据此分配Container。
重要考量因素与最佳实践
-
资源分配:
- Spark on YARN时,要合理设置Executor的内存和CPU核心数,避免与集群中其他服务(如HBase)或其它YARN任务争抢资源,导致OOM(内存溢出)或效率低下。
- 需要在YARN的
capacity-scheduler.xml中合理配置队列资源。
-
数据本地性:
- Spark和MR一样,会优先将任务调度到存有数据的节点上,以减少网络传输。确保Spark节点也是HDFS的DataNode。
-
依赖管理:
- 如果你的Spark作业依赖第三方JAR包,可以使用
spark-submit的--jars参数上传,或者预先放到集群所有节点的类路径下。
- 如果你的Spark作业依赖第三方JAR包,可以使用
-
监控与调试:
- YARN Web UI (
http://<resource-manager-host>:8088): 查看所有YARN应用的状态、日志和资源使用情况。 - Spark Web UI: 每个Spark应用都有自己的Web UI(URL在YARN UI中会提供),可以查看详细的DAG图、Stage、Task执行情况、Shuffle数据量等,是性能调优的利器。
- Spark History Server: 查看已完成应用的历史信息。
- YARN Web UI (
-
性能调优:
- 序列化: 使用Kryo序列化(
spark.serializer org.apache.spark.serializer.KryoSerializer)来减少序列化大小和时间。 - 内存管理: 调整
spark.executor.memoryOverhead以及堆内/堆外内存比例,防止Shuffle或缓存时溢出。 - Shuffle调优: 调整
spark.sql.shuffle.partitions来控制Shuffle后的分区数,避免过多或过少的分区导致性能问题。
- 序列化: 使用Kryo序列化(
总结
将Hadoop的MR替换为Spark是一个“低风险、高收益”的操作,核心流程是:
- 部署Spark:配置为
Spark on YARN模式。 - 代码重写:用Spark的API(RDD/DataFrame/Dataset)重写原有的MR任务。这是主要工作量。
- 提交运行:使用
spark-submit将任务提交到YARN。 - 监控调优:利用Web UI和日志监控任务运行状态,并进行性能调优。
通过这种方式,你既保留了Hadoop HDFS和YARN的稳定性和可靠性,又享受到了Spark带来的高性能和开发效率,完美实现了计算引擎的升级。

3967

被折叠的 条评论
为什么被折叠?



