此文已由做者岳猛受权网易云社区发布。
html
欢迎访问网易云社区,了解更多网易技术产品运营经验。java
基因而spark core的spark streaming架构。算法
Spark Streaming是将流式计算分解成一系列短小的批处理做业。这里的批处理引擎是Spark,也就是把Spark Streaming的输入数据按照batch size(如1秒)分红一段一段的数据(Discretized Stream),每一段数据都转换成Spark中的RDD(Resilient Distributed Dataset),而后将Spark Streaming中对DStream的Transformation操做变为针对Spark中对RDD的Transformation操做,将RDD经 过操做变成中间结果保存在内存中。整个流式计算根据业务的需求能够对中间的结果进行叠加,或者存储到外部设备。数据库
简而言之,Spark Streaming把实时输入数据流以时间片Δt (如1秒)为单位切分红块,Spark Streaming会把每块数据做为一个RDD,并使用RDD操做处理每一小块数据。每一个块都会生成一个Spark Job处理,而后分批次提交job到集群中去运行,运行每一个job的过程和真正的spark 任务没有任何区别。apache
负责job的调度编程
JobScheduler是SparkStreaming 全部Job调度的中心, JobScheduler的启动会致使ReceiverTracker和JobGenerator的启动。ReceiverTracker的启动致使运行在Executor端的Receiver启动而且接收数据,ReceiverTracker会记录Receiver接收到的数据meta信息。JobGenerator的启动致使每隔BatchDuration,就调用DStreamGraph生成RDD Graph,并生成Job。JobScheduler中的线程池来提交封装的JobSet对象(时间值,Job,数据源的meta)。Job中封装了业务逻辑,致使最后一个RDD的action被触发,被DAGScheduler真正调度在Spark集群上执行该Job。安全
负责Job的生成服务器
经过定时器每隔一段时间根据Dstream的依赖关系生一个一个DAG图。网络
负责数据的接收,管理和分配架构
ReceiverTracker在启动Receiver的时候他有ReceiverSupervisor,其实现是ReceiverSupervisorImpl, ReceiverSupervisor自己启动的时候会启动Receiver,Receiver不断的接收数据,经过BlockGenerator将数据转换成Block。定时器会不断的把Block数据经过BlockManager或者WAL进行存储,数据存储以后ReceiverSupervisorImpl会把存储后的数据的元数据Metadate汇报给ReceiverTracker,实际上是汇报给ReceiverTracker中的RPC实体ReceiverTrackerEndpoint,主要。
上图为spark on yarn 的cluster模式,Spark on Yarn启动后,由Spark AppMaster中的driver(在AM的里面会启动driver,主要是StreamingContext对象)把Receiver做为一个Task提交给某一个Spark Executor;Receive启动后输入数据,生成数据块,而后通知Spark AppMaster;Spark AppMaster会根据数据块生成相应的Job,并把Job的Task提交给空闲Spark Executor 执行。图中蓝色的粗箭头显示被处理的数据流,输入数据流能够是磁盘、网络和HDFS等,输出能够是HDFS,数据库等。对比Flink和spark streaming的cluster模式能够发现,都是AM里面的组件(Flink是JM,spark streaming是Driver)承载了task的分配和调度,其余container承载了任务的执行(Flink是TM,spark streaming是Executor),不一样的是spark streaming每一个批次都要与driver进行通讯来进行从新调度,这样延迟性远低于Flink。
图2.1 Spark Streaming程序转换为DStream Graph
图2.2 DStream Graph转换为RDD的Graph
Spark Core处理的每一步都是基于RDD的,RDD之间有依赖关系。下图中的RDD的DAG显示的是有3个Action,会触发3个job,RDD自下向上依 赖,RDD产生job就会具体的执行。从DSteam Graph中能够看到,DStream的逻辑与RDD基本一致,它就是在RDD的基础上加上了时间的依赖。RDD的DAG又能够叫空间维度,也就是说整个 Spark Streaming多了一个时间维度,也能够成为时空维度,使用Spark Streaming编写的程序与编写Spark程序很是类似,在Spark程序中,主要经过操做RDD(Resilient Distributed Datasets弹性分布式数据集)提供的接口,如map、reduce、filter等,实现数据的批处理。而在Spark Streaming中,则经过操做DStream(表示数据流的RDD序列)提供的接口,这些接口和RDD提供的接口相似。Spark Streaming把程序中对DStream的操做转换为DStream Graph,图2.1中,对于每一个时间片,DStream Graph都会产生一个RDD Graph;针对每一个输出操做(如print、foreach等),Spark Streaming都会建立一个Spark action;对于每一个Spark action,Spark Streaming都会产生一个相应的Spark job,并交给JobScheduler。JobScheduler中维护着一个Jobs队列, Spark job存储在这个队列中,JobScheduler把Spark job提交给Spark Scheduler,Spark Scheduler负责调度Task到相应的Spark Executor上执行,最后造成spark的job。
图2.3时间维度生成RDD的DAG
Y轴就是对RDD的操做,RDD的依赖关系构成了整个job的逻辑,而X轴就是时间。随着时间的流逝,固定的时间间隔(Batch Interval)就会生成一个job实例,进而在集群中运行。
基于spark 1.5的spark streaming源代码解读,基本架构是没怎么变化的。
支持从多种数据源获取数据,包括Kafk、Flume、Twitter、ZeroMQ、Kinesis 以及TCP sockets,从数据源获取数据以后,可使用诸如map、reduce、join和window等高级函数进行复杂算法的处理。最后还能够将处理结果 存储到文件系统,数据库和现场仪表盘。在“One Stack rule them all”的基础上,还可使用Spark的其余子框架,如集群学习、图计算等,对流数据进行处理。
Spark目前在EC2上已可以线性扩展到100个节点(每一个节点4Core),能够以数秒的延迟处理6GB/s的数据量(60M records/s),其吞吐量也比流行的Storm高2~5倍,图4是Berkeley利用WordCount和Grep两个用例所作的测试,在 Grep这个测试中,Spark Streaming中的每一个节点的吞吐量是670k records/s,而Storm是115k records/s。
Spark Streaming将流式计算分解成多个Spark Job,对于每一段数据的处理都会通过Spark DAG图分解,以及Spark的任务集的调度过程,其最小的Batch Size的选取在0.5~2秒钟之间(Storm目前最小的延迟是100ms左右),因此Spark Streaming可以知足除对实时性要求很是高(如高频实时交易)以外的全部流式准实时计算场景。
更加稳定的exactly-once语义支持。
Spark Streaming 从v1.5开始引入反压机制(back-pressure),经过动态控制数据接收速率来适配集群数据处理能力.
简单来讲,反压机制须要调节系统接受数据速率或处理数据速率,然而系统处理数据的速率是无法简单的调节。所以,只能估计当前系统处理数据的速率,调节系统接受数据的速率来与之相匹配。
严格来讲,Flink无需进行反压,由于系统接收数据的速率和处理数据的速率是天然匹配的。系统接收数据的前提是接收数据的Task必须有空闲可用的Buffer,该数据被继续处理的前提是下游Task也有空闲可用的Buffer。所以,不存在系统接受了过多的数据,致使超过了系统处理的能力。
由此看出,Spark的micro-batch模型致使了它须要单独引入反压机制。
反压一般产生于这样的场景:短时负载高峰致使系统接收数据的速率远高于它处理数据的速率。
可是,系统可以承受多高的负载是系统数据处理能力决定的,反压机制并非提升系统处理数据的能力,而是系统所面临负载高于承受能力时如何调节系统接收数据的速率。
Driver和executor采用预写日志(WAL)方式去保存状态,同时结合RDD自己的血统的容错机制。
Spark 2.0中引入告终构化数据流,统一了SQL和Streaming的API,采用DataFrame做为统一入口,可以像编写普通Batch程序或者直接像操做SQL同样操做Streaming,易于编程。
除了能够读取HDFS, Flume, Kafka, Twitter andZeroMQ数据源之外,咱们本身也能够定义数据源,支持运行在Yarn,Standalone及EC2上,可以经过Zookeeper,HDFS保证高可用性,处理结果能够直接写到HDFS
依赖java环境,只要应用可以加载到spark相关的jar包便可。
Storm集群采用主从架构方式,主节点是Nimbus,从节点是Supervisor,有关调度相关的信息存储到ZooKeeper集群中。架构以下:
Storm集群的Master节点,负责分发用户代码,指派给具体的Supervisor节点上的Worker节点,去运行Topology对应的组件(Spout/Bolt)的Task。
Storm集群的从节点,负责管理运行在Supervisor节点上的每个Worker进程的启动和终止。经过Storm的配置文件中的supervisor.slots.ports配置项,能够指定在一个Supervisor上最大容许多少个Slot,每一个Slot经过端口号来惟一标识,一个端口号对应一个Worker进程(若是该Worker进程被启动)。
用来协调Nimbus和Supervisor,若是Supervisor因故障出现问题而没法运行Topology,Nimbus会第一时间感知到,并从新分配Topology到其它可用的Supervisor上运行。
运行流程
1)户端提交拓扑到nimbus。
2) Nimbus针对该拓扑创建本地的目录根据topology的配置计算task,分配task,在zookeeper上创建assignments节点存储task和supervisor机器节点中woker的对应关系;
在zookeeper上建立taskbeats节点来监控task的心跳;启动topology。
3) Supervisor去zookeeper上获取分配的tasks,启动多个woker进行,每一个woker生成task,一个task一个线程;根据topology信息初始化创建task之间的链接;Task和Task之间是经过zeroMQ管理的;后整个拓扑运行起来。
在YARN上开发一个应用程序,一般只须要开发两个组件,分别是客户端和ApplicationMaster,其中客户端主要做用是提交应用程序到YARN上,并和YARN和ApplicationMaster进行交互,完成用户发送的一些指令;而ApplicationMaster则负责向YARN申请资源,并与NodeManager通讯,启动任务。
不修改任何Storm源代码便可将其运行在YARN之上,最简单的实现方法是将Storm的各个服务组件(包括Nimbus和Supervisor)做为单独的任务运行在YARN上,而Zookeeper做为一个公共的服务运行在YARN集群以外的几个节点上。
1)经过YARN-Storm Client将Storm Application提交到YARN的RM上;
2)RM为YARN-Storm ApplicationMaster申请资源,并将其运行在一个节点上(Nimbus);
3)YARN-Storm ApplicationMaster 在本身内部启动Nimbus和UI服务;
4)YARN-Storm ApplicationMaster 根据用户配置向RM申请资源,并在申请到的Container中启动Supervisor服务;
5)与向普通Storm集群提交Topology同样,用户直接与运行在Nimbus交互,提交Topology。
相似于MapReduce下降了并行批处理复杂性,Storm下降了进行实时处理的复杂性。
一个服务框架,支持热部署,即时上线或下线App.
你能够在Storm之上使用各类编程语言。默认支持Clojure、Java、Ruby和Python。要增长对其余语言的支持,只需实现一个简单的Storm通讯协议便可。
Storm会管理工做进程和节点的故障。
计算是在多个线程、进程和服务器之间并行进行的。
Storm保证每一个消息至少能获得一次完整处理。任务失败时,它会负责从消息源重试消息。
系统的设计保证了消息能获得快速的处理,使用ZeroMQ做为其底层消息队列。
Storm有一个“本地模式”,能够在处理过程当中彻底模拟Storm集群。这让你能够快速进行开发和单元测试。
依赖于Zookeeper进行任务状态的维护,必须首先部署Zookeeper。
Apache |
Flink |
SparkStreaming |
Storm |
架构 |
架构介于spark和storm之间,主从结构与spark streaming类似,DataFlow Grpah与Storm类似,数据流能够被表示为一个有向图。 每一个顶点是一个用户定义的运算,每向边表示数据的流动。 Native |
架构依赖spark,主从模式,每一个Batch处理都依赖主(driver),能够理解为时间维度上的spark DAG。
Micro-Batch |
主从模式,且依赖ZK,处理过程当中对主的依赖不大。
Native |
容错 |
基于Chandy-Lamport distributed snapshots checkpoint机制 Medium |
WAL及RDD 血统机制
High |
Records ACK
Medium |
处理模型与延迟 |
单条事件处理 亚秒级低延迟 |
一个事件窗口内的全部事件。 秒级高延迟 |
每次传入的一个事件 亚秒级低延迟 |
吞吐量 |
High |
High |
Low |
数据处理保证 |
exactly once
High |
exactly once(实现采用Chandy-Lamport 算法,即marker-checkpoint )
High |
at least once(实现采用record-level acknowledgments),Trident能够支持storm 提供exactly once语义。 Medium |
高级API |
Flink 栈中提供了提供了不少具备高级 API 和知足不一样场景的类库:机器学习、图分析、关系式数据处理 High |
可以很容易的对接Spark生态栈里面的组件,同时可以对接主流的消息传输组件及存储系统。
|
应用须要按照特定的storm定义的规则编写。
Low |
易用性 |
支持SQL Steaming,Batch和STREAMING采用统一编程框架
High |
支持SQL Steaming Batch和STREAMING采用统一编程框架。 High |
不支持SQL Steaming
Low |
成熟性 |
新兴项目,处于发展阶段。 Low |
已经发展一段时间 Medium |
相对较早的流系统,比较稳定。 High |
社区活跃度 |
212 contributor,活跃度呈上升趋势。 Medium |
937 contirbutor
High |
216 contributors,活跃度比较稳定。 Medium |
部署性 |
部署相对简单,只依赖JRE环境 Low |
部署相对简单,只依赖JRE环境 Low |
依赖JRE环境和Zookeeper High |
若是对延迟要求不高的状况下,建议使用Spark Streaming,丰富的高级API,使用简单,自然对接Spark生态栈中的其余组件,吞吐量大,部署简单,UI界面也作的更加智能,社区活跃度较高,有问题响应速度也是比较快的,比较适合作流式的ETL,并且Spark的发展势头也是有目共睹的,相信将来性能和功能将会更加完善。
若是对延迟性要求比较高的话,建议能够尝试下Flink,Flink是目前发展比较火的一个流系统,采用原生的流处理系统,保证了低延迟性,在API和容错上也是作的比较完善,使用起来相对来讲也是比较简单的,部署容易,并且发展势头也愈来愈好,相信后面社区问题的响应速度应该也是比较快的。
我的对Flink是比较看好的,由于原生的流处理理念,在保证了低延迟的前提下,性能仍是比较好的,且愈来愈易用,社区也在不断发展。
更多网易技术、产品、运营经验分享请点击。
相关文章:
【推荐】 关于Runtime.getRuntime().exec()产生阻塞的2个陷阱