SparkStreaming概述

一、SparkStreaming概述

Spark内置对象:

sparkconf:

SparkContext的初始化需要一个SparkConf对象,SparkConf包含了Spark集群配置的各种参数。

SparkContext:

**SparkContext为Spark的主要入口点 ,SparkContext用于连接Spark集群、创建RDD、累加器(accumlator)、广播变量(broadcast variables),所以说SparkContext为Spark程序的根本都不为过** 

SqlContext:

SQLContext是SQL进行结构化数据处理的入口,可以通过它进行DataFrame的创建及SQL的执行 

StreamingContext:

创建应用程序主入口,并连上Driver上接收数据9999端口写入源数据 

 

 

数据能够被推到文件系统和数据库以及仪表板。

SparkStreaming会实时接收到数据流,将其拆分成很多批次,再被Spark引擎处理,得到最终的结果(批次)

 

软件之间相互协作:

启动一个软件----启动一个进程------请求类型http/hdfs-------端口(服务进行监听)-----另一个软件进行访问------输入命令通过端口发送--------通过端口进行返回

 

不同计算机之间的相互协作

 

客户端-----目标服务交互-----配置一致

 

Kafka(消息中间件,能够以容错的方式存储流式数据)----数据计算-----能够对实时采集的数据进行计算----历史数据存储-------合并历史数据----延迟性比较低的效果。

 

特点:

1. 易用

2. 容错

3. 易整合

二、词频统计案例

1. spark-submit

root用户

yum install nc

bigdata用户

Nc 监听某个端口有没有数据进来/还可以发送数据

在Linux下安装netcat: root下 yum install nc

在linux下解压压缩包到c://windows/System32

nc -lk 9999

spark-submit --master local[2] \
--class org.apache.spark.examples.streaming.NetworkWordCount \
$SPARK_HOME/lib/spark-examples-1.6.3-hadoop2.6.0.jar hh 9999

 

参数解释类的全路径,jar包的位置 主机 端口号

 

2. spark-shell

spark-shell --master local[2]    //根据CPU的核数分配线程,线程数为2

Intel超线程实际核数4有4个模拟核数
import org.apache.spark.streaming.{Seconds, StreamingContext}
val ssc = new StreamingContext(sc, Se6conds(1))
val lines = ssc.socketTextStream("hh", 8888)
val words = lines.flatMap(_.split(" "))
val wordCounts = words.map(x => (x, 1)).reduceByKey(_ + _)
wordCounts.print()
ssc.start()
ssc.awaitTermination()

三、SparkStreaming运行原理

1. 粗粒度

SparkStreaming接收实时数据流

根据给定的时间间隔进行拆分,变成小批次的处理

底层由Spark引擎计算

处理后的结果也是按批次的

2. 细粒度

在Driver端启动StreamingContext

同时启动Receiver

将接收到的数据拆分暂存在内存中

Receiver会向StreamingContext报告信息

StreamingContext会按预设的周期发布job

SparkContext会将job分发给Executor

、StreamingContext

可以使用SparkConf获得,也可以使用SparkContext获得

使用Streaming需要定义数据输入的源(DStream)

需要定义计算模式,最终作用在DStream

使用StreamingContext的start方法启动

使用awaitTermination方法将停止方式设置为手动停止或由于某些错误停止

手工停止时可以使用stop方法

、DStream

代表一个持续化的数据流,代表一系列的RDD,其中的每一个RDD都包含了一个批次的数据。

任何对于DStream的操作都相当于是对于每个RDD做相同的作。

、Input DStream和Receivers

每一个Input DStream都需要关联一个Receiver

1. Input DStream

代表从源头接收的数据流

2. Receivers

从源头接收数据(除文件系统外),存放在内存中,在处理时使用

、Transformation和Operations

1. Transformation

和RDD的操作类似,允许对Input DStream的数据进行修改

2. Operations

可以使用Output Operations输出计算结果,除此之外还支持窗口函数等

五、SparkStreaming处理Socket数据

build.sbt中添加依赖:

libraryDependencies += "org.apache.spark" %% "spark-streaming" % "1.6.3" % "provided"

import org.apache.spark.SparkConf
import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}
import org.apache.spark.streaming.{Seconds, StreamingContext}

object NetworkDataStream {
  def main(args: Array[String]): Unit = {
    val sparkConf = new SparkConf().setMaster("local[2]").setAppName("Streaming")
    val ssc = new StreamingContext(sparkConf,Seconds(3))
    val lines: ReceiverInputDStream[String] = ssc.socketTextStream("localhost", 9999)
    val result: DStream[(String, Int)] = lines.flatMap(_.split(" ")).map((_,1)).reduceByKey(_ + _)
    result.print()
    ssc.start()
    ssc.awaitTermination()
  }
}

运行在window上 需要安装netcat 在dos下启动nc -pl 9999进行监听

在idea中启动程序

注意:需要sbt配置文件将省略压缩包打开

spark-streaming" % "1.6.3"//% "provided"

 

程序运行到虚拟机:


import org.apache.spark.SparkConf
import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream}
import org.apache.spark.streaming.{Seconds, StreamingContext}

object NetWorkData2 {

  def main(args: Array[String]): Unit = {

    val sparkConf=new SparkConf().setAppName("Streaming").setMaster("local[2]")

    val ssc=new StreamingContext(sparkConf,Seconds(3))

    ssc.checkpoint("hdfs://hh:8020/ck-2018-8-19-001")

    val lines:ReceiverInputDStream[String]=ssc.socketTextStream("hh",9988)

    val words:DStream[String]=lines.flatMap(_.split(" "))

    val result:DStream[(String,Int)]=words.map((_,1)).reduceByKey(_+_)

    result.print()

    ssc.start()
    ssc.awaitTermination()
  }

}

 

 

第一步:程序打包

File---project  structure---Artifacts----+----第一项----第二项---moduel----创建的类---OK-----APPLY----OK

 

BUILD----build artifacts-----项目名---build----out中复制压缩包

 

第二步:上传到linux的datas中

 

启动两个客户端

第一个:nc -lk 9988

第二个:spark-submit --class com.qfedu.streaming.NetWorkData2 --master spark://hh:7077 untitled.jar

注意:端口启动过的就不要用了看不出效果:程序执行第二遍的话一定换一个端口,或重启各个服务

、SparkStreaming处理文件系统数据

Streaming会监控指定的文件夹,当有任何文件被创建时将会进行计算(但不支持子目录)

数据文件必须含有相同的格式。

 

文件必须通过移动或重命名的方式进行创建

 

一旦发生移动,文件不能被改变,新增的数据不会被读取

spark-shell
import org.apache.spark.streaming.{Seconds, StreamingContext}
val ssc = new StreamingContext(sc,Seconds(3))
val lines = ssc.textFileStream("file:///home/hadoop/dataDir")
val result = lines.flatMap(_.split(" ")).map((_,1)).reduceByKey(_ + _)
result.print()
ssc.start()
ssc.awaitTermination()

、UpdateStateByKey

UpdateStateByKey允许在使用持续更新的数据时保持状态信息,将最新的计算结果与历史结果做合并

 

定义一个状态-可以是任意的数据类型

 

定义一个状态更新的方法-如何使用先前状态和输入流中的新值更新

、流式数据单词计数案例

import org.apache.spark.SparkConf
import org.apache.spark.streaming.dstream.DStream
import org.apache.spark.streaming.{Seconds, StreamingContext}

object StatefulWordCount {
  def main(args: Array[String]): Unit = {
    val sparkConf = new SparkConf().setMaster("local[2]").setAppName("Streaming");
    val ssc = new StreamingContext(sparkConf,Seconds(3))
    ssc.checkpoint(".")   //可以指定为windows上的目录
    val lines = ssc.socketTextStream("localhost",9999)
    val result: DStream[(String, Int)] = lines.flatMap(_.split(" ").map((_,1)))
    val state = result.updateStateByKey(updateFunction)
    state.print()
    ssc.start()
    ssc.awaitTermination()
  }

