Spark基础全解析

SPARK全解析

标签(空格分隔): Spark


Spark是什么?


Spark是Apache的一个顶级项目,是一个快速、通用的大规模数据处理引擎。以下是它的几个特点 :

  • Speed
    存储在内存中的数据,Spark比Hadoop的MapReduce快100多倍,存储在磁盘中的数据要快10多倍。
  • Easy of Use
    开发Spark应用程序可以使用Java、Scala、Python、R等编程语言
  • Generality
    Spark提供了SparkSQL、Streaming、MLlib、GraphX,功能强大。一站式解决需求。
  • Runs Everywhere
    Spark可以运行在Hadoop的Yarn上、Mesos上、以及它自身的standalone上,处理的文件系统包括HDFS、Cassandra、HBase、S3.
    以上部分摘自官网: http://spark.apache.org/

Spark 源码编译

本文以 spark1.6.1版本为例

  • (1)下载源码包
    image_1arfncu4k17rfmqs15b51q47gs99.png-62.4kB
    • (2)准备环境
      Spark1.6.1版本编译需要Maven 3.3.3 or newer and Java 7+ 环境
      image_1arfndoeh1chn2mu143c16b51bp0m.png-102.1kB
    • (3)编译
      –1 解压spark源码
      –2 在执行编译前修改$SPARK_HOME下的make-distribution.sh文件如下
      image_1arfneage1ufi6flqgakrf15qb13.png-8.6kB
      –3 编译apache hadoop,需要配置镜像文件
      路径/opt/modules/apache-maven-3.3.3/conf/settings.xml
      配置内容
      image_1arfnes1f32h19pp1eie1lfi14ta1g.png-103.9kB
      如果是cdh版本hadoop,则必须去掉该镜像
      –配置域名解析服务器
      # vi /etc/resolv.conf
      内容:
      nameserver 8.8.8.8
      nameserver 8.8.4.4

      –4 执行编译(根据所使用的Hadoop版本进行编译)

—-针对APACH HADOOP
./make-distribution.sh --tgz -Phadoop-2.4 -Dhadoop.version=2.5.0 -Phive -Phive-thriftserver -Pyarn
—- 针对CDH HADOOP
./make-distribution.sh --tgz -Phadoop-2.4 -Dhadoop.version=2.5.0-cdh5.3.6 -Phive -Phive-thriftserver -Pyarn
image_1arfng4qo1hjh1agsf8efmhd4p1t.png-24.7kB


Spark本地模式安装配置及Spark Shell基本使用


