作者:Jack47

转载请保留作者和原文出处

欢迎关注我的微信公众账号程序员杰克,两边的文章会同步,也可以添加我的RSS订阅源

一个Storm拓扑,就是一个复杂的多阶段的流式计算。Storm中的组件(Component)就是对各个阶段的一个抽象,其中的Spout是生产者的角色,它负责源源不断地从Storm外部接收消息,扔给下游的组件处理,下游组件处理完成后,最终输出到外部的存储系统。

本文主要讲解消息在Storm内部的各个组件(Component)之间如何进行传递,本文适用于JStorm 2.1.0以后的版本。对于JStorm各个版本的改进,见这里

如果读者对Storm的基本组成部分如Spout,Bolt,Worker进程和Task不了解,可以先看下 Storm介绍(一)Storm介绍(二)“理解Storm拓扑并发”

下文中使用的"消息"(Messagesage)和“元组"(Tuple)两个词语其实是同一个意思。

Storm中的每个组件,可以用一个三元组来定义

<inputStreamId, boltImpl, outputStreamInfo>

其中inputStreamId定义了这个组件所消费的流的ID; boltImpl是bolt的具体实现的类;outputStreamInfo代表这个组件的输出流的信息,包含两部分:输出流的ID和路由方式。所以当一个组件发射一个消息后,通过这个流的分组策略(Grouping)就可以立马计算出消费它的taskId。

拿下面中的拓扑为例,从图一看到这个拓扑由三个组件构成:蓝色的Spout,消费方是Green Bolt,Green Bolt的消费方是Yellow Bolt。这个拓扑在集群上的运行时的状态如图二所示:

它由两个Worker进程组成,每个Work里面运行4个Task。仔细的读者已经发现了这里没有Executor,这是JStorm和Storm很大的不同。JStorm认为Executor的存在收益比太低,虽然它支持不停机动态扩大Task的数量,但同时增加了理解成本,增加了应用开发人员编程的复杂度,所以JStorm中去掉了Executor。

->

<-

图一 一个实际拓扑组件的构成

->

<-

图二 集群上运行的一个实际拓扑

在Storm拓扑内部,同一个拓扑的多个Worker之间会发生消息传递,比如上图二中的两个Worker进程,他们之间的通信就是进程间的通信了,发送的消息需要经过序列化和反序列化。Storm中,Worker之间使用Netty进行网络通信。

在Storm拓扑的一个Worker进程内部,多个Task之间也会进行通信。比如上图二中的Task 6和Task 3。Storm中Worker进程内部的消息通信依赖于LMAX Disruptor这个高性能线程间通信的消息通信库。

Storm内部的消息传递

JStorm与Storm在内部消息传递机制上的主要差别:

JStorm中独立出一个线程来专门负责消息的反序列化,这样执行线程单独执行,而不是Storm那样,一个线程负责执行反序列化并执行用户的逻辑。相当于是把流水线拆解的更小了。这样对于反序列化时延跟执行时延在同一个数量级的应用性能提升比较明显。

图三:JStorm内部消息队列的概要图

从图里看到队列都是绿色的,这些队列都是某个Worker内部的队列。为了可读性只保留了一个Worker进程(一个storm节点一般都运行多个Worker),而且在这个Worker进程里只画了一个Task,(再次的,在一个Worker进程里通常有多个Task)

详细解释

每个Worker进程有一个NettyServer,它监听在Worker的TCP端口上(通过 supervisor.slots.ports来配置),其他需要跟它通信的Worker会作为NettyClient分别建立连接。当NettyServer接收到消息,会根据taskId参数把消息放到对应的反序列化队列(DeserializedQueue)里面。 topology.executor.receive.buffer.size决定了反序列化队列的大小。TaskReceiver中的反序列化线程专门负责消费反序列化队列中的消息:先将消息反序列化,然后放到执行队列(Execute Queue)中去。

执行队列的消费者是BoltExecutor线程,它负责从队列中取出消息,执行用户的代码逻辑。执行完用户的代码逻辑后,最终通过OutputCollect输出消息,此时消息里已经生成了目标task的taskId。topology.executor.receive.buffer.size决定了执行队列的大小。可以看到JStorm中执行队列跟反序列化队列的大小是同一个配置项,即它们是一致的。

