问题与解决
本文介绍了用户在使用 Storm 过程中遇到的问题与相应的解决方法。
Worker 进程在启动时挂掉而没有留下堆栈跟踪信息的问题
可能出现的现象:
- 拓扑在一个节点上运行正常,但是多个 worker 进程在多个节点上就会崩溃
解决方案:
- 你的网络配置可能有问题,导致每个节点无法根据 hostname 连接到其他的节点。ZeroMQ 有时会在不能识别 host 的时候挂掉 进程。如果是这种情况,有两种可行的解决方案:
- 在 /etc/hosts 文件中配置好 hostname 与 IP 的对应关系
- 设置一个局域网 DNS 服务器,使得节点可以根据 hostname 定位到其他节点
节点之间无法通信
可能出现的现象:
- 每个 spout tuple 的处理都不成功
- 拓扑中的处理过程不起作用
解决方案:
- Storm 不支持 ipv6,你可以在 supervisor 的 child-opts 配置中添加
-Djava.net.preferIPv4Stack=true
参数,然后重启 supervisor。 - 你的网络配置可能存在问题,请参考上个问题中的解决方案。
拓扑在一段时间后停止了 tuple 的处理过程
可能出现的现象:
- 拓扑正常运行一段时间后突然停止了数据处理过程,并且 spout 的 tuple 一起开始处理失败
解决方案:
- 这是 ZeroMQ 2.1.10 中的一个已经确认的问题,请将 ZMQ 降级到 2.1.7 版本。
Storm UI 中没有显示出所有的 supervisor 信息
可能出现的现象:
- Storm UI 中缺少部分 supervisor 的信息
- 在刷新 Storm UI 页面后 supervisor 列表会变化
解决方案:
- 确保 supervisor 的本地工作目录是相互独立的(也就是说不要出现在 NFS 中共享同一个目录的情况)
- 尝试删除 supervisor 的本地工作目录,然后重启 supervisor 后台进程。supervisor 启动时会为自己创建一个唯一的 id 并存储在本地目录中。如果这个 id 被复制到其他节点中,就会让 Storm 无法确定哪个 supervisor 正在运行(这种情况并不少见,如果需要扩展集群,就很容易出现直接将某个节点的 Storm 文件直接复制到新节点的情况 —— 译者注)。
“Multiple defaults.yaml found” 错误
可能出现的现象:
- 在使用
storm jar
命令部署拓扑时出现此错误
解决方案:
- 你很可能在拓扑的 jar 包中包含了 Storm 自身的 jar 包。注意,在打包拓扑时,请不要将 Storm 自身的 jar 包加入,因为 Storm 已经在它的 classpath 中提供了这些 jar 包。
运行 storm jar 命令时出现 “NoSuchMethorError”
可能出现的现象:
- 运行
storm jar
命令时出现奇怪的 “NoSuchMethodError”
解决方案:
- 这可能是由于你部署拓扑的 Storm 版本与你构建拓扑时使用的 Storm 版本不同。请确保你编译拓扑时使用的 Storm 版本与你运行拓扑的 Storm 客户端版本相同。
Kryo ConcurrentModificationException
可能出现的现象:
- 系统运行时出现如下的异常堆栈跟踪信息
java.lang.RuntimeException: java.util.ConcurrentModificationException
at backtype.storm.utils.DisruptorQueue.consumeBatchToCursor(DisruptorQueue.java:84)
at backtype.storm.utils.DisruptorQueue.consumeBatchWhenAvailable(DisruptorQueue.java:55)
at backtype.storm.disruptor$consume_batch_when_available.invoke(disruptor.clj:56)
at backtype.storm.disruptor$consume_loop_STAR_$fn__1597.invoke(disruptor.clj:67)
at backtype.storm.util$async_loop$fn__465.invoke(util.clj:377)
at clojure.lang.AFn.run(AFn.java:24)
at java.lang.Thread.run(Thread.java:679)
Caused by: java.util.ConcurrentModificationException
at java.util.LinkedHashMap$LinkedHashIterator.nextEntry(LinkedHashMap.java:390)
at java.util.LinkedHashMap$EntryIterator.next(LinkedHashMap.java:409)
at java.util.LinkedHashMap$EntryIterator.next(LinkedHashMap.java:408)
at java.util.HashMap.writeObject(HashMap.java:1016)
at sun.reflect.GeneratedMethodAccessor17.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
at java.io.ObjectStreamClass.invokeWriteObject(ObjectStreamClass.java:959)
at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1480)
at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1416)
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346)
at backtype.storm.serialization.SerializableSerializer.write(SerializableSerializer.java:21)
at com.esotericsoftware.kryo.Kryo.writeClassAndObject(Kryo.java:554)
at com.esotericsoftware.kryo.serializers.CollectionSerializer.write(CollectionSerializer.java:77)
at com.esotericsoftware.kryo.serializers.CollectionSerializer.write(CollectionSerializer.java:18)
at com.esotericsoftware.kryo.Kryo.writeObject(Kryo.java:472)
at backtype.storm.serialization.KryoValuesSerializer.serializeInto(KryoValuesSerializer.java:27)
解决方案:
- 这个信息表示你在将一个可变的对象作为 tuple 发送出去。你发送到 outputcollector 中的所有对象必须是非可变的。这个错误表明对象在被序列化并发送到网络中时你的 bolt 正在修改这个对象。
Storm 中的 NullPointerException
可能出现的现象:
- Storm 运行中出现了如下的 NullPointerException
java.lang.RuntimeException: java.lang.NullPointerException
at backtype.storm.utils.DisruptorQueue.consumeBatchToCursor(DisruptorQueue.java:84)
at backtype.storm.utils.DisruptorQueue.consumeBatchWhenAvailable(DisruptorQueue.java:55)
at backtype.storm.disruptor$consume_batch_when_available.invoke(disruptor.clj:56)
at backtype.storm.disruptor$consume_loop_STAR_$fn__1596.invoke(disruptor.clj:67)
at backtype.storm.util$async_loop$fn__465.invoke(util.clj:377)
at clojure.lang.AFn.run(AFn.java:24)
at java.lang.Thread.run(Thread.java:662)
Caused by: java.lang.NullPointerException
at backtype.storm.serialization.KryoTupleSerializer.serialize(KryoTupleSerializer.java:24)
at backtype.storm.daemon.worker$mk_transfer_fn$fn__4126$fn__4130.invoke(worker.clj:99)
at backtype.storm.util$fast_list_map.invoke(util.clj:771)
at backtype.storm.daemon.worker$mk_transfer_fn$fn__4126.invoke(worker.clj:99)
at backtype.storm.daemon.executor$start_batch_transfer__GT_worker_handler_BANG_$fn__3904.invoke(executor.clj:205)
at backtype.storm.disruptor$clojure_handler$reify__1584.onEvent(disruptor.clj:43)
at backtype.storm.utils.DisruptorQueue.consumeBatchToCursor(DisruptorQueue.java:81)
... 6 more
解决方案:
- 这个问题是由于多个线程同时调用
OutputCollector
中的方法造成的。Storm 中所有的 emit、ack、fail 方法必须在同一个线程中运行。出现这个问题的一种场景是在一个IBasicBolt
中创建了一个独立的线程。由于IBasicBolt
会在execute
方法调用之后自动调用ack
,所以这就会出现多个线程同时使用OutputCollector
的情况,进而抛出这个异常。也就是说,在使用IBasicBolt
时,所有的消息发送操作必须在同一个线程的execute
方法中执行。