1、Spark安装环境准备:

  • JAVA
  • HDFS(HDFS是否脱离了安全模式
  • SCALA
    image_1arfp3qag39r1l7l10n9c5kias2n.png-117.1kB

2、Spark安装

  • 将编译好的cdh版本的spark赋予执行权限,解压至指定目录
    image_1arfp7n5n4ufkqa2pv9fsfb034.png-23.7kB

  • 通过notepad++配置$SPARK_HOME目录下conf下的配置文件
    ①日志配置
    更改log4j.properties.template文件名为log4j.properties
    ②配置spark-env.sh
    image_1arfp9m3d57o4fl1eoapdank13h.png-96kB

  • 配置完成

3、测试Spark Shell命令行
使用Spark RDD进行简单测试:

  • 启动spark交互式命令行:bin/spark-shell 并编程测试wordcount

    • HDFS上的数据源

    image_1arfqlusteiq6ob1c681bav1rv23u.png-11.6kB

    • 定义rdd读取数据源

    image_1arfqnbb67m5jv3rg11838uni4b.png-36.2kB

    • 使用rdd.map(line => line.split(“ ”)) 可以将文件按空格进行分割,分割之后会变成数组

    image_1arfqs38afrolgd168b8mk69i55.png-18.9kB

    • 再在其后面加上.collect之后查看输出

    image_1arfqv0nq99l12821es5na499t5i.png-29.8kB

    • 这里需使用flatMap代替map对该数组进行一个压平的操作,即: rdd.flatMap(line => line.split(” “)).collect,输出的为压平后的一个个单词
      image_1arfr0lo7jum1pcbu100b1m25v.png-25.5kB

    • 再使用map操作将其变为元组对,即:rdd.flatMap(line => line.split(” “)).map(word => (word,1)).collect
      输出结果:
      image_1arfr1qrfri21ds01tqk1do0b3p6c.png-25.6kB

    • 进行到这一步,再使用reduceByKey()就可完成wordcount了,reduceByKey中的ByKey使数组中的元组对按key进行排序,reduce进行相加。
      即:
      rdd.flatMap(line => line.split(" ")).map(word => (word,1)).reduceByKey((a,b) => (a + b))
      image_1arfr4hh81dka15t5u8uq4r1f2p6p.png-37.1kB

    • 上一步即完成了对数据的处理,再对其赋值之后保存,即可完成wordcount
      赋值:
      val wordcountRDD = rdd.flatMap(line => line.split(" ")).map(word => (word,1)).reduceByKey((a,b) => (a + b))
      image_1arfr5u91o24g2f176s181p16d476.png-44.3kB

    • 保存: wordcountRDD.saveAsTextFile("/user/vin/wordcount/output")
      image_1arfr6v7o1q5uutr1kmg15rahcb7j.png-15.9kB


Spark集群


Spark Cluster 可以运行在Yarn上,由Yarn进行资源管理和任务调度,还可以运行在其自带的资源管理调度框架Standalone上,分为主节点Master(类似于yarn的resourcemanager)和从节点Work(类似于yarn的nodemanager),不同的是一台机器上可以运行多个Work。
Spark架构原理图:
image_1arg10ugj1lc09nr174n17cqhde80.png-109.7kB
说明:Job:包含了由Spark Action催生的多个Tasks,是一个并行计算
Stage:一个Job分为了多个彼此依赖的Stage,每个Stage又包含了一系列的Task,类似于MapReduce的Map阶段和reduce阶段。
- Spark集群安装部署
- 配置$SPARK_HOME目录下conf下的配置文件
1 配置spark-env.sh
参考官网:http://spark.apache.org/docs/1.6.1/spark-standalone.html#installing-spark-standalone-to-a-cluster
2 配置slaves
配置运行Work的主机名
3 启动
在sbin目录里使用
start-master.sh
start-slaves.sh
//启动所有的从节点,使用此命令时,运行此命令的机器,必须要配置与其他机器的SSH无密钥登录,否则启动的时候会出现一些问题
image_1arg1qjvueat11c54qs17i317ka8d.png-25.1kB
4 Spark的的web监控端口为8080,URL为7070,Job监控4040,都是自动增长
image_1arg1tn8o1fs81rceoh21vj42358q.png-58.3kB
5 测试Spark集群
spark-shell是spark的一个application,将其运行在spark standalone上,通过输入: bin/spark-shell –help 查看其运行方法
image_1arg22ohv6l61ql41u1p1hbod2897.png-35.5kB
启动: bin/spark-shell –master spark://vin01:7077
image_1arg243mjhgqjth1dqm19qdqfk9k.png-34kB


Spark Application开发、运行及监控(IDEA)


  • 在IDEA中创建scala Project,并添加spark依赖包
    步骤:File -> Project Structure -> Libraries -> +号 -> java -> 选择编译好的spark目录下的lib依赖包
    image_1arhk7l25c38kkn1l1idl21vvsb8.png-83.5kB
  • 导入依赖包之后即可进行程序开发,新建包、在包中创建Scala class之SparkApp
  • 编程
  • 配置resurces(在新建scala Project时,创建resources)
    由于程序中需要读hdfs上的数据文件,所以需要将hadoop的配置文件hdfs-site.xml 与core-site.xml 文件拷贝到scala project的resources中
    image_1arhkvlcm1fic1reg12h813ktmroc2.png-81.8kB

  • 本地运行
    使用Idea工具可以直接运行在本地模式,无需插件
    运行查看输出:
    image_1arhl0reh2pb1fqt1sbleapf5ccf.png-61.5kB

  • 打包在Spark shell上提交运行(bin/spark-submit …)
    步骤:

    1 打包
    File -> project structure -> Artifacts -> + -> jar
    image_1arhl4fer95oje1e881hmktm8cs.png-76.9kB
    2 选择类
    image_1arhl4v5l14a8gsd1f4d1qsohctd9.png-48.6kB
    3 去除依赖包(因为集群上本身有)
    image_1arhl5br4ervkue1bafrrd97idm.png-82.8kB
    4 上述步骤设置了打哪个包,还需要build进行打包
    image_1arhl678a1l371p5isapi991h6ce3.png-28.3kB
    5 将jar包上传至linux下并赋予执行权限:此处为方便上传到Spark主目录下
    image_1arhl73581prnlls1r3l1tkf14ndeg.png-33.7kB
    6 提交任务
    image_1arhl85lpl9dai01at1hsm1hvcet.png-21.9kB
    7 先测试本地
    image_1arhl9f5r1o7v1kr41cabc6f2h7fa.png-51.1kB
    8 测试集群:此时需要将代码中的master注释掉再重新打包,重新打包直接用rebuild即可
    image_1arhlab9919gn1e7l1qr41ti71gthfn.png-69.4kB
    9 启动spark Standalone
    查看8080端口是否有资源
    提交任务
    bin/spark-sumit --master spark://vin01:7077 scalaProject.jar
    image_1arhlb2f71ug718ho13q69p212jkg4.png-32.7kB
    10 监控
    image_1arhlbfofetu1aja1339efv4l1gh.png-47.9kB


Spark 日志监控(HistoryServer)配置


Spark HistoryServer配置分为两个部分:

第一、设置SparkApplicaiton在运行时,需要记录日志信息
配置:配置$SPARK_HOME目录下conf下spark-defaults.conf文件
image_1arhja89fq9a1kqkabk1gfrjdea1.png-23.7kB
第二、启动HistoryServer,通过界面查看
配置Spark主目录下conf下spark-env.sh文件
SPARK_HISTORY_OPTS="-Dspark.history.fs.logDirectory=hdfs://vin01/user/vin/sparkEventLogs"
配置完成启动服务
image_1arhjcvbo1lou192m18kgpomv1cae.png-95.2kB
它端口号是18080
image_1arhjh0ub1cj8a1mf291q3dupar.png-51.1kB


Spark RDD


  1. RDD是什么
    官方解释:
    RDD是Spark的基本抽象,是一个弹性分布式数据集,代表着不可变的,分区(partition)的集合,能够进行并行计算。也即是说:

    • 它是一系列的分片、比如说128M一片,类似于Hadoop的split;
    • 在每个分片上都有一个函数去执行/迭代/计算它
    • 它也是一系列的依赖,比如RDD1转换为RDD2,RDD2转换为RDD3,那么RDD2依赖于RDD1,RDD3依赖于RDD2。
    • 对于一个Key-Value形式的RDD,可以指定一个partitioner,告诉它如何分片,常用的有hash、range
    • 可选择指定分区最佳计算位置
  2. 创建RDD的两种方式

    • 方式一:
      将集合进行并行化操作
      List\Seq\Array
      演示:
      image_1arhmhtoq4pa1k5717bk1ntc15d6gu.png-38.8kB
    • 方式二:
      外部存储系统
      HDFS, HBase, or any data source offering a Hadoop InputFormat.
      image_1arhmrv6k1tkfp9h9731r11eukhb.png-117.9kB
  3. RDD的三大Operations
    • Transformation
      从原有的一个RDD进行操作创建一个新的RDD,通常是一个lazy过程,例如map(func) 、filter(func),直到有Action算子执行的时候
    • Action
      返回给驱动program一个值,或者将计算出来的结果集导出到存储系统中,例如count() reduce(func)
    • Persist
      将数据存储在内存中,或者存储在硬盘中
      例如: cache() persist() unpersist()
      合理使用persist()和cache()持久化操作能大大提高spark性能,但是其调用是有原则的,必须在transformation或者textFile后面直接调用persist()或cache(),如果先创建的RDD,然后再起一行调用这两个方法,则会报错
  4. RDD的常用Transformation
    – map(func) :返回一个新的分布式数据集,由每个原元素经过func函数转换后组成
    spark shell本地测试:
    val numbers = Array(1, 2, 3, 4, 5)
    val numberRDD = sc.parallelize(numbers, 1)  
    val multipleNumberRDD = numberRDD.map ( num => num * 2 )
    multipleNumberRDD.foreach ( num => println(num) ) 

image_1arhvvo24sjq5921hk81ile1ob19.png-29.7kB

– filter(func) : 返回一个新的数据集,由经过func函数后返回值为true的原元素组成

    val numbers = Array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
    val numberRDD = sc.parallelize(numbers, 1)
    val evenNumberRDD = numberRDD.filter { num => num % 2 == 0 }
    evenNumberRDD.foreach { num => println(num) }  

image_1ari04fp91q8sdfb1b8r66tj4mm.png-22.4kB

– flatMap(func) : 类似于map,但是每一个输入元素,会被映射为0到多个输出元素(因此,func函数的返回值是一个Seq,而不是单一元素)

    val lineArray = Array("hello you", "hello me", "hello world")  
    val lines = sc.parallelize(lineArray, 1)
    val words = lines.flatMap { line => line.split(" ") }   
    words.foreach { word => println(word) }

image_1ari0mqic1qmq1qvl1q2f1sq91dl13.png-24.3kB
– union(otherDataset) : 返回一个新的数据集,由原数据集和参数联合而成
– groupByKey([numTasks]) :在一个由(K,V)对组成的数据集上调用,返回一个(K,Seq[V])对的数据集。注意:默认情况下,使用8个并行任务进行分组,你可以传入numTask可选参数,根据数据量设置不同数目的Task

    val scoreList = Array(Tuple2("class1", 80), Tuple2("class2", 75),Tuple2("class1", 90), Tuple2("class2", 60))
    val scores = sc.parallelize(scoreList, 1)  
    val groupedScores = scores.groupByKey() 
     groupedScores.foreach(score => { 
      println(score._1); 
      score._2.foreach { singleScore => println(singleScore) };
      println("=============================")  })

image_1ari0pnrr31b8pkgn141f1p661g.png-32.7kB
– reduceByKey(func, [numTasks]) : 在一个(K,V)对的数据集上使用,返回一个(K,V)对的数据集,key相同的值,都被使用指定的reduce函数聚合到一起。和groupbykey类似,任务的个数是可以通过第二个可选参数来配置的。在实际开发中,能使reduceByKey实现的就不用groupByKey

val scoreList = Array(Tuple2("class1", 80), Tuple2("class2", 75),Tuple2("class1", 90), Tuple2("class2", 60))
    val scores = sc.parallelize(scoreList, 1)  
    val totalScores = scores.reduceByKey(_ + _)  
    totalScores.foreach(classScore => println(classScore._1 + ": " + classScore._2))  

image_1ari0vb9ie2f1sb7ehc13tvl411t.png-34.3kB
– join(otherDataset, [numTasks]) :在类型为(K,V)和(K,W)类型的数据集上调用,返回一个(K,(V,W))对,每个key中的所有元素都在一起的数据集

    val studentList = Array(
        Tuple2(1, "leo"),
        Tuple2(2, "jack"),
        Tuple2(3, "tom"));
   val scoreList = Array(
        Tuple2(1, 100),
        Tuple2(2, 90),
        Tuple2(3, 60));
    val students = sc.parallelize(studentList);
    val scores = sc.parallelize(scoreList);
    val studentScores = students.join(scores)  
    studentScores.foreach(studentScore => { 
      println("student id: " + studentScore._1);
      println("student name: " + studentScore._2._1)
      println("student socre: " + studentScore._2._2)  
      println("=======================================")  
    })  

image_1ari12cb8122f11tv1ufv14ao1i4n2a.png-76.8kB
– groupWith(otherDataset, [numTasks]) : 在类型为(K,V)和(K,W)类型的数据集上调用,返回一个数据集,组成元素为(K, Seq[V], Seq[W]) Tuples。这个操作在其它框架,称为CoGroup
– cartesian(otherDataset) : 笛卡尔积。但在数据集T和U上调用时,返回一个(T,U)对的数据集,所有元素交互进行笛卡尔积。
– repartition():重新分区,当数据处理到最后剩下很少的数据集时,可以使用repartition()进行重新分区

  1. 常用Action

    – reduce(func) : 通过函数func聚集数据集中的所有元素。Func函数接受2个参数,返回一个值。这个函数必须是关联性的,确保可以被正确的并发执行

    val numberArray = Array(1, 2, 
  • 11
    点赞
  • 138
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值