Spark简单介绍&安装步骤

Spark

1.spark 概述

  • spark概念
    • 基于内存的分布式计算系统,计算速度很快,只是用于数据的计算,不涉及到数据的存储.可以对接外部数据源(例如HDFS)
    • Spark是一个开源的类似于Hadoop MapReduce的通用的并行计算框架,Spark基于map reduce算法实现的分布式计算,拥有Hadoop MapReduce所具有的优点;但不同于MapReduce的是Spark中的Job中间输出和结果可以保存在内存中,从而不再需要读写HDFS,因此Spark能更好地适用于数据挖掘与机器学习等需要迭代的map reduce的算法。
    • Spark是MapReduce的替代方案,而且兼容HDFS、Hive,可融入Hadoop的生态系统,以弥补MapReduce的不足。

2.spark特性

  • 速度快
    • 与Hadoop的MapReduce相比,Spark基于内存的运算要快100倍以上,基于硬盘的运算也要快10倍以上。Spark实现了高效的DAG执行引擎,可以通过基于内存来高效处理数据流。
    • 在MapReduce任务中,如果当前有100个task,需要100个进程去执行task(MapReduce是以进程的方式运行任务)
    • 在spark任务中,如果当前有100个task,需要100个线程去执行task(spark是以线程的方式运行任务)
  • 易用性
    • 可以快速编写spark应用程序,使用四中语言 Java/scala/pathon/R.还支持超过80种高级算法,使用户可以快速构建不同的应用。
  • 通用性
    • Spark可以用于批处理、交互式查询(Spark SQL)、实时流处理(Spark Streaming)、机器学习(Spark MLlib)和图计算(GraphX)。这些不同类型的处理都可以在同一个应用中无缝使用。
  • 兼容性
    • Spark可以使用Hadoop的YARN和Apache Mesos作为它的资源管理和调度器,并且可以处理所有Hadoop支持的数据,包括HDFS、HBase和Cassandra等。
    • Spark也可以不依赖于第三方的资源管理和调度器,它实现了Standalone作为其内置的资源管理和调度框架,这样进一步降低了Spark的使用门槛,使得所有人都可以非常容易地部署和使用Spark。此外,Spark还提供了在EC2上部署Standalone的Spark集群的工具。

3.spark安装

  • 1.解压安装包
tar -zxvf spark-2.0.2-bin-hadoop2.7.tgz -C /usr/local/soft
  • 2.修改配置文件
    • 配置文件目录在 /usr/local/soft/spark/conf
    • vi spark-env.sh 修改文件(先把spark-env.sh.template重命名为spark-env.sh)
#配置java环境变量
export JAVA_HOME=/usr/local/soft/jdk1.7.0_67
#指定spark老大Master的IP
export SPARK_MASTER_HOST=node1
#指定spark老大Master的端口
export SPARK_MASTER_PORT=7077

​ vi slaves 修改文件(先把slaves.template重命名为slaves)

node2
node3
  • 3.拷贝配置到其他主机
通过scp 命令将spark的安装目录拷贝到其他机器上
scp -r /usr/local/soft/spark node2:/usr/local/soft
scp -r /usr/local/soft/spark node3:/usr/local/soft
  • 4.配置spark环境变量
    • 将spark添加到环境变量,添加以下内容到 /etc/profile
export SPARK_HOME=/usr/local/soft/spark
export PATH=$PATH:$SPARK_HOME/bin:$SPARK_HOME/sbin

#之后再把/etc/profile分发到node2和node3上
scp /etc/profile node2:/etc/
scp /etc/profile node3:/etc/

注意最后 source /etc/profile 刷新配置

3.1启动spark

  • #在主节点上启动spark,配置环境变量可以直接启动
/usr/local/soft/sbin/start-all.sh

注意 启动命令与hadoop相同,一般通过局部路径启动或者绝对路径启动

3.2 停止spark

  • #在主节点上停止spark集群
/usr/local/soft/spark/sbin/stop-all.sh

注意 关闭命令与hadoop相同,一般通过局部路径关闭或者绝对路径关闭

3.3spark的web界面

  • 正常启动spark集群后,可以通过访问http://node1:8080,查看spark的web界面,查看相关信息。

4.Spark HA高可用部署

