作者: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. Mysql事务探索及其在Django中的实践(二)

    继上一篇<Mysql事务探索及其在Django中的实践(一)>交代完问题的背景和Mysql事务基础后,这一篇主要想介绍一下事务在Django中的使用以及实际应用给我们带来的效率提升. 首先 ...

  2. [APUE]标准IO库(下)

    一.标准IO的效率 对比以下四个程序的用户CPU.系统CPU与时钟时间对比 程序1:系统IO 程序2:标准IO getc版本 程序3:标准IO fgets版本 结果: [注:该表截取自APUE,上表中 ...

  3. ASP.NET MVC5+EF6+EasyUI 后台管理系统(74)-微信公众平台开发-自定义菜单

    系列目录 引言 1.如果不借用Senparc.Weixin SDK自定义菜单,编码起来,工作量是非常之大 2.但是借助SDK似乎一切都是简单得不要不要的 3.自定义菜单无需要建立数据库表 4.自定义菜 ...

  4. 谈谈一些有趣的CSS题目(九)-- 巧妙的实现 CSS 斜线

    开本系列,谈谈一些有趣的 CSS 题目,题目类型天马行空,想到什么说什么,不仅为了拓宽一下解决问题的思路,更涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题 ...

  5. [.NET] C# 知识回顾 - 委托 delegate (续)

    C# 知识回顾 - 委托 delegate (续) [博主]反骨仔 [原文]http://www.cnblogs.com/liqingwen/p/6046171.html 序 上篇<C# 知识回 ...

  6. Effective前端2:优化html标签

    div { float: left; } .keyboard > div + div { margin-left: 8px; } --> div{display:table-cell;ve ...

  7. .NET 基础 一步步 一幕幕[面向对象之对象和类]

    对象和类 本篇正式进入面向对象的知识点简述: 何为对象,佛曰:一花一世界,一木一浮生,一草一天堂,一叶一如来,一砂一极乐,一方一净土,一笑一尘缘,一念一清静.可见"万物皆对象". ...

  8. [转载]强制不使用“兼容性视图”的HTML代码

    在IE8浏览器以后版本,都有一个"兼容性视图",让不少新技术无法使用.那么如何禁止浏览器自动选择"兼容性视图",强制IE以最高级别的可用模式显示内容呢?下面就介 ...

  9. 极光推送和友盟推送,ios端和安卓端的后端调试设置

    我是最后端的,这两天搞了一个app项目,前端安卓使用友盟很方便,调试比较顺利,然后ios就遇到各种问题了,证书.发送成功推送不成功,测试时用的TestMode(),ios上架之后就必须用product ...

  10. JavaScript学习笔记(四)——jQuery插件开发与发布

    jQuery插件就是以jQuery库为基础衍生出来的库,jQuery插件的好处是封装功能,提高了代码的复用性,加快了开发速度,现在网络上开源的jQuery插件非常多,随着版本的不停迭代越来越稳定好用, ...