作者: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. 通过adb方式给安卓手机截图的cmd批处理文件

    @echo off rem  通过adb方式截图rem  需要安装adb ,一般安装了android sdk 默认带了adb ,路径为sdk目录的android-sdk\platform-toolsr ...

  2. Linux安装LAMP开发环境及配置文件管理

    Linux主要分为两大系发行版,分别是RedHat和Debian,lamp环境的安装和配置也会有所不同,所以分别以CentOS 7.1和Ubuntu 14.04做为主机(L) Linux下安装软件,最 ...

  3. 多线程的通信和同步(Java并发编程的艺术--笔记)

    1. 线程间的通信机制 线程之间通信机制有两种: 共享内存.消息传递.   2. Java并发 Java的并发采用的是共享内存模型,Java线程之间的通信总是隐式执行,通信的过程对于程序员来说是完全透 ...

  4. 从零开始编写自己的C#框架(27)——什么是开发框架

    前言 做为一个程序员,在开发的过程中会发现,有框架同无框架,做起事来是完全不同的概念,关系到开发的效率.程序的健壮.性能.团队协作.后续功能维护.扩展......等方方面面的事情.很多朋友在学习搭建自 ...

  5. css3圆形百分比进度条的实现原理

    原文地址:css3圆形百分比进度条的实现原理 今天早上起来在查看jquery插件机制的时候,一不小心点进了css3圆形百分比进度条的相关文章,于是一发不可收拾,开始折腾了... 关于圆形圈的实现,想必 ...

  6. notepad++设置默认打开txt文件失效的解决方法

    1.系统环境 win10企业版,64位系统 2.初步设置 设置txt默认为notepad++打开,菜单:设置->首选项->文件关联 选择对应的文件扩展,点击"关闭"按钮 ...

  7. OpenLiveWriter代码插件

    1.OpenLiveWriter安装 Windows Live Writer在2012年就停止了更新,Open Live Writer(以下简称OLW)是由Windows Live WriterWri ...

  8. 浅谈Web自适应

    前言 随着移动设备的普及,移动web在前端工程师们的工作中占有越来越重要的位置.移动设备更新速度频繁,手机厂商繁多,导致的问题是每一台机器的屏幕宽度和分辨率不一样.这给我们在编写前端界面时增加了困难, ...

  9. Android Studio:Failed to resolve ***

    更换电脑后,也更新了所有的SDK的tool,仍然报错:Failed to resolve  各种jar包,出现这种问题主要是因为在Android studio中默认不允许在线更新,修改方法如下:

  10. SQL Server中SELECT会真的阻塞SELECT吗?

    在SQL Server中,我们知道一个SELECT语句执行过程中只会申请一些意向共享锁(IS) 与共享锁(S), 例如我使用SQL Profile跟踪会话86执行SELECT * FROM dbo.T ...