一、Spark的体系结构与安装部署
1.1 Spark集群的体系结构
官方的结构图:
更详细的结构图:
1.2 Spark的安装与部署
Spark的安装部署方式有以下几种模式:
Standalone
YARN
Mesos
Amazon EC2
(1)Spark Standalone伪分布
的部署
配置文件:conf/spark-env.sh
export JAVA_HOME=/root/training/jdk1.7.0_75
export SPARK_MASTER_HOST=spark81
export SPARK_MASTER_PORT=7077
#下面的可以不写,默认
export SPARK_WORKER_CORES=1
export SPARK_WORKER_MEMORY=1024m
配置文件:conf/slave
spark81
(2)Spark Standalone全分布
的部署
配置文件:conf/spark-env.sh
export JAVA_HOME=/root/training/jdk1.7.0_75
export SPARK_MASTER_HOST=spark82
export SPARK_MASTER_PORT=7077
#下面的可以不写,默认
export SPARK_WORKER_CORES=1
export SPARK_WORKER_MEMORY=1024m
配置文件 :conf/slave
spark83
spark84
(3)启动Spark集群:sbin/start-all.sh
ip:8080
(端口号)
1.3 Spark HA的实现
(1)基于文件系统的单点恢复
主要用于开发或测试环境。当spark提供目录保存spark Application和worker的注册信息,并将他们的恢复状态写入该目录中,这时,一旦Master发生故障,就可以通过重新启动Master进程(sbin/start-master.sh),恢复已运行的spark Application和worker的注册信息。
基于文件系统的单点恢复,主要是在spark-env.sh
里对SPARK_DAEMON_JAVA_OPTS设置
参数配置 | 参考值 |
spark.deploy.recoveryMode | 设置为FILESYSTEM开启单点恢复功能,默认值:NONE |
spark.deploy.recoveryDirectory | Spark 保存恢复状态的目录 |
export SPARK_DAEMON_JAVA_OPTS=
"-Dspark.deploy.recoveryMode=FILESYSTEM -Dspark.deploy.recoveryDirectory=
/root/training/spark-2.1.0-bin-hadoop2.7/recovery"
测试:
1、在spark82上启动Spark集群
2、在spark83上启动spark shell
MASTER=spark://spark82:7077 spark-shell
3、在spark82上停止master
stop-master.sh
4、观察spark83上的输出:
5、在spark82上重启master
start-master.sh
(2)基于Zookeeper的Standby Masters
ZooKeeper提供了一个Leader Election机制,利用这个机制可以保证虽然集群存在多个Master,但是只有一个是Active的,其他的都是Standby。当Active的Master出现故障时,另外的一个Standby Master会被选举出来。由于集群的信息,包括Worker, Driver和Application的信息都已经持久化到ZooKeeper,因此在切换的过程中只会影响新Job的提交,对于正在进行的Job没有任何的影响。加入ZooKeeper的集群整体架构如下图所示。
配置参数 | 参考值 |
spark.deploy.recoveryMode | 设置为ZOOKEEPER开启单点恢复功能,默认值:NONE |
spark.deploy.zookeeper.url | ZooKeeper集群的地址 |
spark.deploy.zookeeper.dir | Spark信息在ZK中的保存目录,默认:/spark |
参考:
export SPARK_DAEMON_JAVA_OPTS="-Dspark.deploy.recoveryMode=ZOOKEEPER
-Dspark.deploy.zookeeper.url=bigdata12:2181,bigdata13:2181,bigdata14:2181
-Dspark.deploy.zookeeper.dir=/spark"
另外:每个节点上,需要将以下两行注释掉。
ZooKeeper中保存的信息:
启动:
在主节点上启动 start-all
在另外从节点上 start-master.sh
二、执行Spark Demo程序
2.1 执行Spark Example程序
(1)示例程序:$SPARK_HOME/examples/jars/spark-examples_2.11-2.1.0.jar
(2)所有的示例程序:$EXAMPLE_HOME/examples/src/main
有Java、Scala等等等
(3)Demo:蒙特卡罗求PI
命令:
spark-submit --master spark://spark81:7077 --class
org.apache.spark.examples.SparkPi examples/jars/spark-examples_2.11-2.1.0.jar 100
2.2 使用Spark Shell
spark-shell是Spark自带的交互式Shell程序,方便用户进行交互式编程,用户可以在该命令行下用scala编写spark程序。
(1)启动Spark Shell:spark-shell
也可以使用以下参数:
参数说明:
--master spark://spark81:7077 指定Master的地址
--executor-memory 2g 指定每个worker可用内存为2G
--total-executor-cores 2 指定整个集群使用的cup核数为2个
例如:
spark-shell --master spark://spark81:7077 --executor-memory 2g
--total-executor-cores 2
(2)注意:
如果启动spark shell时没有指定master地址,但是也可以正常启动spark shell和执行spark shell中的程序,其实是启动了spark的local模式
,该模式仅在本机启动一个进程,没有与集群建立联系。
请注意local模式和集群模式的日志区别:
(3)在Spark Shell中编写WordCount程序
程序如下:
sc.textFile("hdfs://192.168.88.111:9000/data/data.txt").flatMap(_.split("
")).map((_,1)).reduceByKey(_+_).saveAsTextFile("hdfs://192.168.88.111:9000
/output/spark/wc")
说明:
sc 是SparkContext对象,该对象时提交spark程序的入口
textFile("hdfs://192.168.88.111:9000/data/data.txt") 是hdfs中读取数据
flatMap(_.split(" ")) 先map在压平
map((_,1)) 将单词和1构成元组
reduceByKey(_+_) 按照key进行reduce,并将value累加
saveAsTextFile("hdfs://192.168.88.111:9000/output/spark/wc") 将结果写入到hdfs中
2.3 在IDEA中编写WordCount程序
(1)需要的jar包:$SPARK_HOME/jars/*.jar
(2)创建Scala Project,并创建Scala Object、或者Java Class
(3)书写源代码
Scala版本:
package mydemo
import org.apache.spark.{SparkConf, SparkContext}
//使用Scala程序实现WordCount
object WordCount {
//定义主方法
def main(args: Array[String]): Unit = {
//创建SparkConf对象
val conf = new SparkConf().setAppName("My Scala WordCount")
//创建SparkContext对象
val sc = new SparkContext(conf)
//使用sc对象执行相应的算子
sc.textFile(args(0))
.flatMap(_.split(" "))
.map((_, 1))
.reduceByKey(_ + _)
.saveAsTextFile(args(1))
//停止sc
sc.stop()
}
}
Java版本:
package mydemo;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.FlatMapFunction;
import org.apache.spark.api.java.function.Function2;
import org.apache.spark.api.java.function.PairFunction;
import scala.Tuple2;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;
public final class JavaWordCount {
private static final Pattern SPACE = Pattern.compile(" ");
public static void main(String[] args) throws Exception {
if (args.length < 1) {
System.err.println("Usage: JavaWordCount <file>");
System.exit(1);
}
SparkConf sparkConf = new SparkConf().setAppName("JavaWordCount");
JavaSparkContext ctx = new JavaSparkContext(sparkConf);
JavaRDD<String> lines = ctx.textFile(args[0], 1);
JavaRDD<String> words = lines
.flatMap(new FlatMapFunction<String, String>() {
@Override
public Iterator<String> call(String s) throws Exception {
return Arrays.asList(SPACE.split(s)).iterator();
}
});
JavaPairRDD<String, Integer> ones = words
.mapToPair(new PairFunction<String, String, Integer>() {
@Override
public Tuple2<String, Integer> call(String s) {
return new Tuple2<String, Integer>(s, 1);
}
});
JavaPairRDD<String, Integer> counts = ones
.reduceByKey(new Function2<Integer, Integer, Integer>() {
@Override
public Integer call(Integer i1, Integer i2) {
return i1 + i2;
}
});
List<Tuple2<String, Integer>> output = counts.collect();
for (Tuple2<?, ?> tuple : output) {
System.out.println(tuple._1() + ": " + tuple._2());
}
ctx.stop();
}
}