Spark

1.spark安装

  (1)上传,解压
  (2)进入conf目录并重命名并修改spark-env.sh.template文件
	cd conf/
	mv spark-env.sh.template spark-env.sh
	vi spark-env.sh
	在该配置文件中添加如下配置
	export JAVA_HOME=/usr/local/jdk1.8.0_152
	export SPARK_MASTER_IP=hadoop01
	export SPARK_MASTER_PORT=7077
  (3)重命名并修改slaves.template文件
	mv slaves.template slaves
	vi slaves
	在该文件中添加子节点所在的位置(Worker节点)
	hadoop02
	hadoop03
	保存退出
	将配置好的Spark拷贝到其他节点上
	scp -r spark-1.6.1-bin-hadoop2.6/ root@hadoop02:$PWD
  (4)在sbin目录下启动./start-all.sh

2.RDD的概念

RDD(Resilient Distributed Dataset)叫做分布式数据集,是Spark中最基本的数据抽象,
	它代表一个不可变(创建了内容不可变)、可分区、里面的元素可并行计算的集合

特点:

1.由多个分区组成。对于RDD来说,每个分片都会被一个计算任务处理,并决定并行计算的粒度。
2.一个计算函数用于每个分区。Spark中RDD的计算是以分片为单位的,每个RDD都会实现compute函数以达到这个目的。
3.RDD之间的依赖关系。RDD的每次转换都会生成一个新的RDD,所以RDD之间就会形成类似于流水线一样的前后依赖关系。数据丢失时,根据依赖重新计算丢失的分区而不是整个分区。
4.一个Partitioner,即RDD的分片函数。默认是HashPartition
5.分区数据的最佳位置去计算。就是将计算任务分配到其所要处理数据块的存储位置。数据本地化

RDD中两种算子:
transformation 和 action

常用的transformation:

(1)map、flatMap、filter
(2)intersection求交集、union求并集:注意类型要一致
	 distinct:去重
(3)join:类型为(K,V)和(K,W)的RDD上调用,返回一个相同key对应的所有元素对在一起的(K,(V,W))的RDD
(4)groupByKey:在一个(K,V)的RDD上调用,返回一个(K, Iterator[V])的RDD
	 但是效率reduceByKey较高,因为有一个本地combiner的过程。
(5)cartesian笛卡尔积

常用的action

(1)collect()、count()
(2)collectAsMap:将K,V格式的RDD回收到Driver端作为Map使用
(3)reduce:通过func函数聚集RDD中的所有元素
(4)take(n):取前n个;top(2):排序取前两个
(5)takeOrdered(n):排完序后取前n个
(6)countByKey:统计相同的key 出现的个数
(7)countByValue:计数RDD中相同的value 出现的次数,不必须是K,V格式的RDD
(8)first : 取出第一个元素
(9)foreach : 遍历RDD中的每个元素
(10)foreachPartition:
(11)takeSample : takeSample(withReplacement,num,seed) 随机抽样将数据结果拿回Driver端使用,
返回Array。withReplacement:有无放回抽样num:抽样的条数 seed:种子

spark启动流程

1.调用start-all.sh脚本,首先启动Master服务
2.脚本开始解析slaves配置文件,解析到启动Worker的响应节点
  开始向启动Worker的节点发送启动命令来启动Worker
3.Worker开始向Master发送注册信息
4.Master接收到注册信息后并保存到内存和磁盘,保存后向Worker发送Mster的url
5.Worker接收大Master的url并保存,调用一个定时器,定时的向Master心跳
6.Master收到Worker的心跳后,找到相应的WorkerInfo,把最后一次心跳时间更改为当前时间

Spark SQL

Spark SQL是Spark用来处理结构化数据的一个模块,它提供了一个编程抽象叫做DataFrame并且作为分布式SQL查询引擎的作用。
与RDD类似,DataFrame也是一个分布式数据容器。然而DataFrame更像传统数据库的二维表格,除了数据以外,还记录数据的结构信息,即schema。

Spark SQL 基础代码:

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

