几个星期以来,我们在项目中使用Storm。今天,我们发现了一种非常奇怪的行为。 假设我们有以下拓扑:
SpoutA ---> BoltB
---> BoltC
因此,我们有一个SpoutA,它将自定义Java对象(我们称之为Message)发送到两个不同的螺栓。 BoltB和BoltC。基本上,我们进行拆分。
直到今天,我们假设如果SpoutA发出消息对象,它会在SpoutA上序列化并在BoltB和BoltC上反序列化。但是,这种假设似乎是错误的。今天,我们发现BoltB中的反序列化对象与BoltC中的对象相同(相同的System.identitfyHashCode)。换句话说,如果我操纵BoltB中的Object,我也会操纵BoltC中的Object,导致许多无法预料的副作用。
此外,这种行为对我来说似乎很奇怪,因为它只适用于SpoutA和相应的螺栓B和C在同一个工作器中运行的情况。如果我明确强制使用三个作品,那么该对象(如预期的那样)是BoltB和BoltC的不同对象,因为它用于不同的JVM。因此,如果我们假设我们在三个工人上运行了更大的拓扑(50个不同的螺栓),那么我们永远无法确定当前是否在螺栓之间共享对象。
所以基本上,我们真的不希望在螺栓之间共享一个Object。我们通常希望在反序列化期间,为每个螺栓创建新的不同对象。
所以这是我的问题: 我们的主要缺点是什么?我们发出“可变”对象的主要缺陷是什么?我们使用序列化/反序列化是错误的吗?或者它甚至可能是风暴的设计缺陷?
显然,我们可以通过发送字节数组来强制创建新对象,但在我看来这与Storm相矛盾。
祝你好运, 安德烈
答案 0 :(得分:1)
当将元组从一个组件移动到另一个组件时,Storm使用两种不同的排队方法,一种是两个组件在同一个JVM中,另一个是元组必须穿过JVM的组件。我认为你已经陷入同样的JVM案例中,元组中的对象实际上并没有被序列化,因为只有跨JVM队列才需要序列化。
我总是对元组和Java bean之间的数据进行编组和解组,以便为每个bolt / spout中的业务逻辑提供强类型接口。这样做,我想我无意中避免了你遇到的问题。这可能是解决问题的一种方法。
答案 1 :(得分:0)
为什么期望哈希码不同?就像没有要求用户提供的哈希码值对于每个新对象实例(具有相同的字段和字段值!)不同,没有什么要求本机哈希码实现在创建同一对象两次时返回不同的值。 / p>
所以回答你的问题:我们的主要缺陷是什么?
主要缺陷是您了解hashcode的工作原理。正如Mahesh Madushanka在评论中指出的那样,你可以解决这个问题。
此外,当您序列化对象时,它会序列化所有内容,包括私有字段。许多Java对象将其哈希值缓存在私有字段中。例如。串。因此,他们的hashcode将返回相同的值是完全正常的(我知道你使用System.identitfyHashCode,并且String返回一个被覆盖的值,但这仍然很重要)。