Spark Streaming基础:
Spark Streaming makes it easy to build scalable fault-tolerant streaming applications.
Spark Streaming使得大规模容错型的流失计算应用变得十分容易
它的特点:
(1)支持多种语言:java scala python sql
(2)容易集成:当部署好spark的时候就spark Streaming已经集成了
(3)容错机制:核型数据模型就是DataStream,DataStream就是离散的RDD
容易出错的地方:
在sparkStreaming实时计算的时候要求最小cpu核数为2,一个负责接收发过来的流数据,一个负责处理数据
DataStream数据模型采样:
一个简单流式数据计算
import org.apache.log4j.Logger
import org.apache.log4j.Level
import org.apache.spark.SparkConf
import org.apache.spark.streaming.StreamingContext
import org.apache.spark.streaming.Seconds
import org.apache.spark.storage.StorageLevel
object demo1 {
def main(args: Array[String]): Unit = {
//不打印多余的日志配置
Logger.getLogger("org.apache.spark").setLevel(Level.ERROR)
Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF)
//获取StreamingContext对象
val conf=new SparkConf().setAppName("StreamTest2").setMaster("local[2]")
val ssc=new StreamingContext(conf,Seconds(2))
//得到DStream,是一个scoket输入流 ip 端口
val dstream = ssc.socketTextStream("192.168.112.111", 1234, StorageLevel.MEMORY_AND_DISK_SER)
dstream.flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).print()
//启动流式计算
ssc.start()
ssc.awaitTermination()
}
}
host:192.168.112.111,
port:1234
是我在linux服务下使用netcat当做一个socket服务在发送数据
nc -l -p 1234
nc :是命令
-l :使用的监听模式
-p :端口使用的是1234
还需要注意的是:
1、
dstream.flatMap(_.split(" ")).map((_,1)).reduceByKey(_+_).print()
必须需要有那个print()输出函数,不然的话会报一个错误,说没有输出函数:
Exception in thread "main" java.lang.IllegalArgumentException: requirement failed: No output operations registered, so nothing to execute
语法异常,没有输出操作注册,没有需要执行的操作。
2、每隔2秒钟采样一次,但是每次计算只是这2秒的内容,如果想把以前累加起来还需要自己做一个缓存操作,恰好spark给提供了一个处理以前状态的算子updateStateByKey
import org.apache.spark.SparkConf
import org.apache.spark.streaming.StreamingContext
import org.apache.spark.streaming.Seconds
import org.apache.spark.storage.StorageLevel
import org.apache.log4j.Logger
import org.apache.log4j.Level
object MyNetWorkWordCountTotal {
def main(args: Array[String]): Unit = {
//不打印多余的日志配置
Logger.getLogger("org.apache.spark").setLevel(Level.ERROR)
Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF)
//获取StreamingContext对象
val conf=new SparkConf().setAppName("StreamTest2").setMaster("local[2]")
val ssc=new StreamingContext(conf,Seconds(2))
//设置检查点
ssc.checkpoint("hdfs://192.168.112.111:9000/ckpt/day0529")
//得到DStream,是一个scoket输入流 ip 端口
val dstream = ssc.socketTextStream("192.168.112.111", 1234, StorageLevel.MEMORY_AND_DISK_SER)
val dStream2=dstream.flatMap(_.split(" ")).map((_,1))
/* val updateFunc=(currentValues:Seq[Int],previousValues:Option[Int]) => {
//当前要累加的总数
System.out.print(currentValues.length)
val currentSum = currentValues.sum
val previousValue=previousValues.getOrElse(0)
Some(currentSum+previousValue)
}*/
dStream2.updateStateByKey(updateFunc).print()
//启动流式计算
ssc.start()
ssc.awaitTermination()
}
def updateFunc(currentValues:Seq[Int],previousValues:Option[Int])={
//当前要累加的总数
System.out.print(currentValues.length)
val currentSum = currentValues.sum
val previousValue=previousValues.getOrElse(0)
Some(currentSum+previousValue)
}
}
使用这个函数的时候需要设置一个检查点,不然的话会报一下错误:
Exception in thread “main” java.lang.IllegalArgumentException: requirement failed: The checkpoint directory has not been set. Please set it by StreamingContext.checkpoint().
updateStateByKey的算子需要传入一个处理以前状态和现在状态的函数,注释掉的定义的updateFunc方法和下面定义的方法都可以。
S表示你要保存起来对应value的类型
Seq[Int]中的int类型是由操作你的DataStream流所决定的,比如的流中的value是Int那就是Int,如果是String那就是String
def updateStateByKey[S](updateFunc: (Seq[Int], Option[S]) => Option[S])(implicit evidence$4: ClassTag[S]): DStream[(String, S)]
3、sparkStreaming的一个窗口计算的算子
import org.apache.spark.streaming.StreamingContext
import org.apache.spark.streaming.Seconds
import org.apache.log4j.Logger
import org.apache.log4j.Level
import org.apache.spark.SparkConf
import org.apache.spark.storage.StorageLevel
object MyNetWorkWordCountWithWindow {
def main(args: Array[String]): Unit = {
//不打印多余的日志配置
Logger.getLogger("org.apache.spark").setLevel(Level.ERROR)
Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF)
//获取StreamingContext对象
val conf=new SparkConf().setAppName("StreamTest2").setMaster("local[2]")
val ssc=new StreamingContext(conf,Seconds(2))
//得到DStream,是一个scoket输入流 ip 端口
val dstream = ssc.socketTextStream("192.168.112.111", 1234, StorageLevel.MEMORY_AND_DISK_SER)
val pairRdd=dstream.flatMap(_.split(" ")).map((_,1))
pairRdd.reduceByKeyAndWindow((a:Int,b:Int)=>a+b, Seconds(30), Seconds(10)).print()
//启动流式计算
ssc.start()
ssc.awaitTermination()
}
}
reduceByKeyAndWindow中有俩个时间,Seconds(30)是窗口的大小,Second(10)是窗口滑动的时间,也是多长时间计算一次。和上边Second(2)的关系是,Second(2)是负责采样连续的数据形成离散的RDD的DStream,但不是说采样完了就立马计算,是过Second(10)时间才计算,而且计算的是当前往后的30s采样的数据。这样在窗口滑动的过程中,其实有重叠的部分