4.1 高可用部署说明

  • SparkStandalone集群是Master-Slaves架构的集群模式,和大部分的Master-Slaves结构集群一样,存在着Master单点故障的问题。如何解决这个单点故障的问题,Spark提供了两种方案:
  • (1)基于文件系统的单点恢复(Single-NodeRecovery with Local File System)。

​ 主要用于开发或测试环境。当spark提供目录保存spark Application和worker的注册信息,并将他们的恢复状态写入该目录中,这时,一旦Master发生故障,就可以通过重新启动Master进程(sbin/start-master.sh),恢复已运行的spark Application和worker的注册信息。

  • (2)基于zookeeper的StandbyMasters(Standby Masters with ZooKeeper)。

​ 用于生产模式。其基本原理是通过zookeeper来选举一个Master,其他的Master处于Standby状态。将spark集群连接到同一个ZooKeeper实例并启动多个Master,利用zookeeper提供的选举和状态保存功能,可以使一个Master被选举成活着的master,而其他Master处于Standby状态。如果现任Master死去,另一个Master会通过选举产生,并恢复到旧的Master状态,然后恢复调度。整个恢复过程可能要1-2分钟。

4.2 基于zookeeper的Spark HA高可用集群部署

  • 该HA方案使用起来很简单,首先需要搭建一个zookeeper集群,然后启动zooKeeper集群,最后在不同节点上启动Master。具体配置如下:
vim spark-env.sh

注释掉   export SPARK_MASTER_HOST=hdp-node-01

​ 在spark-env.sh添加SPARK_DAEMON_JAVA_OPTS,内容如下:

export SPARK_DAEMON_JAVA_OPTS="-Dspark.deploy.recoveryMode=ZOOKEEPER  
-Dspark.deploy.zookeeper.url=node1:2181,node2:2181,node3:2181  
-Dspark.deploy.zookeeper.dir=/spark"
  • 参数说明
    • spark.deploy.recoveryMode:恢复模式(Master重新启动的模式)
    • 有三种:(1)ZooKeeper(2) FileSystem (3)NONE
    • spark.deploy.zookeeper.url:ZooKeeper的Server地址
    • spark.deploy.zookeeper.dir:保存集群元数据信息的文件、目录。包括Worker,Driver和Application。

注意:

  • 在普通模式下启动spark集群,只需要在主机上面执行start-all.sh 就可以了。
  • 在高可用模式下启动spark集群,先需要在任意一台节点上启动start-all.sh命令。然后在另外一台节点上单独启动master。命令start-master.sh。
可以在zkCli.sh 中查看zookeeper根目录是否有spark的存储信息

结果如下:
[zk: localhost:2181(CONNECTED) 2] ls /
[cluster, brokers, storm, zookeeper, admin, isr_change_notification, log_dir_event_notification, controller_epoch, spark, kafka-manager, consumers, latest_producer_id_block, config]

5.spark各个角色介绍

​ Spark架构使用了分布式计算中master-slave模型,master是集群中含有master进程的节点,slave是集群中含有worker进程的节点。

  • Driver Program :运⾏main函数并且新建SparkContext的程序。
  • Application:基于Spark的应用程序,包含了driver程序和集群上的executor。
  • Cluster Manager:指的是在集群上获取资源的外部服务。目前有三种类型

(1)Standalone:spark原生的资源管理,由Master负责资源的分配

(2)ApacheMesos:与hadoop MR兼容性良好的一种资源调度框架

(3)HadoopYarn: 主要是指Yarn中的ResourceManager

  • Worker Node: 集群中任何可以运行Application代码的节点,在Standalone模式中指的是通过slaves文件配置的Worker节点,在Spark on Yarn模式下就是NodeManager节点
  • Executor:是在一个worker node上为某应⽤启动的⼀个进程,该进程负责运⾏行任务,并且负责将数据存在内存或者磁盘上。每个应⽤都有各自独立的executor。
  • Task :被送到某个executor上的工作单元。

6.spark程序

  • 1.普通模式提交(指定当前集群中或者的master地址)
bin/spark-submit \
--class org.apache.spark.examples.SparkPi \
--master spark://node1:7077 \
--executor-memory 1G \
--total-executor-cores 2 \
examples/jars/spark-examples_2.11-2.3.0.jar \      
10

#spark2.3  jar包名字 :  spark-examples_2.11-2.3.0.jar

