Storm数据流模型的分析及讨论

Storm数据流模型的分析及讨论
这篇文章很详细的介绍了Storm,特此推荐!
本文首先介绍了Storm的基本概念和数据流模型,然后结合一个典型应用场景来说明Storm支持Topology之间数据流订阅的必要性,最后对比了Storm与另一个流处理系统在数据流模型上的区别之处。
Storm基本概念
Storm是一个开源的实时计算系统,它提供了一系列的基本元素用于进行计算:Topology、Stream、Spout、Bolt等等。
在Storm中,一个实时应用的计算任务被打包作为Topology发布,这同Hadoop的MapReduce任务相似。但是有一点不同的是:在Hadoop中,MapReduce任务最终会执行完成后结束;而在Storm中,Topology任务一旦提交后永远不会结束,除非你显示去停止任务。
计算任务Topology是由不同的Spouts和Bolts,通过数据流(Stream)连接起来的图。下面是一个Topology的结构示意图:

 
其中包含有:
Spout:Storm中的消息源,用于为Topology生产消息(数据),一般是从外部数据源(如Message Queue、RDBMS、NoSQL、Realtime Log)不间断地读取数据并发送给Topology消息(tuple元组)。
Bolt:Storm中的消息处理者,用于为Topology进行消息的处理,Bolt可以执行过滤, 聚合, 查询数据库等操作,而且可以一级一级的进行处理。
最终,Topology会被提交到storm集群中运行;也可以通过命令停止Topology的运行,将Topology占用的计算资源归还给Storm集群。
Storm数据流模型
数据流(Stream)是Storm中对数据进行的抽象,它是时间上无界的tuple元组序列。在Topology中,Spout是Stream的源头,负责为Topology从特定数据源发射Stream;Bolt可以接收任意多个Stream作为输入,然后进行数据的加工处理过程,如果需要,Bolt还可以发射出新的Stream给下级Bolt进行处理。
下面是一个Topology内部Spout和Bolt之间的数据流关系:

 
Topology中每一个计算组件(Spout和Bolt)都有一个并行执行度,在创建Topology时可以进行指定,Storm会在集群内分配对应并行度个数的线程来同时执行这一组件。
那么,有一个问题:既然对于一个Spout或Bolt,都会有多个task线程来运行,那么如何在两个组件(Spout和Bolt)之间发送tuple元组呢?
Storm提供了若干种数据流分发(Stream Grouping)策略用来解决这一问题。在Topology定义时,需要为每个Bolt指定接收什么样的Stream作为其输入(注:Spout并不需要接收Stream,只会发射Stream)。
目前Storm中提供了以下7种Stream Grouping策略:Shuffle Grouping、Fields Grouping、All Grouping、Global Grouping、Non Grouping、Direct Grouping、Local or shuffle grouping,具体策略可以参考这里
一种Storm不能支持的场景
以上介绍了一些Storm中的基本概念,可以看出,Storm中Stream的概念是Topology内唯一的,只能在Topology内按照“发布-订阅”方式在不同的计算组件(Spout和Bolt)之间进行数据的流动,而Stream在Topology之间是无法流动的

这一点限制了Storm在一些场景下的应用,下面通过一个简单的实例来说明。
假设现在有一个Topology1的结构如下:通过Spout产生数据流后,依次需要经过Filter Bolt,Join Bolt,Business1 Bolt。其中,Filter Bolt用于对数据进行过滤,Join Bolt用于数据流的聚合,Business1 Bolt用于进行一个实际业务的计算逻辑。

目前这个Topology1已经被提交到Storm集群运行,而现在我们又有了新的需求,需要计算一个新的业务逻辑,而这个Topology的特点是和Topology1公用同样的数据源,而且前期的预处理过程完全一样(依次经历Filter Bolt和Join Bolt),那么这时候Storm怎么来满足这一需求?据个人了解,有以下几种“曲折”的实现方式:
1)第一种方式:首先kill掉已经在集群中运行的Topology1计算任务,然后实现Business2 Bolt的计算逻辑,并重新打包形成一个新的Topology计算任务jar包后,提交到Storm集群中重新运行,这时候Storm内的整体Topology结构如下:

这种方式的缺点在于:由于要重启Topology,所以如果Spout或Bolt有状态则会丢失掉;同时由于Topology结构发生了变化,因此重新运行Topology前需要对程序的稳定性、正确性进行验证;另外Topology结构的变化也会带来额外的运维开销。
2)第二种方式:完全开发部署一套新的Topology,其中前面的公共部分的Spout和Bolt可以直接复用,只需要重新开发新的计算逻辑Business2 Bolt来替换原有的Business1 Bolt即可。然后重新提交新的Topology运行。这时候Storm内的整体Topology结构如下:

这种方式的缺点在于:由于两个Topology都会从External Data Source读取同一份数据,无疑增加了External Data Source的负载压力;而且会导致同样的数据在Storm集群内被传输相同的两份,被同样的计算单元Bolt进行处理,浪费了Storm的计算资源和网络传输带宽。假设现在不止有两个这样的Topology计算任务,而是有N个,那么对Storm的计算Slot的浪费很严重。
注意:上述两种方式还有一个公共的缺点——系统可扩展性不好,这意味着不管哪种方式,只要以后有这种新增业务逻辑的需求,都需要进行复杂的人工操作或线性的资源浪费现象。
3)第三种方式:OK,看了以上两种方式后,也许你会提出下面的解决方案:通过Kafka这样的消息中间件,实现不同Topology的Spout共享数据源,而且这样可以做到消息可靠传输、消息rewind回传等,好处是对于Storm来说,已经有了storm-kafka插件的支持。这时候Storm内的整体Topology结构如下:

这种方式的缺点在于:由于两个Topology都会从External Data Source读取同一份数据,无疑增加了External Data Source的负载压力;而且会导致同样的数据在Storm集群内被传输相同的两份,被同样的计算单元Bolt进行处理,浪费了Storm的计算资源和网络传输带宽。假设现在不止有两个这样的Topology计算任务,而是有N个,那么对Storm的计算Slot的浪费很严重。
注意:上述两种方式还有一个公共的缺点——系统可扩展性不好,这意味着不管哪种方式,只要以后有这种新增业务逻辑的需求,都需要进行复杂的人工操作或线性的资源浪费现象。
 

0 个评论

要回复文章请先登录注册