仔细看了图三的同学会发现执行队列的生产者除了TaskReceiver外,还有一个。这种消息的来源就是Worker内部的其他Task的TaskTransfer。

输出的消息通过TaskTransfer来发送,如果目标Task是Worker内部的Task,就直接扔到目标Task的执行队列中去。如果目标Task是在其他Worker上,那就先放到序列化队列中,然后由单独的一个线程专门负责序列化,然后通过NettyClient发送出去。topology.executor.send.buffer.size决定了序列化队列的大小。

每个Worker进程有多个NettyClient,他们负责与其他的Worker进行网络通信。

延伸阅读

如何配置Storm的内部消息缓存

上面提到的众多配置项都在conf/defaults.yaml里有定义。可以通过在Storm集群的conf/storm.yaml里进行配置来全局的覆值。也可以通过Storm的Java API backtype.storm.Config 来对单个的Storm拓扑进行配置。

如何配置Storm的并发###

Storm消息缓存的正确配置不但是和你的拓扑的负载类型紧密关联的,而且和拓扑的并发度有很大关系。后者的详细信息见理解Storm并发一文。

了解Storm拓扑上发生了什么?

Storm UI是一个用于观察你正在运行的拓扑的关键指标的良好开端。例如,它可以给你展示所谓的Spout/Bolt的“容量”。众多的指标可以帮助你决定对本文中提到的众多缓存相关的配置参数的修改,对你的拓扑的运行效率的影响是正向的还是负向的。更多信息见"运行一个多节点Storm集群"一文。

除此之外还可以注册应用程序自己的指标并使用类似Graphite这类工具来跟踪它们。详细信息见“从Storm发送指标到Graphite"和“通过RPM和Supervisord来安装和运行Graphite"。

性能调优方面的建议

可以看Storm主要作者Nathan Marz的演讲:调优和上线Storm拓扑

看看其他没有提到的参数:

topology.spout.max.batch.size

数据容量(data volume),数据速度(velocity),消息的大小,处理一个消息的计算复杂度。所以需要不断调整才能找到最佳的参数,没有银弹。

参考资料:

Understanding storm internal message buffers


如果您看了本篇博客,觉得对您有所收获,请点击右下角的“推荐”,让更多人看到!

资助Jack47写作,打赏一个鸡蛋灌饼钱吧
微信打赏
支付宝打赏

Storm内部的消息传递机制的更多相关文章

  1. Chrome 消息传递机制

    Chrome插件开发入门(二)——消息传递机制 Blog | Qiushi Chen 2014-03-31 9538 阅读 Chrome 插件 由于插件的js运行环境有区别,所以消息传递机制是一个重要 ...

  2. Chrome插件开发入门(二)——消息传递机制

    Chrome插件开发入门(二)——消息传递机制   由于插件的js运行环境有区别,所以消息传递机制是一个重要内容.阅读了很多博文,大家已经说得很清楚了,直接转一篇@姬小光 的博文,总结的挺好.后面附一 ...

  3. iOS开发——OC篇&消息传递机制(KVO/NOtification/Block/代理/Target-Action)

     iOS开发中消息传递机制(KVO/NOtification/Block/代理/Target-Action)   今晚看到了一篇好的文章,所以就搬过来了,方便自己以后学习 虽然这一期的主题是关于Fou ...

  4. Android异步消息传递机制源码分析

    1.Android异步消息传递机制有以下两个方式:(异步消息传递来解决线程通信问题) handler 和 AsyncTask 2.handler官方解释的用途: 1).定时任务:通过handler.p ...

  5. (Android数据传递)Intent消息传递机制 “Intent”“数据传递”

    Intent类的继承关系:   需要注意的是,该类实现了Parcelable(用于数据传递)和Cloneable接口. Intent是一种(系统级别的)消息传递机制,可以在应用程序内使用,也可以在应用 ...

  6. 安卓开发_深入理解Handler消息传递机制

    一.概述 因为子线程的run()方法无法修改UI线程(主线程)的UI界面,所以Android引入了Handler消息传递机制,实现在新创建的线程中操作UI界面 二.消息类(Message) 消息类是存 ...

  7. Apache Storm内部原理分析

    转自:http://shiyanjun.cn/archives/1472.html 本文算是个人对Storm应用和学习的一个总结,由于不太懂Clojure语言,所以无法更多地从源码分析,但是参考了官网 ...

  8. Android 消息传递机制

    线程间消息传递机制 1.消息怎么发送的? 我们都知道当调用Handler发送消息的时候,不管是调用 sendMessage,sendEmptyMessage,sendMessageDelayed还是其 ...

  9. 我理解的Hanlder--android消息传递机制

    每一个学习Android的同学都会觉得Handler是一个神奇的东西,我也一样,开始我以为我懂了Handler的机制,后来发现自己是一知半解,昨天想想,我能否自己实现一个Handler,让子线程与Ac ...

