Spark Streaming数据限流简述
Spark Streaming对实时数据流进行分析处理,源源不断的从数据源接收数据切割成一个个时间间隔进行处理;
流处理与批处理有明显区别,批处理中的数据有明显的边界、数据规模已知;而流处理数据流并没有边界,也未知数据规模;
由于流处理的数据流特征,使之数据流具有不可预测性,而且数据处理的速率还与硬件、网络等资源有关,在这种情况下如不对源源不断进来的数据流速率进行限制,那当Spark节点故障、网络故障或数据处理吞吐量下来时还有数据不断流进来,那将有可能将出现OOM进而导致Spark Streaming程序崩溃;
在Spark Streaming中不同的数据源采用不同的限速策略,但无论是Socket数据源的限流策略还是Kafka数据源的限流策略其速率(rate)的计算都是使用PIDController算法进行计算而得来;
下面从源码的角度分别介绍Socket数据源与Kafka数据源的限流处理。
速率限制的计算与更新
Spark Streaming的流处理其实是基于微批处理(MicroBatch)的,也就是说将数据流按某比较小的时间间隔将数据切割成为一段段微批数据进行处理;

StreamingContext调用Start()启动的时候会将速率控制器(rateController)添加到StreamingListener监听器中;
当每批次处理完成时将触发监听器(RateController),使用该批处理的处理结束时间、处理延迟时间、调度延迟时间、记录行数调用PIDRateEstimator传入PID算法中(PID Controller)计算出该批次的速率(rate)并更新速率限制(rateLimit)与发布该限制速率;
override def onBatchCompleted(batchCompleted: StreamingListenerBatchCompleted) {
val elements = batchCompleted.batchInfo.streamIdToInputInfo
for {
processingEnd <- batchCompleted.batchInfo.processingEndTime
workDelay <- batchCompleted.batchInfo.processingDelay
waitDelay <- batchCompleted.batchInfo.schedulingDelay
elems <- elements.get(streamUID).map(_.numRecords)
} computeAndPublish(processingEnd, elems, workDelay, waitDelay)
}
private def computeAndPublish(time: Long, elems: Long, workDelay: Long, waitDelay: Long): Unit =
Future[Unit] {
val newRate = rateEstimator.compute(time, elems, workDelay, waitDelay)
newRate.foreach { s =>
rateLimit.set(s.toLong)
publish(getLatestRate())
}
}
Socket数据源限流
批次的限制速率上面已经算出,这里说的是接收Socket过来的数据时的数据限流;
SocketInputStream类receive方法接收到数据后将数据存入 BlockGenerator的Buffer中,在写入Buffer前调用限流器 (RateLimiter)对写入数据进行限流;
RateLimiter限流器使用了Google开源的 Guava中内置的RateLimiter限流器,该类只是对Guava限流器的简单封装;
在Spark Streaming中可通过使用两个参数配置初始速率与最大速率spark.streaming.receiver.maxRate、spark.streaming.backpressure.initialRate;亦可配置PIDController算法相关的四个参数值;
RateLimiter限流器是基于令牌桶的算法基本原理比较简单,以一个恒定的速率生成令牌放入令牌桶中,桶满则停止,处理请求时需要从令牌桶中取出令牌,当桶中无令牌可取时阻塞等待,此算法用于确保系统不被洪峰击垮。
private lazy val rateLimiter = GuavaRateLimiter.create(getInitialRateLimit().toDouble)
/**
* Push a single data item into the buffer.
*/
def addData(data: Any): Unit = {
if (state == Active) {
//调用限流器等待
waitToPush()
synchronized {
if (state == Active) {
currentBuffer += data
} else {
throw new SparkException(
"Cannot add data as BlockGenerator has not been started or has been stopped")
}
}
} else {
throw new SparkException(
"Cannot add data as BlockGenerator has not been started or has been stopped")
}
}
def waitToPush() {
//限流器申请令牌
rateLimiter.acquire()
}
Guava库中RateLimiter限流器基本使用:
//创建限流器,每秒产生令牌数1
RateLimiter rateLimiter=RateLimiter.create(1);
for (int i = 0; i < 10; i++) {
//获得一个令牌,未申请到令牌则阻塞等待
double waitTime = rateLimiter.acquire();
System.out.println(String.format("id:%d time:%d waitTime:%f",i,System.currentTimeMillis(),waitTime));
}
Kafka数据源限流的实现
在Spark Streaming Kafka包拉取Kafka数据会进行如下动作:
1、取Kafka中最新偏移量、分区
2、通过rateController限制每个分区可拉取的最大消息数
3、在DirectKafkaInputDStream中创建KafkaRDD,在其中调用相关对象拉取数据
通过如上步骤也可用看出,只要限制了Kafka某个分区的偏移量(offset)范围也就可限制从Kafka拉取的消息数量,从而达到限流的目的,Spark streaming kafka也是通过此实现的;
计算每个分区速率限制,有如下步骤:
1、通过seekToEnd获取最新可用偏移量与当前偏移量对比获得当前所有分区延迟偏移量
单个分区偏移量延迟=最新偏移量记录-当前偏移量记录
2、获取配置项中每个分区最大速率
(spark.streaming.kafka.maxRatePerPartition),背压率计算,计算每个分区背压率计算公式为:
单个分区背压率=单个分区偏移量延迟/所有分区总延迟*速率限制
速率限制(rateLimit):为通过PIDController动态计算得来
如有配置每个分区最大速率则取配置项最大速率与背压率两者中的最小值,未配置则取背压率作为每个分区速率限制;
3、将批次间隔(batchDuration)*每个分区速率限制=每个分区最大消息数
4、取当前分区偏移量+分区最大消息数 与 最新偏移量两者当中最小的,由此来控制拉取消息速率;
如当前偏移量+分区最大消息数 大于 最新偏移量则取 最新偏移量否则取 当前偏移量+分区最大消息数作为拉取Kafka数据的Offset范围;
// 限制每个分区最大消息数
protected def clamp(
offsets: Map[TopicPartition, Long]): Map[TopicPartition, Long] = {
maxMessagesPerPartition(offsets).map { mmp =>
mmp.map { case (tp, messages) =>
val uo = offsets(tp)
tp -> Math.min(currentOffsets(tp) + messages, uo)
}
}.getOrElse(offsets)
}
不管是Kafka数据源还是Socket数据源Spark Streaming中都使用了PIDController算法用于计算其速率限制值,两者的差别也只是因为两种数据源的获取方式数据特征而决定的。Socket数据源使用了Guava RateLimiter、而Kafka数据源自己实现了基于Offsets的限流;
以上说介绍的框架版本为:Spark Streaming 版本为2.3.2与spark-streaming-kafka-0-10_2.11;
参考资料:
http://kafka.apache.org
http://spark.apache.org
文章首发地址:Solinx
https://mp.weixin.qq.com/s/yHStZgTAGBPoOMpj4e27Jg
Spark Streaming数据限流简述的更多相关文章
- Spark Streaming:大规模流式数据处理的新贵(转)
原文链接:Spark Streaming:大规模流式数据处理的新贵 摘要:Spark Streaming是大规模流式数据处理的新贵,将流式计算分解成一系列短小的批处理作业.本文阐释了Spark Str ...
- Spark Streaming:大规模流式数据处理的新贵
转自:http://www.csdn.net/article/2014-01-28/2818282-Spark-Streaming-big-data 提到Spark Streaming,我们不得不说一 ...
- Spark Streaming 数据接收过程
SparkStreaming 源码分析 一节中从源码角度,描述了Streaming执行时代码的调用过程.下边就接收转化阶段过程再简单分析一下,为分析backpressure作准备. SparkStre ...
- Spark Streaming数据清理内幕彻底解密
本讲从二个方面阐述: 数据清理原因和现象 数据清理代码解析 Spark Core从技术研究的角度讲 对Spark Streaming研究的彻底,没有你搞不定的Spark应用程序. Spark Stre ...
- Spark Streaming源码解读之流数据不断接收全生命周期彻底研究和思考
本期内容 : 数据接收架构设计模式 数据接收源码彻底研究 一.Spark Streaming数据接收设计模式 Spark Streaming接收数据也相似MVC架构: 1. Mode相当于Rece ...
- Kafka:ZK+Kafka+Spark Streaming集群环境搭建(二十二)Spark Streaming接收流数据及使用窗口函数
官网文档:<http://spark.apache.org/docs/latest/streaming-programming-guide.html#a-quick-example> Sp ...
- Spark Streaming源码解读之流数据不断接收和全生命周期彻底研究和思考
本节的主要内容: 一.数据接受架构和设计模式 二.接受数据的源码解读 Spark Streaming不断持续的接收数据,具有Receiver的Spark 应用程序的考虑. Receiver和Drive ...
- 大数据技术之_19_Spark学习_04_Spark Streaming 应用解析 + Spark Streaming 概述、运行、解析 + DStream 的输入、转换、输出 + 优化
第1章 Spark Streaming 概述1.1 什么是 Spark Streaming1.2 为什么要学习 Spark Streaming1.3 Spark 与 Storm 的对比第2章 运行 S ...
- Dream_Spark-----Spark 定制版:005~贯通Spark Streaming流计算框架的运行源码
Spark 定制版:005~贯通Spark Streaming流计算框架的运行源码 本讲内容: a. 在线动态计算分类最热门商品案例回顾与演示 b. 基于案例贯通Spark Streaming的运 ...
随机推荐
- JS将扁平化的数据处理成Tree结构
let jsonData= [ { id:1, parentId:0, name:"一级菜单A" }, { id:2, parentId:0, name:"一级菜单B& ...
- v-charts x轴字体斜显示
如下图,因为X轴内容太多,放不下,插件默认间隔显示需求:X轴内容要全部显示出来(只有斜显示或固定宽多余的用省略代替,本来需要就是想显示全部内容,所以只能取斜显示的方案) 先看看v-charts的文档: ...
- toj 3616 Add number (没想到啊~~)
Add number 时间限制(普通/Java):1000MS/3000MS 运行内存限制:65536KByte总提交: 60 测试通过: 21 描述 Employees of Baidu like ...
- vue垂死挣扎系列(一)——vue-cli快速搭建
项目安装(windows10安装环境+vue-cli 2.x) 安装node 在官网上下载稳定版本的node node.js官网 一路傻瓜安装 测试是否安装成功 cmd中node --version ...
- 万科A顺利出局,布局一心堂
万科的这两日的走势还不错,今日冲高回落,顺利出局. 那么有选中了一只 股票 一心堂 资金量W 12 建仓价格 22.2 加仓系数 1.5 加仓间隔 1.50% 总盈利比 ...
- opencv —— minEnclosingCircle、fitEllipse 寻找包裹轮廓的最小圆、点集拟合椭圆
寻找包裹轮廓的最小圆:minEnclosingCircle 函数 返回圆应满足:① 轮廓上的点均在圆形空间内.② 没有面积更小的满足条件的圆. void minEnclosingCircle(Inpu ...
- Excel——排序筛选
1,自定义排序:多个关键字,从右向左一一排序 * 按颜色排序 * 按自定义序列排序 *两列中,列一个中间数,升序 * 打印标题行 * 选中,定位条件(可见),选择 * 数值筛选(大于等于),文本筛选( ...
- Anaconda 包管理与环境管理
包管理命令 conda命令 安装包 conda install 包名称 卸载包 conda remove 包名称 更新包 conda update 包名称 模糊查询 conda search 包名称 ...
- Mysql字符串截取,去掉时间,匹配日期等于今日
Mysql字符串截取,去掉时间,匹配日期等于今日 方案一 select time from jsb where date(time)=date(now()); 方案二 ));
- 【Git】git使用 - rebase的使用
官方参考指南: Pro Git Book v2, § rebasing. English Pro Git Book v2, § rebase:衍合. 中文版 (建议还是看一下英文原版,就当熟练英语.) ...