Understanding the Internal Message Buffers of Storm

Jun 21st, 2013

When you are optimizing the performance of your Storm topologies it helps to understand how Storm’s internal messagequeues are configured and put to use. In this short article I will explain and illustrate how Storm version 0.8/0.9implements the intra-worker
communication that happens within a worker process and its associated executor threads.

Internal messaging within Storm worker processes

Terminology: I will use the terms message and (Storm)
tuple
interchangeably in the following sections.

When I say “internal messaging” I mean the messaging that happens within a worker process in Storm, which is communicationthat is restricted to happen within the same Storm machine/node. For this communication Storm relies on various messagequeues backed
by LMAX Disruptor, which is a high performance inter-threadmessaging library.

Note that this communication within the threads of a worker process is different from Storm’s
inter-workercommunication, which normally happens across machines and thus over the network. For the latter Storm usesZeroMQ by default (in Storm 0.9 there is experimental support for
Netty asthe network messaging backend). That is, ZeroMQ/Netty are used when a task in one worker process wants to send data toa task that runs in a worker process on different machine in the Storm cluster.

So for your reference:

  • Intra-worker communication in Storm (inter-thread on the same Storm node): LMAX Disruptor
  • Inter-worker communication (node-to-node across the network): ZeroMQ or Netty
  • Inter-topology communication: nothing built into Storm, you must take care of this yourself with e.g. a messagingsystem such as Kafka/RabbitMQ, a database, etc.

If you do not know what the differences are between Storm’s worker processes, executor threads and tasks please take alook atUnderstanding
the Parallelism of a Storm Topology
.

Illustration

Let us start with a picture before we discuss the nitty-gritty details in the next section.

Figure 1: Overview of a worker’s internal message queues in Storm. Queues related to a worker process are colored inred, queues related to the worker’s various executor threads are colored in green. For readability reasons I show onlyone
worker process (though normally a single Storm node runs multiple such processes) and only one executor threadwithin that worker process (of which, again, there are usually many per worker process).

Detailed description

Now that you got a first glimpse of Storm’s intra-worker messaging setup we can discuss the details.

Worker processes

To manage its incoming and outgoing messages each worker process has a single receive thread that listens on the worker’sTCP port (as configured via
supervisor.slots.ports). The parameter topology.receiver.buffer.size determines thebatch size that the receive thread uses to place incoming messages into the incoming queues of the worker’s executorthreads. Similarly, each worker
has a single send thread that is responsible for reading messages from the worker’stransfer queue and sending them over the network to downstream consumers. The size of the transfer queue is configuredvia
topology.transfer.buffer.size.

  • The topology.receiver.buffer.size is the maximum number of messages that are batched together at once forappending to an executor’s incoming queue by the worker receive thread (which reads the messages from the network)Setting this parameter
    too high may cause a lot of problems (“heartbeat thread gets starved, throughput plummets”).The default value is 8 elements, and the value must be a power of 2 (this requirement comes indirectly from LMAXDisruptor).
1
2
3
// Example: configuring via Java API
Config conf = new Config();
conf.put(Config.TOPOLOGY_RECEIVER_BUFFER_SIZE, 16); // default is 8
Note that topology.receiver.buffer.size is in contrast to the other buffer size related parameters described in this article actually not configuring the size of an LMAX Disruptor queue. Rather it sets the size of a simple
ArrayList that is used to buffer incoming messages because in this specific case the data structure does not need to be shared with other threads, i.e. it is local to the worker’s receive thread. But because the content of this buffer is used to fill a
Disruptor-backed queue (executor incoming queues) it must still be a power of 2. See
launch-receive-thread! in backtype.storm.messaging.loader for details.
  • Each element of the transfer queue configured with topology.transfer.buffer.size is actually a
    list of tuples.The various executor send threads will batch outgoing tuples off their outgoing queues onto the transfer queue. Thedefault value is 1024 elements.
1
2
// Example: configuring via Java API
conf.put(Config.TOPOLOGY_TRANSFER_BUFFER_SIZE, 32); // default is 1024

Executors