​ 该算法是利用蒙特·卡罗算法求圆周率PI,通过计算机模拟大量的随机数,最终会计算出比较精确的π。

  • 2.高可用模式提交
    • 在高可用模式下,因为涉及到多个Master,所以对于应用程序的提交就有了一点变化,因为应用程序需要知道当前的Master的IP地址和端口。这种HA方案处理这种情况很简单,只需要在SparkContext指向一个Master列表就可以了,如spark://host1:port1,host2:port2,host3:port3应用程序会轮询列表,找到活着的Master。
bin/spark-submit \
--class org.apache.spark.examples.SparkPi \
--master spark://node1:7077,node2:7077,node3:7077 \
--executor-memory 1G \
--total-executor-cores 2 \
examples/jars/spark-examples_2.11-2.0.2.jar \
10
  • 可以修改log4j控制台输出的命令
# cp log4j.properties.template log4j.properties

#将INFO改为WARN
log4j.rootCategory=WARN, console
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.target=System.err
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yy/MM/dd HH:mm:ss} %p %c{1}: %
m%n

7.spark-shell使用

  • 1、spark-shell –master local[2] 读取本地数据文件实现单词计数
    • local[N]
    • local表示本地运行,后面的数字N表示本地采用多少个线程去运行任务
    • local[*]
    • local表示本地运行,后面的* 表示使用当前机器上所有可用的资源
    • 他会产生一个SparkSubmit进程。
sc.textFile("file:///root/words.txt").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).collect
  • 代码说明:

    • sc:Spark-Shell中已经默认将SparkContext类初始化为对象sc。用户代码如果需要用到,则直接应用sc即可。
    • textFile:读取数据文件
    • flatMap:对文件中的每一行数据进行压平切分,这里按照空格分隔。
    • map:对出现的每一个单词记为1(word,1)
    • reduceByKey:对相同的单词出现的次数进行累加
    • collect:触发任务执行,收集结果数据。
  • 2、spark-shell –master local[2] 读取HDFS数据文件实现单词计数

sc.textFile("hdfs://node1:9000/words.txt").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).collect
  • spark整合HDFS
    • 需要修改spark-env.sh
export HADOOP_CONF_DIR=/usr/local/soft/hadoop-2.7.4/etc/hadoop
  • 3、spark-shell –master spark://node1:7077 读取HDFS数据文件实现单词计数
sc.textFile("/words.txt").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).collect
  • 4.运行spark-shell 指定具体的master地址

(1)需求: spark-shell运行时指定具体的master地址,读取HDFS上的数据,做单词计数,然后将结果保存在HDFS上。

(2)执行启动命令:

spark-shell \
--masterspark://node1:7077 \
--executor-memory 1g \
--total-executor-cores 2

参数说明:

--master spark://hdp-node-01:7077 指定Master的地址
--executor-memory 1g 指定每个worker可用内存为1g
--total-executor-cores 2 指定整个集群使用的cup核数为2

​ 注意:如果启动spark shell时没有指定master地址,但是也可以正常启动spark shell和执行sparkshell中的程序,其实是启动了spark的local模式,该模式仅在本机启动一个进程,没有与集群建立联系

  • 执行代码
sc.textFile("/words.txt").flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).saveAsTextFile("/wc")

8.利用scala编写spark的wordcount程序(本地运行)

  • 导入依赖
 <dependency>
            <groupId>org.scala-lang</groupId>
            <artifactId>scala-library</artifactId>
            <version>2.11.8</version>
        </dependency>
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-core_2.11</artifactId>
            <version>2.0.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.hadoop</groupId>
            <artifactId>hadoop-client</artifactId>
            <version>2.7.4</version>
        </dependency>
  • 代码开发
package cn.itcast

import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.rdd.RDD

//todo:利用scala实现spark的wordcount程序
object WordCount {
  def main(args: Array[String]): Unit = {
      //1、创建sparkconf  设置appName和master地址   local[2] 表示本地使用2个线程运行
      val sparkConf: SparkConf = new SparkConf().setAppName("WordCount").setMaster("local[2]")
      //2、创建sparkcontext,所有计算的源头,它会创建DAGScheduler和TaskScheduler
      val sc = new SparkContext(sparkConf)
     //3、读取数据文件
      val data: RDD[String] = sc.textFile("D:\\words.txt")
     //4、切分每一行
      val words: RDD[String] = data.flatMap(_.split(" "))
     //5、每个单词计为1
      val wordAndOne: RDD[(String, Int)] = words.map((_,1))
     //6、相同单词出现次数累加
      val result: RDD[(String, Int)] = wordAndOne.reduceByKey(_+_)
     //7、打印输出
      val finalResult: Array[(String, Int)] = result.collect()
      println(finalResult.toBuffer)
    //关闭sc
    sc.stop()

  }
}