object SparkSql {
  def main(args: Array[String]): Unit = {
    val conf: SparkConf = new SparkConf().setAppName("SparkSql").setMaster("local")
    val sc = new SparkContext(conf)
    val sqlContext = new SQLContext(sc)
    val linesRDD: RDD[Array[String]] = sc.textFile("D:/person/person.txt").map(_.split(","))
    //导入隐式转换,如果不导入无法将RDD转换成DataFrame
    //将RDD转换成DataFrame
    import sqlContext.implicits._
    val personRDD: RDD[Persons] = linesRDD.map(x => Persons(x(0).toInt,x(1),x(2).toInt))
    val personDF: DataFrame = personRDD.toDF
    personDF.show()
    personDF.select("name").show()
    personDF.select(personDF.col("age")+1).show()
    //显示Schema信息
    personDF.printSchema()
    personDF.filter(personDF.col("age") < 30).show()
    personDF.groupBy("age").count().show()
    //注册临时表
    personDF.registerTempTable("person")
    //sql
    val df: DataFrame = sqlContext.sql("select * from person where age < 30 order by age asc")
    df.write.mode("append").json("hdfs://hadoop01:9000/out-2018920-1")
		//mode
		//- `overwrite`: overwrite the existing data.
       // - `append`: append the data.
       // - `ignore`: ignore the operation (i.e. no-op).
       // - `error`: default option, throw an exception at runtime.
	

  }

}

case class Persons(id: Int, name: String, age: Int)

SparkStreaming:

用于流式数据的处理
特点:1.易用2.容错3.易整合到spark体系

DStream上的原语与RDD的类似,分为Transformations(转换)和Output Operations(输出)两种
transformations:

    map(func)
	flatMap(func)
	filter(func)
	repartition(numPartitions)
	union(otherStream)
	count()
	reduce(func)
	countByValue()
	reduceByKey(func, [numTasks])	
	join(otherStream, [numTasks])
	cogroup(otherStream, [numTasks])
	transform(func)	
	updateStateByKey(func)
	
	特殊的Transformations:
	UpdateStateByKey,Transform,Window
	
	窗口操作:一段时间内数据发生变化
	
	两个重要参数:窗口长度,滑动间隔
	注意窗口长度和滑动间隔必须是批次间隔的倍数

Output Operations on DStreams:

可以将DStream的数据输出到外部的数据库或文件系统,当某个Output Operations原语被调用时(与RDD的Action相同),
	streaming程序才会开始真正的计算过程。
    
	
	print()
	saveAsTextFiles(prefix, [suffix])
	saveAsObjectFiles(prefix, [suffix])
	saveAsHadoopFiles(prefix, [suffix])
	foreachRDD(func)

模板代码:

    //创建SparkConf并设置为本地模式运行
    //注意local[2]代表开两个线程
    val conf = new SparkConf().setMaster("local[2]").setAppName("NetworkWordCount")
    //设置DStream批次时间间隔为2秒
    val ssc = new StreamingContext(conf, Seconds(2))
    //通过网络读取数据
    val lines = ssc.socketTextStream("192.168.10.101", 9999)
    //将读到的数据用空格切成单词
    val words = lines.flatMap(_.split(" "))
    //将单词和1组成一个pair
    val pairs = words.map(word => (word, 1))
    //按单词进行分组求相同单词出现的次数//结果不累加
    val wordCounts = pairs.reduceByKey(_ + _)
    //打印结果到控制台
    wordCounts.print()
    //开始计算
    ssc.start()
    //等待停止
    ssc.awaitTermination()

