spark streaming流式计算---监听器
随着对spark的了解,有时会觉得spark就像一个宝盒一样时不时会出现一些难以置信的新功能。每一个新功能被挖掘,就可以使开发过程变得更加便利一点。甚至使很多不可能完成或者完成起来比较复杂的操作,变成简单起来。有些功能是框架专门开放给用户使用,有些则是框架内部使用但是又对外暴露了接口,用户也可以使用的功能。
今天和大家分享的是两个监听器SparkListener和streamingListener,由于这两个监听器的存在使得很多功能的开发变得轻松很多,也使很多技术实现变得轻便很多。
结合我的使用经验,这两个监听器主要可以如下两种用法:
1. 可以获取我们在sparkUI上的任何指标。当你想获取指标并且想做监控预警或者打算重构sparkUI,那你不需要再通过爬虫解析复杂的网页代码就可以获取sparkUI上的各种指标。
2. 对spark任务的各种事件做相应的操作,嵌入回调代码。
比如:你可以在sparkListener中的onApplicationStart方法中做driver端的第三方框架的连接池初始化(连接仅限driver端使用)以及其他变量的初始化,并放置到公共对象中,driver端直接就可以使用。且在onApplicaionComple方法中做连接的释放工作,以及变量的收集持久化操作,以次达到隐藏变量初始化的操作,冰做成公共jar包供其它人使用。
又如:你可以在StreamingListener的onbatchStart操作中获取kafka读取的offset位置以及读取数据条数,在onBatchCompl方法中将这些offset信息保存到mysql/zk中,达到优雅隐藏容错代码的目的。同样可以做成公共jar共其他项目使用。
等等这些都是一些非常酷炫的操作,当然还会有其他的酷炫的使用场景还在等待着你去挖掘。
性能分析
在使用过程中,大家可能比较关系另外一个问题:指标收集,会对流式计算性能产生多大的影响?
答案就是,在指标收集这一块,对于流式计算或者spark core产生的影响会很小。因为即使你不收集SparkUI也会收集,这些指标一样会生成。只是对于driver端的开销会稍微变大,如果在流式计算场景可能需要你调大driver端的cpu和内存
一 .自定义Listener 并注册(伪代码如下):
val spark:SparkSession=null
val ssc:StreamingContext=null
/*注册streamingListnener*/
ssc.addStreamingListener(new MyStreamingListener)
/*注册sparkListener*/
spark.sparkContext.addSparkListener(new MySparkListener)
/*自定义streamingListener*/
class MyStreamingListener extends StreamingListener{ //TODO 重载内置方法 }
/*自定义SparkListnener*/
class MySparkListener extends SparkListener { //TODO 重载内置方法 }
二.SparkListener内置方法讲解
通过如下重写的方法可以发现,你可以通过这个SparkListener对App,job,stage,task,executor,blockManager等产生的指标进行实时的收集,并在这些事件触发时嵌入一些代码,可以达到当某些指标达到警戒阈值触发自定义的一些规则。如下已经列出了获取的spark级别指标和事件回调函数,下一节会列出streaming的性能监控点以及收集的指标。
class MySparkListener extends SparkListener {
/*当整个应用开始执行时*/
override def onApplicationStart(applicationStart: SparkListenerApplicationStart): Unit={
/*获取appID-->spark on yarn模式下的appID一致*/
applicationStart.appId
/*appName*/
applicationStart.appName
/*driver端的日志,如果配置了日志的截断机制,获取的将不是完整日志*/
applicationStart.driverLogs
/*提交的用户*/
applicationStart.sparkUser
/*开始的事件*/
applicationStart.time
}
/*当整个Application结束时调用的回调函数*/
override def onApplicationEnd(applicationEnd: SparkListenerApplicationEnd): Unit = {
/*结束的时间*/
applicationEnd.time
}
/*当job开始执行时触发的回调函数*/
override def onJobStart(jobStart: SparkListenerJobStart): Unit = {
/*jobId和SParkUI上的一致*/
jobStart.jobId
/*配置信息*/
jobStart.properties
/*当前job根据宽窄依赖生成的所有strageID*/
jobStart.stageIds
/*job开始的时间*/
jobStart.time
jobStart.properties
/*当前job每一个stage的信息抽象*/
jobStart.stageInfos.foreach(stageInfo => {
stageInfo.stageId
/*stage提交的时间,不是task开始执行的时间,这个时间是stage开始抽象成taskDesc的开始时间*/
stageInfo.submissionTime
/*这个stage完成的时间*/
stageInfo.completionTime
/*当前stage发成了错误会重试,重试会在stageID后加上“_重试次数”*/
stageInfo.attemptId
/*当前staget的详细信息*/
stageInfo.details
/*当前stage累加器的中间结果*/
stageInfo.accumulables
/*如果当前stage失败,返回失败原因,如果做日志预警,可以在此处判断非空并嵌入代码收集错误日志*/
stageInfo.failureReason
stageInfo.name
/*当前stage抽象出的taskSet的长度*/
stageInfo.numTasks
/*父依赖stage的id*/
stageInfo.parentIds
stageInfo.rddInfos
/*task指标收集*/
stageInfo.taskMetrics
stageInfo.taskLocalityPreferences
stageInfo.stageFailed("")
})
}
/*当job结束时触发的回调函数*/
override def onJobEnd(jobEnd: SparkListenerJobEnd): Unit = {
jobEnd.jobId
jobEnd.time
jobEnd.jobResult
}
/*当提交stage时触发的回调函数*/
override def onStageSubmitted(stageSubmitted: SparkListenerStageSubmitted): Unit = {
stageSubmitted.properties
stageSubmitted.stageInfo.taskLocalityPreferences
stageSubmitted.stageInfo.stageFailed("")
stageSubmitted.stageInfo.attemptId
stageSubmitted.stageInfo.taskMetrics.executorDeserializeTime
stageSubmitted.stageInfo.taskMetrics.executorDeserializeCpuTime
stageSubmitted.stageInfo.taskMetrics.executorCpuTime
stageSubmitted.stageInfo.taskMetrics.diskBytesSpilled
stageSubmitted.stageInfo.taskMetrics.inputMetrics.recordsRead
stageSubmitted.stageInfo.taskMetrics.inputMetrics.bytesRead
stageSubmitted.stageInfo.taskMetrics.outputMetrics.recordsWritten
stageSubmitted.stageInfo.taskMetrics.outputMetrics.bytesWritten
stageSubmitted.stageInfo.taskMetrics.shuffleReadMetrics.totalBytesRead
stageSubmitted.stageInfo.taskMetrics.shuffleReadMetrics.recordsRead
stageSubmitted.stageInfo.taskMetrics.shuffleReadMetrics.fetchWaitTime
stageSubmitted.stageInfo.taskMetrics.shuffleReadMetrics.localBlocksFetched
stageSubmitted.stageInfo.taskMetrics.shuffleReadMetrics.localBytesRead
stageSubmitted.stageInfo.taskMetrics.shuffleReadMetrics.remoteBlocksFetched
stageSubmitted.stageInfo.taskMetrics.shuffleWriteMetrics.bytesWritten
stageSubmitted.stageInfo.taskMetrics.shuffleWriteMetrics.recordsWritten
stageSubmitted.stageInfo.taskMetrics.shuffleWriteMetrics.writeTime
stageSubmitted.stageInfo.taskMetrics.executorRunTime
stageSubmitted.stageInfo.taskMetrics.jvmGCTime
stageSubmitted.stageInfo.taskMetrics.memoryBytesSpilled
stageSubmitted.stageInfo.taskMetrics.peakExecutionMemory
stageSubmitted.stageInfo.taskMetrics.resultSerializationTime
stageSubmitted.stageInfo.taskMetrics.resultSize
stageSubmitted.stageInfo.taskMetrics.updatedBlockStatuses
stageSubmitted.stageInfo.rddInfos
stageSubmitted.stageInfo.parentIds
stageSubmitted.stageInfo.details
stageSubmitted.stageInfo.numTasks
stageSubmitted.stageInfo.name
stageSubmitted.stageInfo.accumulables
stageSubmitted.stageInfo.completionTime
stageSubmitted.stageInfo.submissionTime
stageSubmitted.stageInfo.stageId
stageSubmitted.stageInfo.failureReason
}
/*当stage完成时触发的回调函数*/
override def onStageCompleted(stageCompleted: SparkListenerStageCompleted): Unit = {
stageCompleted.stageInfo.attemptId
stageCompleted.stageInfo.failureReason
stageCompleted.stageInfo.stageId
stageCompleted.stageInfo.submissionTime
stageCompleted.stageInfo.completionTime
stageCompleted.stageInfo.accumulables
stageCompleted.stageInfo.details
stageCompleted.stageInfo.name
stageCompleted.stageInfo.numTasks
stageCompleted.stageInfo.parentIds
stageCompleted.stageInfo.rddInfos
stageCompleted.stageInfo.taskMetrics
stageCompleted.stageInfo.stageFailed()
stageCompleted.stageInfo.taskLocalityPreferences
}
/*当task开始时触发的回调函数*/
override def onTaskStart(taskStart: SparkListenerTaskStart): Unit = {
taskStart.stageAttemptId
taskStart.stageId
taskStart.taskInfo.executorId
taskStart.taskInfo.taskId
taskStart.taskInfo.finishTime
taskStart.taskInfo.launchTime
taskStart.taskInfo.accumulables
taskStart.taskInfo.attemptNumber
taskStart.taskInfo.failed
taskStart.taskInfo.gettingResultTime
taskStart.taskInfo.gettingResult
taskStart.taskInfo.executorId
taskStart.taskInfo.host
taskStart.taskInfo.index
taskStart.taskInfo.killed
taskStart.taskInfo.speculative
taskStart.taskInfo.taskLocality
taskStart.taskInfo.duration
taskStart.taskInfo.finished
taskStart.taskInfo.id
taskStart.taskInfo.running
taskStart.taskInfo.successful
taskStart.taskInfo.status
}
/*获取task执行的结果*/
override def onTaskGettingResult(taskGettingResult: SparkListenerTaskGettingResult): Unit = {
taskGettingResult.taskInfo
}
/*当task执行完成时执行的回调函数*/
override def onTaskEnd(taskEnd: SparkListenerTaskEnd): Unit = {
taskEnd.taskMetrics.resultSize
taskEnd.taskMetrics.updatedBlockStatuses
taskEnd.taskMetrics.resultSerializationTime
taskEnd.taskMetrics.peakExecutionMemory
taskEnd.taskMetrics.memoryBytesSpilled
taskEnd.taskMetrics.jvmGCTime
taskEnd.taskMetrics.executorRunTime
taskEnd.taskMetrics.shuffleWriteMetrics
taskEnd.taskMetrics.shuffleReadMetrics
taskEnd.taskMetrics.outputMetrics
taskEnd.taskMetrics.inputMetrics
taskEnd.taskMetrics.diskBytesSpilled
taskEnd.taskMetrics.executorCpuTime
taskEnd.taskMetrics.executorDeserializeCpuTime
taskEnd.taskMetrics.executorDeserializeTime
taskEnd.taskInfo.executorId
taskEnd.taskInfo.host
taskEnd.taskInfo.index
taskEnd.taskInfo.killed
taskEnd.taskInfo.speculative
taskEnd.taskInfo.taskLocality
taskEnd.taskInfo.duration
taskEnd.taskInfo.finished
taskEnd.taskInfo.taskId
taskEnd.taskInfo.id
taskEnd.taskInfo.running
taskEnd.stageId
taskEnd.reason
taskEnd.stageAttemptId
taskEnd.taskType
}
/*新增bockManger时触发的回调函数*/
override def onBlockManagerAdded(blockManagerAdded: SparkListenerBlockManagerAdded): Unit = {
blockManagerAdded.blockManagerId.executorId
blockManagerAdded.blockManagerId.host
blockManagerAdded.blockManagerId.port
blockManagerAdded.blockManagerId.topologyInfo
blockManagerAdded.blockManagerId.hostPort
blockManagerAdded.blockManagerId.isDriver
blockManagerAdded.maxMem
blockManagerAdded.time
}
/*当blockManage中管理的内存或者磁盘发生变化时触发的回调函数*/
override def onBlockUpdated(blockUpdated: SparkListenerBlockUpdated): Unit = {
blockUpdated.blockUpdatedInfo.blockId
blockUpdated.blockUpdatedInfo.blockManagerId
blockUpdated.blockUpdatedInfo.diskSize
blockUpdated.blockUpdatedInfo.memSize
blockUpdated.blockUpdatedInfo.storageLevel
}
/*当blockManager回收时触发的回调函数*/
override def onBlockManagerRemoved(blockManagerRemoved: SparkListenerBlockManagerRemoved): Unit = {
blockManagerRemoved.blockManagerId
blockManagerRemoved.time
}
/*当 上下文环境发生变化是触发的回调函数*/
override def onEnvironmentUpdate(environmentUpdate: SparkListenerEnvironmentUpdate): Unit = {
environmentUpdate.environmentDetails
}
/*当RDD发生unpersist时发生的回调函数*/
override def onUnpersistRDD(unpersistRDD: SparkListenerUnpersistRDD): Unit = {
unpersistRDD.rddId
}
override def onOtherEvent(event: SparkListenerEvent): Unit = {
}
/*当新增一个executor时触发的回调函数*/
override def onExecutorAdded(executorAdded: SparkListenerExecutorAdded): Unit = {
executorAdded.executorId
executorAdded.executorInfo.executorHost
executorAdded.executorInfo.logUrlMap
executorAdded.executorInfo.totalCores
executorAdded.time
}
/*当executor发生变化时触发的回调函数*/
override def onExecutorMetricsUpdate(executorMetricsUpdate: SparkListenerExecutorMetricsUpdate): Unit = {
executorMetricsUpdate.accumUpdates
executorMetricsUpdate.execId
}
/*当移除一个executor时触发的回调函数*/
override def onExecutorRemoved(executorRemoved: SparkListenerExecutorRemoved): Unit = {
executorRemoved.executorId
executorRemoved.reason
executorRemoved.time
}
}
三.StreamingListener内置方法讲解
class MyStreamingListener extends StreamingListener {
/*流式计算开始时,触发的回调函数*/
override def onStreamingStarted(streamingStarted: StreamingListenerStreamingStarted): Unit = {
streamingStarted.time
}
/*当前batch提交时触发的回调函数*/
override def onBatchSubmitted(batchSubmitted: StreamingListenerBatchSubmitted): Unit = {
batchSubmitted.batchInfo.streamIdToInputInfo.foreach(tuple=>{
val streamInputInfo = tuple._2
streamInputInfo.metadata
streamInputInfo.numRecords
streamInputInfo.inputStreamId
streamInputInfo.metadataDescription
})
batchSubmitted.batchInfo.numRecords
batchSubmitted.batchInfo.outputOperationInfos
batchSubmitted.batchInfo.submissionTime
batchSubmitted.batchInfo.batchTime
batchSubmitted.batchInfo.processingEndTime
batchSubmitted.batchInfo.processingStartTime
batchSubmitted.batchInfo.processingDelay
batchSubmitted.batchInfo.schedulingDelay
batchSubmitted.batchInfo.totalDelay
}
/*当前batch开始执行时触发的回调函数*/
override def onBatchStarted(batchStarted: StreamingListenerBatchStarted): Unit = {
batchStarted.batchInfo.totalDelay
batchStarted.batchInfo.schedulingDelay
batchStarted.batchInfo.processingDelay
batchStarted.batchInfo.processingStartTime
batchStarted.batchInfo.processingEndTime
batchStarted.batchInfo.batchTime
batchStarted.batchInfo.submissionTime
batchStarted.batchInfo.outputOperationInfos
batchStarted.batchInfo.numRecords
batchStarted.batchInfo.streamIdToInputInfo
}
/*当前batch完成时触发的回调函数*/
override def onBatchCompleted(batchCompleted: StreamingListenerBatchCompleted): Unit = {
batchCompleted.batchInfo.streamIdToInputInfo
batchCompleted.batchInfo.numRecords
batchCompleted.batchInfo.outputOperationInfos
batchCompleted.batchInfo.submissionTime
batchCompleted.batchInfo.batchTime
batchCompleted.batchInfo.processingEndTime
batchCompleted.batchInfo.processingStartTime
batchCompleted.batchInfo.processingDelay
batchCompleted.batchInfo.schedulingDelay
batchCompleted.batchInfo.totalDelay
/*获取offset,并持久化到第三方容器*/
batchCompleted.batchInfo.streamIdToInputInfo.foreach(tuple=>{
val offsets = tuple._2.metadata.get("offsets").get
classOf[List[OffsetRange]].cast(offsets).foreach(offsetRange => {
val partition = offsetRange.partition
val minOffset = offsetRange.fromOffset
val maxOffset = offsetRange.untilOffset
val topicName = offsetRange.topic
//TODO 将kafka容错信息,写到mysql/redis/zk等框架达到数据容错
} )
}
/*当接收器启动时触发的回调函数(非directStreaming)*/
override def onReceiverStarted(receiverStarted: StreamingListenerReceiverStarted): Unit = {
receiverStarted.receiverInfo.executorId
receiverStarted.receiverInfo.active
receiverStarted.receiverInfo.lastError
receiverStarted.receiverInfo.lastErrorMessage
receiverStarted.receiverInfo.location
receiverStarted.receiverInfo.name
receiverStarted.receiverInfo.streamId
receiverStarted.receiverInfo.lastErrorTime
}
/*当接收器结束时触发的回调函数(非directStreaming)*/
override def onReceiverStopped(receiverStopped: StreamingListenerReceiverStopped): Unit = {
receiverStopped.receiverInfo.lastErrorTime
receiverStopped.receiverInfo.lastError
receiverStopped.receiverInfo.streamId
receiverStopped.receiverInfo.name
receiverStopped.receiverInfo.location
receiverStopped.receiverInfo.lastErrorMessage
receiverStopped.receiverInfo.active
receiverStopped.receiverInfo.executorId
}
/*当接收器发生错误时触发的回调函数(非directStreaming)*/
override def onReceiverError(receiverError: StreamingListenerReceiverError): Unit = {
receiverError.receiverInfo.executorId
receiverError.receiverInfo.active
receiverError.receiverInfo.lastErrorMessage
receiverError.receiverInfo.lastError
receiverError.receiverInfo.location
receiverError.receiverInfo.name
receiverError.receiverInfo.streamId
receiverError.receiverInfo.lastErrorTime
}
/*当output开始时触发的回调函数*/
override def onOutputOperationStarted(outputOperationStarted: StreamingListenerOutputOperationStarted): Unit = {
outputOperationStarted.outputOperationInfo.description
outputOperationStarted.outputOperationInfo.batchTime
outputOperationStarted.outputOperationInfo.endTime
outputOperationStarted.outputOperationInfo.failureReason
outputOperationStarted.outputOperationInfo.id
outputOperationStarted.outputOperationInfo.name
outputOperationStarted.outputOperationInfo.startTime
outputOperationStarted.outputOperationInfo.duration
}
/*当output结束时触发的回调函数*/
override def onOutputOperationCompleted(outputOperationCompleted: StreamingListenerOutputOperationCompleted): Unit = {
outputOperationCompleted.outputOperationInfo.duration
outputOperationCompleted.outputOperationInfo.startTime
outputOperationCompleted.outputOperationInfo.name
outputOperationCompleted.outputOperationInfo.id
outputOperationCompleted.outputOperationInfo.failureReason
outputOperationCompleted.outputOperationInfo.endTime
outputOperationCompleted.outputOperationInfo.batchTime
outputOperationCompleted.outputOperationInfo.description
}
}
spark streaming流式计算---监听器的更多相关文章
- spark streaming 流式计算---跨batch连接池共享(JVM共享连接池)
在流式计算过程中,难免会连接第三方存储平台(redis,mysql...).在操作过程中,大部分情况是在foreachPartition/mapPartition算子中做连接操作.每一个分区只需要连接 ...
- Spark Streaming流式处理
Spark Streaming介绍 Spark Streaming概述 Spark Streaming makes it easy to build scalable fault-tolerant s ...
- Spark之 Spark Streaming流式处理
SparkStreaming Spark Streaming类似于Apache Storm,用于流式数据的处理.Spark Streaming有高吞吐量和容错能力强等特点.Spark Streamin ...
- 从Storm和Spark 学习流式实时分布式计算的设计
0. 背景 最近我在做流式实时分布式计算系统的架构设计,而正好又要参加CSDN博文大赛的决赛.本来想就写Spark源码分析的文章吧.但是又想毕竟是决赛,要拿出一些自己的干货出来,仅仅是源码分析貌似分量 ...
- 流式计算(一)-Java8Stream
大约各位看官君多少也听说了Storm/Spark/Flink,这些都是大数据流式处理框架.如果一条手机组装流水线上不同的人做不同的事,有的装电池,有的装屏幕,直到最后完成,这就是典型的流式处理.如果手 ...
- Dream_Spark-----Spark 定制版:005~贯通Spark Streaming流计算框架的运行源码
Spark 定制版:005~贯通Spark Streaming流计算框架的运行源码 本讲内容: a. 在线动态计算分类最热门商品案例回顾与演示 b. 基于案例贯通Spark Streaming的运 ...
- 【流处理】Kafka Stream-Spark Streaming-Storm流式计算框架比较选型
Kafka Stream-Spark Streaming-Storm流式计算框架比较选型 elasticsearch-head Elasticsearch-sql client NLPchina/el ...
- Storm:分布式流式计算框架
Storm是一个分布式的.高容错的实时计算系统.Storm适用的场景: Storm可以用来用来处理源源不断的消息,并将处理之后的结果保存到持久化介质中. 由于Storm的处理组件都是分布式的,而且处理 ...
- 流式计算新贵Kafka Stream设计详解--转
原文地址:https://mp.weixin.qq.com/s?__biz=MzA5NzkxMzg1Nw==&mid=2653162822&idx=1&sn=8c4611436 ...
随机推荐
- 七、Linux_端口、进程
Linux_端口.进程 1.查看所有端口 netstat -nlutp 2.停掉使用端口的进程,根据进程pid kill 1818 kill -9 1818 # 强制杀掉进程 3.根据进程名杀死进程: ...
- Linux之RHEL7root密码破解(三)
Linux系列root密码破解第三种方式,利用修改boot分区里的开机启动顺序来修改密码,即我们进入BIOS,修改boot启动顺序为CD-ROM: 接下来按F10保存退出 选择Troubleshoot ...
- APT 信息收集——shodan.io ,fofa.so、 MX 及 邮件。mx记录查询。censys.io查询子域名。
信息收集 目标是某特殊机构,外网结构简单,防护严密.经探测发现其多个子机构由一家网站建设公司建设. 对子域名进行挖掘,确定目标ip分布范围及主要出口ip. 很多网站主站的访问量会比较大.往往主站都是挂 ...
- 2019年牛客多校第一场 C题Euclidean Distance 暴力+数学
题目链接 传送门 题意 给你\(n\)个数\(a_i\),要你在满足下面条件下使得\(\sum\limits_{i=1}^{n}(a_i-p_i)^2\)最小(题目给的\(m\)只是为了将\(a_i\ ...
- LoadRunner 11的破解方法和license号
安装过程中遇到“命令行选项语法错误键入命令 \?获得帮助”2005的安装问题,可参考本文:http://www.cnblogs.com/lelexiong/p/8974149.html解决 破解方法: ...
- anyproxy学习4-Linux(Centos)搭建anyproxy环境
前言 anyproxy可以跨平台使用,前面第一篇是搭建在windows机器上,本篇讲如何在linux上搭建anyproxy环境,当然有mac的小伙伴也可以用mac去搭建一个环境. nodejs安装 a ...
- Python 爬虫js加密破解(四) 360云盘登录password加密
登录链接:https://yunpan.360.cn/mindex/login 这是一个md5 加密算法,直接使用 md5加密即可实现 本文讲解的是如何抠出js,运行代码 第一部:抓包 如图 第二步: ...
- c++输出中文乱码解决方案
问题的原因应该在cmd的编码和c++程序编码(源文件编码)的不同.cmd默认的是gbk编码,而我用的vs code默认是utf-8编码,因而在输出中文文本时会出现乱码. 但我也遇到了一个比较怪异的情况 ...
- web scraper——爬取知乎|微博用户数据模板【三】
前言 在这里呢,我就只给模板,不写具体的教程啦,具体的可以参考我之前写的博文. https://www.cnblogs.com/wangyang0210/p/10338574.html 模板 进入微博 ...
- 【Selenium-WebDriver实战篇】ScreenRecorder的实际输出路径设置(转)
参考:https://www.cnblogs.com/yongfeiuall/p/4134139.html 我们可以用以下方式在Selenium Webdriver中capture video. 基本 ...