Each worker process controls one or more executor threads. Each executor thread has its own
incoming queue andoutgoing queue. As described above, the worker process runs a dedicated worker receive thread that is responsiblefor moving incoming messages to the appropriate incoming queue of the worker’s various executor threads. Similarly,each
executor has its dedicated send thread that moves an executor’s outgoing messages from its outgoing queue to the“parent” worker’s transfer queue. The sizes of the executors’ incoming and outgoing queues are configured viatopology.executor.receive.buffer.size
and topology.executor.send.buffer.size, respectively.

Each executor thread has a single thread that handles the user logic for the spout/bolt (i.e. your application code),and a single send thread which moves messages from the executor’s outgoing queue to the worker’s transfer queue.

  • The topology.executor.receive.buffer.size is the size of the incoming queue for an executor. Each element ofthis queue is a
    list of tuples. Here, tuples are appended in batch. The default value is 1024 elements, andthe value must be a power of 2 (this requirement comes from LMAX Disruptor).
1
2
// Example: configuring via Java API
conf.put(Config.TOPOLOGY_EXECUTOR_RECEIVE_BUFFER_SIZE, 16384); // batched; default is 1024
  • The topology.executor.send.buffer.size is the size of the outgoing queue for an executor. Each element of thisqueue will contain a
    single tuple. The default value is 1024 elements, and the value must be a power of 2 (thisrequirement comes from LMAX Disruptor).
1
2
// Example: configuring via Java API
conf.put(Config.TOPOLOGY_EXECUTOR_SEND_BUFFER_SIZE, 16384); // individual tuples; default is 1024

Where to go from here

How to configure Storm’s internal message buffers

The various default values mentioned above are defined inconf/defaults.yaml. You can override these valuesglobally in a Storm cluster’s
conf/storm.yaml. You can also configure these parameters per individual Stormtopology via
backtype.storm.Config in Storm’s JavaAPI.

How to configure Storm’s parallelism

The correct configuration of Storm’s message buffers is closely tied to the workload pattern of your topology as wellas the configured
parallelism of your topologies. SeeUnderstanding the Parallelism of a Storm Topologyfor more details about the latter.

Understand what’s going on in your Storm topology

The Storm UI is a good start to inspect key metrics of your running Storm topologies. For instance, it shows you theso-called “capacity” of a spout/bolt. The various metrics will help you decide whether your changes to thebuffer-related configuration parameters
described in this article had a positive or negative effect on the performanceof your Storm topologies. SeeRunning a Multi-Node Storm Cluster for details.

Apart from that you can also generate your own application metrics and track them with a tool like Graphite.See my articles
Sending Metrics From Storm to Graphite andInstalling and Running Graphite via RPM and Supervisordfor details. It might also
be worth checking out ooyala’smetrics_storm project on GitHub (I haven’t used it yet).

Advice on performance tuning

Watch Nathan Marz’s talk onTuning and Productionization of Storm.

The TL;DR version is: Try the following settings as a first start and see whether it improves the performance of yourStorm topology.

1
2
3
4
conf.put(Config.TOPOLOGY_RECEIVER_BUFFER_SIZE,             8);
conf.put(Config.TOPOLOGY_TRANSFER_BUFFER_SIZE, 32);
conf.put(Config.TOPOLOGY_EXECUTOR_RECEIVE_BUFFER_SIZE, 16384);
conf.put(Config.TOPOLOGY_EXECUTOR_SEND_BUFFER_SIZE, 16384);
Interested in more? You can subscribe to this blog, or follow me on Twitter.

Posted by Michael G. Noll Jun 21st, 2013
Filed under Programming, Storm

原文地址: http://www.michael-noll.com/blog/2013/06/21/understanding-storm-internal-message-buffers/

