storm调优

来源:互联网 发布:excel2010数据透视图 编辑:程序博客网 时间:2024/06/06 03:13

storm调优

@(STORM)[storm]

本文从2个方面讨论storm的调优,第一个是集群的调优,第二个是运行在集群中的拓扑的调优,这部分还包括了使用storm-kafka从kafka中读取消息的调优。

官方的一些建议请见:http://storm.apache.org/documentation/FAQ.html
中文版:http://ifeve.com/storm-faq/

一、集群调优

1、netty的调优

netty的配置项主要包括以下几个:

storm.messaging.netty.server_worker_threads: 1storm.messaging.netty.client_worker_threads: 1storm.messaging.netty.buffer_size: 5242880 #5MB buffer# Since nimbus.task.launch.secs and supervisor.worker.start.timeout.secs are 120, other workers should also wait at least that long before giving up on connecting to the other worker. The reconnection period need also be bigger than storm.zookeeper.session.timeout(default is 20s), so that we can abort the reconnection when the target worker is dead.storm.messaging.netty.max_retries: 300storm.messaging.netty.max_wait_ms: 1000storm.messaging.netty.min_wait_ms: 100# If the Netty messaging layer is busy(netty internal buffer not writable), the Netty client will try to batch message as more as possible up to the size of storm.messaging.netty.transfer.batch.size bytes, otherwise it will try to flush message as soon as possible to reduce latency.storm.messaging.netty.transfer.batch.size: 262144# Sets the backlog value to specify when the channel binds to a local addressstorm.messaging.netty.socket.backlog: 500# By default, the Netty SASL authentication is set to false.  Users can override and set it true for a specific topology.storm.messaging.netty.authentication: false

2、GC记录打印

  • 在配置文件中开启 GC 日志记录;如果一切正常,日志中记录的 major GC 应该会非常少

二、拓扑调优

1、使用组件的并行度代替线程池

在storm中,我们可以很方便的调整spout/bolt的并行度,即使启动拓扑时设置不合理,也可以使用rebanlance命令进行动态调整。
但有些人可能会在一个spout/bolt组件的task内部启动一个线程池,这些线程池所在的task会比其余task消耗更多的资源,因此这些task所在的worker会消耗较多的资源,有可能影响其它拓扑的正常执行。
因此,应该使用组件自身的并行度来代替线程池,因为这些并行度会被合理分配到不同的worker中去。除此之外,还可以使用CGroup等技术进行资源的控制。

2、不要在spout中处理耗时的操作

在storm中,spout是单线程的。如果nextTuple方法非常耗时,某个消息被成功执行完毕后,acker会给spout发送消息,spout若无法及时消费,则有可能导致 ack消息被丢弃,然后spout认为执行失败了。
在jstorm中将spout分成了3个线程,分别执行nextTuple, fail, ack方法。

3、fieldsGrouping的数据均衡性

fieldsGrouping根据某个field的值进行分组,以userId为例,如果一个组件以userId的值作为分组,则具有相同userId的值会被发送到同一个task。如果某些userId的数据量特别大,会导致这接收这些数据的task负载特别高,从而导致数据均衡出现问题。
因此必须合理选择field的值,或者更换分组策略。

4、优先使用localOrShuffleGrouping代替shuffleGrouping

localOrShuffleGrouping是指如果task发送消息给目标task时,发现同一个worker中有目标task,则优先发送到这个task;如果没有,则进行shuffle,随机选取一个目标task。
localOrShuffleGrouping其实是对shuffleGrouping的一个优化,因为消除了网络开销和序列化操作。

5、设置合理的MaxSpoutPending

另附官方建议:
- 开始时设置一个很小的 TOPOLOGY_MAX_SPOUT_PENDING(对于 trident 可以设置为 1,对于一般的 topology 可以设置为 executor 的数量),然后逐渐增大,直到数据流不再发生变化。这时你可能会发现结果大约等于 “2 × 吞吐率(每秒收到的消息数) × 端到端时延” (最小的额定容量的2倍)。

注意,此参数慎用,过大的maxspoutpending会增加某个batch fail的风险,如果不能合理处理fail(如写磁盘),则将其设置为1以尽量降低其fail的风险。如果可以通过state来处理fail,则可选择最优参数。

在启用了ack的情况下,spout中有个RotatingMap来保存spout已经发送出去,但未收到ack结果的消息。RotatingMap最大的大小为p*num-task,其中num-task就是spout的task数量,而p为topology.max.spout.pending的值,也可以通过setMaxSpoutPending来指定,是指每个task最多已经发送出去但未被ack的消息数量。

若设置过小,则task的处理能力未充分应用,不能达到最佳的吞吐量。若设置过大,则消费过多的内存,还有可能spout的消息不能及时处理,从而导致fail的出现。

1、spout的Execute latency(执行nextTuple的时间)为17ms,因此理论上每秒每个spout task的最大发送速度是60个tuple。
2、一个tuple的处理时长约为200ms(topo的complete latency)
3、200ms内有大约有60*0.2=12个tuple被发送。
4、因此MaxSpoutPenging被设置为12较为合理。

小结:1/Execute latency*complete latency,即使用topo的complete latency除以Execute latency即可,但实际上不应该考虑如此极端的情况,以避免过多的fail出现,所以可以设置为上述值除以1.5左右。

默认值为1,需要改为合理的值。对trident是否适用??

//任何时刻中,一个spout task最多可以同时处理的tuple数量,即已经emite,但未acked的tuple数量。默认为1    Number active = (Number) conf.get(Config.TOPOLOGY_MAX_SPOUT_PENDING);    if(active==null) {        _maxTransactionActive = 1;    } else {        _maxTransactionActive = active.intValue();    }

