一 背景

Spark社区为Spark Streaming提供了很多数据源接口,但是有些比较偏的数据源没有覆盖,由于公司技术栈选择,用了阿里云的MQ服务ONS,要做实时需求,要自己编写Receiver

二 技术实现

1.官网的例子已经比较详细,但是进入实践还需要慢慢调试,官方文档

2.实现代码,由三部分组成,receiver,inputstream,util

3.receiver代码

import java.io.Serializable
import java.util.Properties import com.aliyun.openservices.ons.api._
import com.aliyun.openservices.ons.api.impl.ONSFactoryImpl
import org.apache.spark.internal.Logging
import org.apache.spark.storage.StorageLevel
import org.apache.spark.streaming.receiver.Receiver class OnsReceiver(
cid: String,
accessKey: String,
secretKey: String,
addr: String,
topic: String,
tag: String,
func: Message => Array[Byte])
extends Receiver[Array[Byte]](StorageLevel.MEMORY_AND_DISK_2) with Serializable with Logging {
receiver => private var consumer: Consumer = null
private var workerThread: Thread = null override def onStart(): Unit = {
workerThread = new Thread(new Runnable {
override def run(): Unit = {
val properties = new Properties
properties.put(PropertyKeyConst.ConsumerId, cid)
properties.put(PropertyKeyConst.AccessKey, accessKey)
properties.put(PropertyKeyConst.SecretKey, secretKey)
properties.put(PropertyKeyConst.ONSAddr, addr)
properties.put(PropertyKeyConst.MessageModel, "CLUSTERING")
properties.put(PropertyKeyConst.ConsumeThreadNums, "50")
val onsFactoryImpl = new ONSFactoryImpl
consumer = onsFactoryImpl.createConsumer(properties)
consumer.subscribe(topic, tag, new MessageListener() {
override def consume(message: Message, context: ConsumeContext): Action = {
try {
receiver.store(func(message))
Action.CommitMessage
} catch {
case e: Throwable => e.printStackTrace()
Action.ReconsumeLater
}
}
})
consumer.start()
}
})
workerThread.setName(s"Aliyun ONS Receiver $streamId")
workerThread.setDaemon(true)
workerThread.start()
} override def onStop(): Unit = {
if (workerThread != null) {
if (consumer != null) {
consumer.shutdown()
} workerThread.join()
workerThread = null
logInfo(s"Stopped receiver for streamId $streamId")
}
}
}

input代码

import com.aliyun.openservices.ons.api.Message
import org.apache.spark.streaming.StreamingContext
import org.apache.spark.streaming.dstream.ReceiverInputDStream
import org.apache.spark.streaming.receiver.Receiver class OnsInputDStream(
@transient _ssc: StreamingContext,
cid: String,
topic: String,
tag: String,
accessKey: String,
secretKey: String,
addr:String,
func: Message => Array[Byte]
) extends ReceiverInputDStream[Array[Byte]](_ssc) { override def getReceiver(): Receiver[Array[Byte]] = {
new OnsReceiver(cid,accessKey,secretKey,addr,topic,tag,func)
} }

util代码

import com.aliyun.openservices.ons.api.Message
import org.apache.spark.annotation.Experimental
import org.apache.spark.streaming.StreamingContext
import org.apache.spark.streaming.dstream.{DStream, ReceiverInputDStream} object OnsUtils {
@Experimental
def createStream(
ssc: StreamingContext,
cid: String,
topic: String,
tag: String,
accessKey: String,
secretKey: String,
addr: String,
func: Message => Array[Byte]): ReceiverInputDStream[Array[Byte]] = {
new OnsInputDStream(ssc, cid, topic, tag, accessKey, secretKey, addr, func)
} @Experimental
def createStreams(
ssc: StreamingContext,
consumerIdTopicTags: Array[(String, String, String)],
accessKey: String,
secretKey: String,
addr: String,
func: Message => Array[Byte]): DStream[Array[Byte]] = {
val invalidTuples1 = consumerIdTopicTags.groupBy(e => (e._1, e._2)).filter(e => e._2.length > 1)
val invalidTuples2 = consumerIdTopicTags.map(e => (e._1, e._2)).groupBy(e => e._1).filter(e => e._2.length > 1)
if (invalidTuples1.size > 1 || invalidTuples2.size > 1) {
throw new RuntimeException("Inconsistent consumer subscription.")
} else {
ssc.union(consumerIdTopicTags.map({
case (consumerId, topic, tags) =>
createStream(ssc, consumerId, topic, tags, accessKey, secretKey, addr, func)
}))
}
} }

三 调用

val stream = (0 until 3).map(i => {
OnsUtils.createStream(ssc,
"CID",
"BI_CALL",
"call_log_ons",
config.getString("ons.access_key"),
config.getString("ons.sercet_key"),
config.getString("ons.ons_addr"),
func)
})
val unionStream = ssc.union(stream).foreachRDD(...)

