Apache Storm:发射到不同螺栓的可变对象

Apache Storm: Mutable Object emitted to different bolts

几周以来,我们在项目中使用了 Storm。今天,我们发现了一个非常奇怪的行为。 假设我们有以下拓扑:


SpoutA ---> BoltB
       ---> BoltC 

因此,我们有一个 SpoutA,它向两个不同的 Bolt 发出自定义 Java 对象(我们称之为消息)。螺栓 B 和螺栓 C。基本上,我们执行拆分。

直到今天,我们假设如果 SpoutA 发出消息对象,它会在 SpoutA 上序列化并在 BoltB 和 BoltC 上反序列化。然而,这个假设似乎是错误的。今天,我们发现BoltB中的反序列化对象与BoltC中的对象完全相同(SameSystem.identitfyHashCode)。换句话说,如果我操作了BoltB中的Object,我也操作了BoltC中的Object,导致许多不可预见的副作用。

此外,这种行为对我来说似乎很奇怪,因为它只适用于 SpoutA 和相应的螺栓 B 和 C 在同一工人中 运行 的情况。如果我明确强制使用三个作品,那么该对象(正如预期的那样)是 BoltB 和 BoltC 的不同对象,因为它用于不同的 JVM。因此,如果我们假设我们有一个更大的拓扑结构(50 个不同的 bolts)运行 在三个 worker 上,那么我们永远无法确定对象当前是否在 bolts 之间共享。

所以基本上,我们真的不希望在螺栓之间共享一个对象。我们通常期望在反序列化过程中,为每个螺栓创建新的不同对象。

所以这是我的问题: 我们这里的主要缺陷是什么?我们发出 "mutable" 个对象是我们的主要缺陷吗?我们使用 serialization/deserialization 错了吗?或者它甚至可能是风暴的设计缺陷?

显然,我们可以通过仅发出字节数组来强制创建新对象,但我认为这与 Storm 相矛盾。

此致, 安德烈

为什么您希望哈希码不同?就像没有要求用户提供的哈希码值对于每个新对象实例(具有相同的字段和字段值!)一样应该不同,没有什么需要本机哈希码实现 return 不同的值,同时创建相同的对象两次。

所以回答你的问题:我们这里的主要缺陷是什么?

主要缺陷在于您对哈希码工作原理的理解。正如 Mahesh Madushanka 在评论中指出的那样,您可以解决此功能。

此外,当您序列化一个对象时,它会序列化所有内容,包括私有字段。许多 Java 对象将其哈希值缓存在私有字段中。例如。细绳。所以他们的哈希码将 return 相同的值是完全正常的(我知道你使用 System.identitfyHashCode,而 String 是 returning 一个覆盖值,但记住这一点仍然很重要) .

Storm 在将元组从一个组件移动到另一个组件时使用两种不同的排队方法,一种是两个组件位于同一 JVM 内,另一种是元组必须跨 JVM 传输。我认为您陷入了同一个 JVM 的情况,其中元组中的对象实际上并未序列化,因为只有跨 JVM 队列才需要序列化。

我总是在元组和 Java bean 之间编组和解组数据,以便为每个 bolt/spout 中的业务逻辑提供强类型接口。这样做我想我无意中避免了你遇到的问题。这可能是解决您的问题的一种方法。