9.利用scala编写spark的wordcount程序(集群运行)

package cn.itcast

import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.rdd.RDD

//todo:利用scala实现spark的wordcount程序(集群运行)
object WordCountOnlinux {
  def main(args: Array[String]): Unit = {
    //1、创建sparkconf  设置appName
    val sparkConf: SparkConf = new SparkConf().setAppName("WordCount_Online")
    //2、创建sparkcontext,所有计算的源头,它会创建DAGScheduler和TaskScheduler
    val sc = new SparkContext(sparkConf)
    //3、读取数据文件
    val data: RDD[String] = sc.textFile(args(0))
    //4、切分每一行
    val words: RDD[String] = data.flatMap(_.split(" "))
    //5、每个单词计为1
    val wordAndOne: RDD[(String, Int)] = words.map((_,1))
    //6、相同单词出现次数累加
    val result: RDD[(String, Int)] = wordAndOne.reduceByKey(_+_)
    //7、保存结果数据到HDFS上
      result.saveAsTextFile(args(1))

    //关闭sc
    sc.stop()
  }
}
  • 提交脚本(包是包含依赖的jar包)
spark-submit --class cn.itcast.WordCountOnlinux --master spark://node1:7077 --executor-memory 1g --total-executor-cores 2 spark-mytest-1.0-SNAPSHOT.jar /words.txt /2018

10.利用java编写spark的wordcount程序(本地运行)

package cn.itcast;
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;
//todo:利用java语言实现spark的wordcount程序
public class WordCount_Java {
public static void main(String[] args) {
    //1、创建sparkconf对象
    SparkConf sparkConf = new SparkConf().setAppName("WordCount_Java").setMaster("local[2]");
    //2、创建javaSparkContext
    JavaSparkContext jsc = new JavaSparkContext(sparkConf);
    //3、读取数据文件
    JavaRDD<String> dataJavaRDD = jsc.textFile("d:\\words.txt");
    //4、切分每一行
    JavaRDD<String> wordsJavaRDD = dataJavaRDD.flatMap(new FlatMapFunction<String, String>() {
        public Iterator<String> call(String line) throws Exception {
            String[] words = line.split(" ");
            return Arrays.asList(words).iterator();
        }
    });
    //5、每个单词计为1
    JavaPairRDD<String, Integer> wordAndOneJavaPairRDD = wordsJavaRDD.mapToPair(new PairFunction<String, String, Integer>() {
        public Tuple2<String, Integer> call(String word) throws Exception {
            return new Tuple2<String, Integer>(word, 1);
        }
    });
    //6、相同单词出现的次数累加
    JavaPairRDD<String, Integer> resultJavaPairRDD = wordAndOneJavaPairRDD.reduceByKey(new Function2<Integer, Integer, Integer>() {
        public Integer call(Integer v1, Integer v2) throws Exception {
            return v1 + v2;
        }
    });
     //按照单词出现的次数降序排列  需要把(单词,次数) 位置颠倒 (次数,单词)
    JavaPairRDD<Integer, String> reverseJavaRDD = resultJavaPairRDD.mapToPair(new PairFunction<Tuple2<String, Integer>, Integer, String>() {
        public Tuple2<Integer, String> call(Tuple2<String, Integer> t) throws Exception {
            return new Tuple2<Integer, String>(t._2, t._1);
        }
    });

    //按照单词出现的次数降序排列 需要把(次数,单词)位置颠倒(单词,次数)
    JavaPairRDD<String, Integer> sortedRDD = reverseJavaRDD.sortByKey(false).mapToPair(new PairFunction<Tuple2<Integer, String>, String, Integer>() {
        public Tuple2<String, Integer> call(Tuple2<Integer, String> t) throws Exception {
            return new Tuple2<String, Integer>(t._2, t._1);
        }
    });

    //7、打印结果
    List<Tuple2<String, Integer>> finalResult = sortedRDD.collect();
    for (Tuple2<String, Integer> tuple : finalResult) {
        System.out.println("单词:"+tuple._1+" 次数:"+tuple._2);
    }
    //8、关闭
    jsc.stop();
   }
}
阅读更多

没有更多推荐了,返回首页