Understanding the Internal Message Buffers of Storm的更多相关文章

  1. STORM在线业务实践-集群空闲CPU飙高问题排查

    源:http://daiwa.ninja/index.php/2015/07/18/storm-cpu-overload/ 2015-07-18AUTHORDAIWA STORM在线业务实践-集群空闲 ...

  2. STORM在线业务实践-集群空闲CPU飙高问题排查(转)

    最近将公司的在线业务迁移到Storm集群上,上线后遇到低峰期CPU耗费严重的情况.在解决问题的过程中深入了解了storm的内部实现原理,并且解决了一个storm0.9-0.10版本一直存在的严重bug ...

  3. Storm-源码分析- Disruptor在storm中的使用

    Disruptor 2.0, (http://ifeve.com/disruptor-2-change/) Disruptor为了更便于使用, 在2.0做了比较大的调整, 比较突出的是更换了几乎所有的 ...

  4. Storm worker 并行度等理解

    Storm 调优是非常重要的, 仅次于写出正确的代码, 好在Storm官网上有关于worker executors tasks的介绍, http://storm.incubator.apache.or ...

  5. Storm内部的消息传递机制

    作者:Jack47 转载请保留作者和原文出处 欢迎关注我的微信公众账号程序员杰克,两边的文章会同步,也可以添加我的RSS订阅源. 一个Storm拓扑,就是一个复杂的多阶段的流式计算.Storm中的组件 ...

  6. Storm 学习之路(二)—— Storm核心概念详解

    一.Storm核心概念 1.1 Topologies(拓扑) 一个完整的Storm流处理程序被称为Storm topology(拓扑).它是一个是由Spouts 和Bolts通过Stream连接起来的 ...

  7. Storm 系列(二)—— Storm 核心概念详解

    一.Storm核心概念 1.1 Topologies(拓扑) 一个完整的 Storm 流处理程序被称为 Storm topology(拓扑).它是一个是由 Spouts 和 Bolts 通过 Stre ...

  8. Storm如何保证可靠的消息处理

    作者:Jack47 PS:如果喜欢我写的文章,欢迎关注我的微信公众账号程序员杰克,两边的文章会同步,也可以添加我的RSS订阅源. 本文主要翻译自Storm官方文档Guaranteeing messag ...

  9. Android Message Handling Mechanism

    转自:http://solarex.github.io/blog/2015/09/22/android-message-handling-mechanism/ Android is a message ...

随机推荐

  1. TortoiseSVN客户端重新设置用户名和密码

    TortoiseSVN客户端重新设置用户名和密码 在第一次使用TortoiseSVN从服务器CheckOut的时候,会要求输入用户名和密码,这时输入框下面有个选项是保存认证信息,如果选了这个选项,那么 ...

  2. mysql实战之 批量update

    mysql实战之批量update 现阶段我们的业务量很小,要对admin_user表中的relationship字段进行更新,指定id是409.已知409是公司内的一服务中心,需要把该服务中心放到区代 ...

  3. 21-React的学习

    # React的学习 React概述: React是一个用于构建用户界面的JavaScript库. React主要用于构建UI,很多人认为React是MVC中的V(视图). React起源于Faceb ...

  4. GOLANG 变量

    语法格式 var    变量名    类型   类型:        可以是go语言内置的各种基本数据类型.复合数据类型,甚至是函数.方法.接口以及自定义类型. 声明变量会给变量设定零值.数值类型变量 ...

  5. Jmeter + Grafana + InfluxDB 性能测试监控

    阅读目录 1. 安装InfluxDB 2. 安装Grafana 3. 配置Jmeter 序章 前几天在群里看到大神们在讨论Jmeter + InfluxDB + Grafana监控.说起来Jmeter ...

  6. DG的Switchover切换

    用户可以使用角色管理服务,进行主.备库的计划中的角色切换,这个叫switchover,或者是非计划中的角色切换,叫failover. 目的:实现主库(orcl)和从库(standby)的切换 主库参数 ...

  7. springmvc 解决跨域CORS

    import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import ja ...

  8. SAP采购订单历史明细报表源代码(自己收藏)

    SPAN { font-family: "Courier New"; font-size: 10pt; color: #000000; background: #FFFFFF } ...

  9. javascript原型prototype浅识

    C++,java是基于类的语言,主要通过类来实现继承. javascript是基于原型的语言,通过原型来实现继承. 什么是原型?每种物质,都可以追根溯源,原型就是对象的根源.继承就是追根溯源. jav ...

  10. 转:Linux内部的时钟处理机制全面剖析

    Linux内部的时钟处理机制全面剖析 在 Linux 操作系统中,很多活动都和时间有关,例如:进程调度和网络处理等等.所以说,了解 Linux 操作系统中的时钟处理机制有助于更好地了解 Linux 操 ...