  def updateFunction(curValues: Seq[Int], preValues: Option[Int]): Option[Int] = {
    val curCount = curValues.sum
    val preCount = preValues.getOrElse(0)
    Some(curCount + preCount)
  }
}

十一、Streaming写入结果至RDBMS

将统计结果写入MySQL,同时尽量保证高效运行

工程构建

libraryDependencies += "mysql" % "mysql-connector-java" % "5.1.46"

create table wordCount(
    word varchar(50) default null,
    counts int(11) default null
)

1. 实现一(错误示范)

连接出现序列化异常数据库有最大连接数

import org.apache.spark.SparkConf
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.streaming.dstream.DStream

object ForeachRDD {
  def main(args: Array[String]): Unit = {
    val sparkConf = new SparkConf().setMaster("local[2]").setAppName("Streaming");
    val ssc = new StreamingContext(sparkConf,Seconds(3))
    ssc.checkpoint(".")
    val lines = ssc.socketTextStream("localhost",9999)
    val result: DStream[(String, Int)] = lines.flatMap(_.split(" ").map((_,1))).reduceByKey(_ + _)
    result.foreachRDD(rdd => {
      val connection = createNewConnection()
      rdd.foreach(record => {
        val sql = "insert into wordCount values ('" + record._1 + "'," + record._2 + ")"
        connection.createStatement().execute(sql)
      })
    })
    ssc.start()
    ssc.awaitTermination()
  }

  def createNewConnection() = {
    Class.forName("com.mysql.jdbc.Driver")
    DriverManager.getConnection("jdbc:mysql://localhost:3306/teach01","root","mysql")
  }
}

2. 实现二

import java.sql.DriverManager
import org.apache.spark.SparkConf
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.streaming.dstream.DStream

object ForeachRDD {
  def main(args: Array[String]): Unit = {
    val sparkConf = new SparkConf().setMaster("local[2]").setAppName("Streaming");
    val ssc = new StreamingContext(sparkConf,Seconds(3))
    val lines = ssc.socketTextStream("localhost",9999)
    val result: DStream[(String, Int)] = lines.flatMap(_.split(" ").map((_,1))).reduceByKey(_ + _)
    result.print()
    result.foreachRDD(rdd => {
      rdd.foreachPartition(partitionOfRecords => {
          val connection = createNewConnection()
          partitionOfRecords.foreach(record => {
            val sql = "insert into wordCount values ('" + record._1 + "'," + record._2 + ")"
            connection.createStatement().execute(sql)
          })
          connection.close()
      })
    })
    ssc.start()
    ssc.awaitTermination()
  }

  def createNewConnection() = {
    Class.forName("com.mysql.jdbc.Driver")
    DriverManager.getConnection("jdbc:mysql://localhost:3306/teach01","root","mysql")
  }
}

十二、黑名单过滤

数据源分为两部分:访问日志(流式数据)和黑名单列表(离线数据),在流式数据中将黑名单中出现的数据进行过滤

数据维度:点击时间,用户名称

数据分隔符:逗号

import org.apache.spark.SparkConf
import org.apache.spark.streaming.{Seconds, StreamingContext}

object BlackListFilter {
  def main(args: Array[String]): Unit = {
    val sparkConf = new SparkConf().setMaster("local[2]").setAppName("Streaming");
    val ssc = new StreamingContext(sparkConf,Seconds(3))
    val blackListRDD = ssc.sparkContext.parallelize(List("ZhangSan","LiSi")).map((_,true))
    val lines = ssc.socketTextStream("localhost",9999)
    val result = lines.map(log => (log.split(",")(1),log)).transform(rdd => {
      rdd.leftOuterJoin(blackListRDD).filter(_._2._2.getOrElse(false) != true).map(_._1)
    })
    result.print()
    ssc.start()
    ssc.awaitTermination()
  }
}

 

 

猜你喜欢

转载自blog.csdn.net/qq_37001101/article/details/84245613