让我们看一个示例拓扑。
假设您的拓扑变为 spout -> bolt1,并且您正在从 spout 发出 MyObject 实例。
假设您已将拓扑设置为在 1 个工作人员中运行。
当从 spout 发出一个元组(例如 MyObject@1234)时,Storm 将检查该元组是否需要转到另一个工作人员。如果没有,它只是将对象引用传递给bolt1。这就是您只有 1 个工人时所看到的。当 MyObject@1234 需要从 spout 转移到 bolt 时,Storm 只是将 MyObject@1234 引用交给 bolt。
现在假设你告诉拓扑使用 2 个 worker,Storm 决定将 spout 放在 worker 1 中,将 bolt 放在 worker 2 中。回想一下,每个 worker 都是一个单独的 JVM 进程,因此将对象引用从 worker 1 传递给 worker 2不会工作。
当元组从 spout 发出时,Storm 会看到它正在发送给另一个工作人员,并根据您的配置使用 Kryo 或 Java 序列化对其进行序列化。这意味着 MyObject@1234 被序列化。Storm 将序列化的表单交给 worker 2,后者将其反序列化。当它被反序列化时,它被非常合理地赋予了一个新的内存地址(例如MyObject@6789)。
如果您设计螺栓以假设它们不在同一个 JVM 中运行,这不是问题,您绝对应该这样做。例如,如果您想将 MyObject 从 worker 1 传输到 worker 2,您可以将其设为 Serializable,或者您可以将其注册到 Kryo(参见https://storm.apache.org/releases/2.0.0-快照/序列化.html )。您需要这样做,以便 Storm 可以将您的 spout 和 bolts 放在单独的 JVM 中,而不会破坏您的拓扑。
测试拓扑时,应启用https://storm.apache.org/releases/1.2.2/javadocs/org/apache/storm/Config.html#TOPOLOGY_TESTING_ALWAYS_TRY_SERIALIZE。这将导致 Storm 始终序列化您的元组,即使元组没有在工作人员之间传输。这可以帮助您在序列化问题投入生产之前发现它们。
顺便说一句,您应该始终更喜欢 Kryo 序列化而不是 Java 序列化。Kryo 序列化要快得多。