结果每次在Linux段输入的单词次数都被正确的统计出来,但是结果不能累加!如果需要累加需要使用updateStateByKey(func)来更新状态
//updateStateByKey(func),结果可以累加但是需要传入一个自定义的累加函数

    val conf: SparkConf = new SparkConf().setAppName("SparkStreamACCWordCount").setMaster("local[2]")
    //批次间隔
    val ssc = new StreamingContext(conf,Milliseconds(5000))
    //最好目录设在hdfs
    ssc.checkpoint("hdfs://hadoop01:9000/out-2018-8-1")

    //获取数据
    val dStream: ReceiverInputDStream[String] = ssc.socketTextStream("hadoop01",6666)
    //将获取到的数据生成一个一个元组
    val tupled: DStream[(String, Int)] = dStream.flatMap(_.split(" ")).map((_,1))

    //调用updateStateByKey来进行聚合
    val sumed: DStream[(String, Int)] = tupled.updateStateByKey(func,new HashPartitioner(ssc.sparkContext.defaultParallelism),true)
    sumed.print()
    ssc.start()
    ssc.awaitTermination()

  }

  /**
    * 该函数中,参数只有一个Iterator,其中有三个类型,分别代表
    * String代表元组中的每一个单词作为key
    * seq[Int]代表当前批次相同单词出现的次数:Seq(1,1,1,1)
    * Option[Int]代表上一批次相同单词累加的结果,有可能有值也有可能没有值
    * 所以用Option封装,此时取值最好用getElse方法
    *
    */
  val func = (it: Iterator[(String, Seq[Int], Option[Int])]) =>{
    it.map(x =>{
      (x._1,x._2.sum + x._3.getOrElse(0))
    })
  }

需求:获取kafka的数据并做批次累加功能的单词计数
注意1.怎么设置获取kafka的一些配置
2.怎么应用updateStateByKey

    val conf: SparkConf = new SparkConf().setAppName("LoadKafkaDataAndWordCount").setMaster("local[2]")
    val ssc = new StreamingContext(conf,Seconds(5))//批次间隔5秒

    //实现按批次累加功能,需要checkpoint
    ssc.checkpoint("hdfs://hadoop01:9000/cp-20180802-1")

    //设置请求kafka的一些配置信息
    val Array(zkQuorum,group,topics,numThreads) = args

    //把每个topic放到一个map里

    val topicMap: Map[String, Int] = topics.split(",").map((_,numThreads.toInt)).toMap
    //调用kafka工具类获取kafka集群的数据
    val data: ReceiverInputDStream[(String, String)] =
      KafkaUtils.createStream(ssc,zkQuorum,group,topicMap)
    //因为key对应的是offset值,不需要,只留下数据
    val lines: DStream[String] = data.map(_._2)

    //计算单词计数
    val tupled: DStream[(String, Int)] = lines.flatMap(_.split(" ")).map((_,1))

    val sumed: DStream[(String, Int)] =
      tupled.updateStateByKey(func,new HashPartitioner(ssc.sparkContext.defaultParallelism),true)

    sumed.print()//打印

    ssc.start()//线程执行

    ssc.awaitTermination()//线程等待
  }
  //Iterator[(K, Seq[V], Option[S])]) => Iterator[(K, S)
    val func = (it: Iterator[(String,Seq[Int],Option[Int])]) => {
      it.map{
        case (x,y,z) => {
          (x,y.sum + z.getOrElse(0))
        }
      }
    }

SparkStreaming获取Kafka的两种方式:

 reciever:
  是利用 Kafka 消费者高级 API 在 Spark 的工作节点上创建消费者线程,订阅 Kafka 中的消息,
  数据会传输到 Spark 工作节点的执行器中,但是默认配置下这种方法在 Spark Job 出错时会导致数据丢失,
  如果要保证数据可靠性,需要在 Spark Streaming 中开启Write Ahead Logs(WAL),
  也就是上文提到的 Kafka 用来保证数据可靠性和一致性的数据保存方式。
  可以选择让 Spark 程序把 WAL 保存在分布式文件系统(比如 HDFS)
  
  
  direct:
  不需要建立消费者线程,使用 createDirectStream 接口直接去读取 Kafka 的 WAL,将 Kafka 分区与 RDD 分区做一对一映射,
  相较于第一种方法,不需再维护一份 WAL 数据,提高了性能。读取数据的偏移量由 Spark Streaming 程序通过检查点机制自身处理,
  避免在程序出错的情况下重现第一种方法重复读取数据的情况,消除了 Spark Streaming 与 ZooKeeper/Kafka 数据不一致的风险。
  保证每条消息只会被 Spark Streaming 处理一次。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值