随机推荐

  1. Android请求网络共通类——Hi_博客 Android App 开发笔记

    今天 ,来分享一下 ,一个博客App的开发过程,以前也没开发过这种类型App 的经验,求大神们轻点喷. 首先我们要创建一个Andriod 项目 因为要从网络请求数据所以我们先来一个请求网络的共通类. ...

  2. 如何一步一步用DDD设计一个电商网站(六)—— 给购物车加点料,集成售价上下文

    阅读目录 前言 如何在一个项目中实现多个上下文的业务 售价上下文与购买上下文的集成 结语 一.前言 前几篇已经实现了一个最简单的购买过程,这次开始往这个过程中增加一些东西.比如促销.会员价等,在我们的 ...

  3. Objective-C三种定时器CADisplayLink / NSTimer / GCD的使用

    OC中的三种定时器:CADisplayLink.NSTimer.GCD 我们先来看看CADiskplayLink, 点进头文件里面看看, 用注释来说明下 @interface CADisplayLin ...

  4. 23种设计模式--观察者模式-Observer Pattern

    一.观察者模式的介绍      观察者模式从字面的意思上理解,肯定有两个对象一个是观察者,另外一个是被观察者,观察者模式就是当被观察者发生改变得时候发送通知给观察者,当然这个观察者可以是多个对象,在项 ...

  5. 微软新神器-Power BI横空出世,一个简单易用,还用得起的BI产品,你还在等什么???

    在当前互联网,由于大数据研究热潮,以及数据挖掘,机器学习等技术的改进,各种数据可视化图表层出不穷,如何让大数据生动呈现,也成了一个具有挑战性的可能,随之也出现了大量的商业化软件.今天就给大家介绍一款逆 ...

  6. C# 索引器,实现IEnumerable接口的GetEnumerator()方法

    当自定义类需要实现索引时,可以在类中实现索引器. 用Table作为例子,Table由多个Row组成,Row由多个Cell组成, 我们需要实现自定义的table[0],row[0] 索引器定义格式为 [ ...

  7. SpringMVC+Shiro权限管理【转】

    1.权限的简单描述 2.实例表结构及内容及POJO 3.Shiro-pom.xml 4.Shiro-web.xml 5.Shiro-MyShiro-权限认证,登录认证层 6.Shiro-applica ...

  8. 【转】 FineBI:自助式BI工具打造业务分析的“快与准”

    如今的企业经营方式,业务对于数据分析有极大的需求,但却苦于没有数据以及工具的有效支持,业务分析仍就依赖于IT报表制作.而IT方不断地按业务需求去调研.确认业务逻辑,然后取数做报表,其中还要忍受业务的需 ...

  9. 1.Hibernate简介

    1.框架简介: 定义:基于java语言开发的一套ORM框架: 优点:a.方便开发;           b.大大减少代码量;           c.性能稍高(不能与数据库高手相比,较一般数据库使用者 ...

  10. Oracle 表空间和用户权限管理

    一. 表空间 Oracle数据库包含逻辑结构和物理结构. 数据库的物理结构指的是构成数据库的一组操作系统文件. 数据库的逻辑结构是指描述数据组织方式的一组逻辑概念以及它们之间的关系. 表空间是数据库逻 ...