【问题标题】:Apache Storm: Mutable Object emitted to different boltsApache Storm:发射到不同螺栓的可变对象
【发布时间】:2016-06-30 22:14:18
【问题描述】:

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


SpoutA ---> BoltB
       ---> BoltC 

所以,我们有一个 SpoutA,它向两个不同的 Bolt 发出一个自定义 Java 对象(我们称之为消息)。 BoltB 和 BoltC。基本上,我们执行拆分。

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

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

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

所以这是我的问题: 我们这里的主要缺陷是什么?我们发出“可变”对象是我们的主要缺陷吗?我们是否使用了错误的序列化/反序列化?或者它甚至可能是风暴的设计缺陷?

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

最好的问候, 安德烈

【问题讨论】:

  • 目前我们正在生产中运行 40 螺栓风暴进程,最初我们遇到了更棘手的问题,因此当我们将对象从一个螺栓解析到另一个螺栓时,我们使用 xml 序列化,它将作为 xml 字符串传递。它解决了我们的问题
  • 是的,我们还考虑过实现我们自己的序列化/反序列化(但随后在字节级别)。另一种解决方案是按照约定将传输的对象明确定义为不可变的。但是,我希望可能有更好的解决方案(例如,只是一个强制风暴分别反序列化对象的设置......)
  • 是的,您可以将这些汇总到选项中

标签: java apache-storm mutable


【解决方案1】:

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

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

【讨论】:

  • 是的,谢谢你的详细解释。半小时前,我还在以下演示文稿(de.slideshare.net/miguno/…)中读到了一些关于此的内容。但是,我不明白为什么 Storm 网站上没有记录这一点。编组和解组确实可以解决问题,但也可能会降低性能。
【解决方案2】:

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

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

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

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

【讨论】:

  • 这与哈希码无关。我真的不关心HashCode。我关心由两个不同的螺栓反序列化的对象仍然是相同的(不仅在哈希码方面)。如果我修改 BoltB 中的对象,它也会在 BoltC 中更改。这会导致无法定义的行为,因为无法确定 Bolt 是在同一虚拟机中执行还是在不同虚拟机中执行。因此,人们无法确定是否获得了两个相同或相等的不同对象。因此,在我看来,它不是 Apache Storm 的一个特性,而是一个 Bug。
  • @Vion 所以我不明白,你认为哈希码是相同的,因为对象是相同的。但这种假设是不正确的。那么你是如何检查这些对象是否相同的呢?您是否对他们的参考进行了“==”比较?因为这就是使两个对象相同的原因。
  • 我们通过操作 BoltB 中接收到的对象的属性(例如,计数器)并读取 BoltC 中的属性(计数器)来检查对象是否相同。我们在 BoltB 中将属性更改为的值随后在 BoltC 中可用 => BoltB 接收的对象与 BoltC 接收的对象完全相同...我在 BoltB 中对对象应用的每个修改也适用于 BoltC ...(就像在一个简单的线程场景中一样......)
  • 好的。很高兴知道。很高兴您发现了这一点。
猜你喜欢
  • 2014-07-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多