stream可以决定设置多少个receiver,这个数量必须小于等于spark on yarn的num-executors,内存默认占用executors的内存的一半。

Spark Streaming自定义Receiver的更多相关文章

  1. spark Streaming的Receiver和Direct的优化对比

    Direct 1.简化并行读取:如果要读取多个partition,不需要创建多个输入DStream然后对它们进行union操作.Spark会创建跟Kafka partition一样多的RDD part ...

  2. spark streaming 3: Receiver 到 submitJobSet

     对于spark streaming来说,receiver是数据的源头.spark streaming的框架上,将receiver替换spark-core的以磁盘为数据源的做法,但是数据源(如监听某个 ...

  3. Spark Streaming自定义Receivers

    自定义一个Receiver class SocketTextStreamReceiver(host: String, port: Int( extends NetworkReceiver[String ...

  4. 9. Spark Streaming技术内幕 : Receiver在Driver的精妙实现全生命周期彻底研究和思考

        原创文章,转载请注明:转载自 听风居士博客(http://www.cnblogs.com/zhouyf/)       Spark streaming 程序需要不断接收新数据,然后进行业务逻辑 ...

  5. 4. Spark Streaming解析

    4.1 初始化StreamingContext import org.apache.spark._ import org.apache.spark.streaming._ val conf = new ...

  6. Spark Streaming Backpressure分析

    1.为什么引入Backpressure 默认情况下,Spark Streaming通过Receiver以生产者生产数据的速率接收数据,计算过程中会出现batch processing time > ...

  7. Spark Streaming性能优化: 如何在生产环境下应对流数据峰值巨变

    1.为什么引入Backpressure 默认情况下,Spark Streaming通过Receiver以生产者生产数据的速率接收数据,计算过程中会出现batch processing time > ...

  8. 【Streaming】30分钟概览Spark Streaming 实时计算

    本文主要介绍四个问题: 什么是Spark Streaming实时计算? Spark实时计算原理流程是什么? Spark 2.X下一代实时计算框架Structured Streaming Spark S ...

  9. 第12课:Spark Streaming源码解读之Executor容错安全性

    一.Spark Streaming 数据安全性的考虑: Spark Streaming不断的接收数据,并且不断的产生Job,不断的提交Job给集群运行.所以这就涉及到一个非常重要的问题数据安全性. S ...

随机推荐

  1. JavaScript 操作 DOM 总结

    基本概念 DOM 是 JavaScript 操作网页的接口,全称为"文档对象模型"(Document Object Model).它的作用是将网页转为一个 JavaScript 对 ...

  2. Docker-CE 安装(centos7)

    配置yum源 > cd /etc/yum.repos.d/ > mkdir repo_bak > mv *.repo repo_bak/ > wget http://mirro ...

  3. (Demo分享)利用原生JavaScript-随机数-实现做一个烟花案例

    原生js实现放烟花效果,点击鼠标,然后随机向四周扩散,! 思路: 1.首先烟花是五颜六色的,所以我们先写一个随机颜色的函数: 2.创建一个制造烟花的构造函数,第一个参数为元素,第二参数为初始x轴位置, ...

  4. node中websocket的使用

    web Socket和Socket.IO框架 http协议是无状态的,就是说客户端可以给服务器提交请求,但是服务器不能向客户端提交请求,但是我们实际项目中会要求客户和服务器双方是类似电话那种关系, 一 ...

  5. PATA 1027 Colors In Mars

    #include <cstdio> char radix[13] = {'0','1','2','3','4','5','6','7','8','9','A','B','C'}; int ...

  6. SHELL 中条件语句的运用 if for 条件测试语句

    if条件测试语句可以让脚本根据实际情况自动执行相应的命令.从技术角度来讲,if语句分为单分支结构.双分支结构.多分支结构:其复杂度随着灵活度一起逐级上升. if条件语句的单分支结构由if.then.f ...

  7. 03_javaSE面试题:类初始化和实例初始化

    题目 下面代码运行的结果是什么? Father 类 /** * @author kevin * @date 2019/7/8 15:48 */ public class Father { privat ...

  8. linux 多主机间快速跳转脚本

    #!/usr/bin/env python #coding=utf8 ''' 用于多机器间相互跳转,如有新机器加入,需要更新ip_list文件 ''' from prettytable import ...

  9. 十分钟教你理解TypeScript中的泛型

    转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者.原文出处:https://blog.bitsrc.io/understanding-generics-in-t ...

  10. Ubuntu 16.4-desktop系统安装显卡CUDA具体步骤!

    1.禁用nouveau驱动(切换至tty界面) sudo vim /etc/modprobe.d/blacklist.conf 在文本最后添加:blacklist nouveau options no ...