6、避免出现fail

bolt在处理消息时,worker 的日志中出现Failing message

原因:可能是因为Topology 的消息处理超时所致。一个常见的原因是supervisor的负载太高(如网络、磁盘IO等),不能及时的处理消息,从而导致fail。

解决方法:提交Topology 时设置适当的消息超时时间,比默认消息超时时间(30
秒)更长。比如:

conf.setMessageTimeoutSecs(60);

或者:

config.put(Config.TOPOLOGY_MESSAGE_TIMEOUT_SECS,60);

也可以在storm.yaml中修改这个参数:

topology.message.timeout.secs: 30

因为Config.java中定义了:

public static final String TOPOLOGY_MESSAGE_TIMEOUT_SECS = "topology.message.timeout.secs";

一个场景:拓扑中进行大量的磁盘IO输出,当负载过高时,机器不能在超时时间内处理消息,从而消息fail掉,导致重传。而由于已经写入磁盘的IO无法清除,所以重传时再写入磁盘会导致数据重复。

7、batch interval

  • 将 trident 的 batch interval 配置为你的集群的端到端时延的 50% 左右

8、Coordinator 是什么,为什么会有很多 Coordinator?

Trident spout 实际上是通过 Storm 的 bolt 运行的。MasterBatchCoordinator(MBC)封装了 Trident 拓扑的 spout,它负责整合 Trident 中的 batch,这一点对于你所使用的任何类型的 spout 而言都是一样的。Trident 的 batch 就是在 MBC 向各个 spout-coordinator 分发种子 tuple 的过程中生成的。Spout-coordinator bolt 知道你所定义的 spout 是如何互相协作的 —— 实际上,在使用 Kafka 的情况下,各个 spout 就是通过 spout-coordinator 来获取 pull 消息所需要的 partition 和 offset 信息的。

在 spout 的 metadata 记录中能够存储什么信息?
只能存储少量静态数据,而且是越少越好(尽管你确实可以向其中存储更多的信息,不过我们不推荐这样做)。

emitPartitionBatchNew 函数是多久调用一次的?
由于在 Trident 中 MBC 才是实际运行的 spout,一个 batch 中的所有 tuple 都是 MBC 生成的 tuple 树的节点。也就是说,Storm 的 “max spout pending” 参数实际上定义的是可以并发运行的 batch 数量。MBC 在满足以下两个条件下会发送出一个新的 batch:首先,挂起的 tuple 数需要小于 “max pending” 参数;其次,距离上一个 batch 的发送已经过去了至少一个trident batch interval 的间隔时间。

如果没有数据发送,Trident 会降低发送频率吗?
是的,Storm 中有一个可选的 “spout 等待策略”,默认配置是 sleep 一段指定的配置时间。

topology.spout.wait.strategy: "org.apache.storm.spout.SleepSpoutWaitStrategy"topology.sleep.spout.wait.strategy.time.ms: 1

Trident batch interval 参数有什么用?
你知道 486 时代的计算机上面为什么有个 trubo button 吗?这个参数的作用和这个按钮有点像。

实际上,trident batch interval 有两个用处。首先,它可以用于减缓 spout 从远程数据源获取数据的速度,但这不会影响数据处理的效率。例如,对于一个从给定的 S3 存储区中读取批量上传文件并按行发送数据的 spout,我们就不希望它经常触发 S3 的阈值,因为文件要隔几分钟才会上传一次,而且每个 batch 也需要花费一定的时间来执行。

另一个用处是限制启动期间或者突发数据负载情况下内部消息队列的负载压力。如果 spout 突然活跃起来,并向系统中挤入了 10 个 batch 的记录,那么可能会有从 batch7 开始的大量不紧急的 tuple 堵塞住传输缓冲区,并且阻塞了从 batch3 中的 tuple(甚至可能包含 batch3 中的部分旧 tuple)的 commit 过程#。对于这种情况,我们的解决方法就是将 trident batch interval 设置为正常的端到端处理时延的一半左右 —— 也就是说如果需要花费 600 ms 的时间处理一个 batch,那么就可以每 300 ms 处理一个 batch。

注意,这个 300 ms 仅仅是一个上限值,而不是额外增加的延时时间,如果你的 batch 需要花费 258 ms 来运行,那么 Trident 就只会延时等待 42 ms。

9、fetch Size

在读取streaming数据流时,需要将某个时间点前的数据挂掉,然后从这个时间点开始计算指标。
问题来了,如果指定每个批次的大小很大的话,数据丢得很快,很快就可以进入处理逻辑,但是这批数据由于非常大,后面的bolt处理起来就会有问题,甚至出现OOM。
如果指定批次很小的话话,则需要很长时间才能把数据丢完,可能半天以上,基本不能接受。

解决办法:
默认情况下,每个kafka的数据文件大小为1G,因此丢弃数据时,每个分区均需要丢1G以上的数据。
减小这些topic的文件大小,如64M,则每次只需要丢掉100G左右的数据。

bin/kafka-topics.sh –create –zookeeper 10.120.69.44:2181/kafka –topic streaming_g18_sdc –partitions 20 –replication-factor 2 –config segment.bytes=67108864

10、设置拓扑的jvm

可以在拓扑级别指定Jvm参数,覆盖storm.yaml中的配置:

    config.put(Config.TOPOLOGY_WORKER_CHILDOPTS,"-Xmx2048m -Xms2048m -Xmn384m -XX:PermSize=128m -XX:+UseConcMarkSweepGC");
原创粉丝点击