在充分了解节点计算机硬件资源的情况下进行Storm运行性能的调优。
Storm运行性能调优主要是从以下几个方面:
(1)代码层面,这得看程序编写者的功力了。
(2)并行度层面,分为:
setNumWorkers取值;
kafkaSpout取值(假设是从Kafka中读取数据);
Bolt取值;
shuffleGrouping和fieldsGrouping的选择等。
1. setNumWorkders
worker 可以分配到不同的 supervisor 节点上,这是 Storm 实现多节点并行计算的主要配置手段。在一定程度上workers 的数量越多越好,但实际生产硬件资源有限。所以主要考虑集群中各节点的内存情况:默认情况下,一个 worker 分配 768M 的内存,外加 64M 给 logwriter 进程;因此一个 worker 会耗费 832M 内存;假设集群有3个节点,每个节点4G内存,除去 Linux 系统、kafka、zookeeper 等的消耗,保守估计仅有2G内存可用来运行 topology,由此可知,当集群只有一个 topology 在运行的情况下,最多可以配置6个 worker。
此外,还可以调节 worker 的内存空间。这取决于流过 topology 的数据量的大小以及各 bolt 单元的业务代码的执行时间。如果数据量特别大,代码执行时间较长,那么可以考虑增加单个 worker 的工作内存。有一点需要注意的是,一个 worker 下的所有 executor 和 task 都是共享这个 worker 的内存的,也就是假如一个 worker 分配了 768M 内存,3个 executor,6个 task,那么这个 3 executor 和 6 task 其实是共用这 768M 内存的,但是好处是可以充分利用多核 CPU 的运算性能。
2. kafkaSpout
如果 spout 读取的是 kafka 的数据,那么正常情况下,设置为 topic 的分区数量即可。计算 kafkaSpout 的最佳取值,有一个最简单的办法,就是在 Storm UI里面,点开 topology 的首页,在 Spouts (All time) 下,查看以下几个参数的值:
看这几个参数的技巧:
kafka 只能保证同一分区下消息的顺序性,当 spout 配置了多个 executor 的时候,不同分区的消息会均匀的分发到不同的 executor 上消费,那么消息的整体顺序性就难以保证了,除非将 spout 并行度设为 1
其取值也有一个简单办法,就是在 Storm UI里面,点开 topology 的首页,在 Bolts (All time) 下,查看以下几个参数的值:
3个参数对性能来说参考意义比较明显,包括Execute latency, Process latency, Capacity,
具体的意义如下:
Execute latency:消息的平均处理时间,单位为毫秒。
Process latency:消息从接收到被ack掉所花的时间,单位为毫秒。如果没有启用ACKER机制,那么Process latency的值为0。
Capacity:计算公式为Capacity = Bolt或者Executor调用execute()处理的消息数量×消息平均执行时间/时间区间。如果这个值越接近1,说明Bolt或者Executor基本一直在调用executer(),因此并行度不够,需要扩展这个组件的Executor数量。
一般情况下,按照该 bolt 的代码时间复杂度,设置一个 spout 并行度的 1-3倍即可。
4.优化配置参数
/** tuple发送失败重试策略,一般情况下不需要调整 */
spoutConfig.retryInitialDelayMs = 0;
spoutConfig.retryDelayMultiplier = 1.0;
spoutConfig.retryDelayMaxMs = 60 * 1000;
/** 此参数比较重要,可适当调大一点 */
/** 通常情况下 spout 的发射速度会快于下游的 bolt 的消费速度,当下游的 bolt 还有 TOPOLOGY_MAX_SPOUT_PENDING 个 tuple 没有消费完时,spout 会停下来等待,该配置作用于 spout 的每个 task。 */
conf.put(Config.TOPOLOGY_MAX_SPOUT_PENDING, 10000)
/** 调整分配给每个 worker 的内存,关于内存的调节,上文已有描述 */
conf.put(Config.WORKER_HEAP_MEMORY_MB, 768);
conf.put(Config.TOPOLOGY_WORKER_MAX_HEAP_SIZE_MB, 768);
/** 调整 worker 间通信相关的缓冲参数,以下是一种推荐的配置 */
conf.put(Config.TOPOLOGY_RECEIVER_BUFFER_SIZE, 8); // 1.0 以上已移除
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);
worker内存的配置也可以在yaml配置文件中写入。可以在 Storm UI 上查看当前集群的 Topology Configuration
Storm中真正干活的是各个worker,而worker由supervisor负责启动。在topology启动过程中可以看到如下的启动日志:
这就是启动一个worker进程,也就是一个JVM进程。默认情况下,Storm启动worker进程时,JVM的最大内存是768M。但在使用过程中,由于会在Bolt中加载大量数据,768M内存无法满足需求,会导致内存溢出程序崩溃。可以通过在Strom的配置文件storm.yaml中设置worker的启动参数:
可以直接采用 rebalance 命令(也可以在 Storm UI上操作)重新配置 topology 的并行度:
storm rebalance TOPOLOGY-NAME -n 5 -e SPOUT/BOLT1-NAME=3 -e SPOUT/BOLT2-NAME=10
GC参数优化:
可以对每个worker的java内存参数进行调整,配置在conf/storm.yaml文件中,
可以通过在Strom的配置文件storm.yaml中设置worker的启动参数:
一个比较简单的启用CMS的GC配置可以为:
也可以在worker.childopts的参数中加入打印GC的日志进行GC性能的优化。
-XX:+PrintGCDetails -Xloggc:d:\gc.log
参考文献:
【1】http://www.jianshu.com/p/f645eb7944b0
【2】https://my.oschina.net/u/2326085/blog/391271