继之前遇到的那个同步问题的坑之后(storm坑之---同步问题),最近对代码又做了调整和重构,并且又遇到了另一个storm开发中应该值得警惕的坑。接下来说说这个坑的大体情况。

  在我的storm程序中,Abolt需要将数据封装成一个对象同时发送给Bbolt和Cbolt各一份,Bbolt和Cbolt分别对对象做一定的处理后,更新到数据库。在查看日志时,意外的发现有些数据是不正确的诡异的,我先是怀疑算法问题,但又发现有部分数据又是正确的。算法应该没啥问题。纠结之下之后打印了更详细的日志,通过观察诡异数据的规律最后恍然大悟:肯定是Bbolt收到对象后对对象的修改影响到了Cbolt。在这里笔者几乎可以肯定的是:当Bbolt和Cbolt运行在同一个进程中时。发送给Bbolt和Cbolt的对象他们是公用的。Bbolt的修改会影响到Cbolt,反之亦然。如果Bbolt和Cbolt不是同一进程,则没有此影响。这就解释了为什么有的数据正常有的异常。

  下面举一个例子代码测试一下:

拓扑构建类:

public class Main {

	public static void main(String[] args) {
TopologyBuilder builder = new TopologyBuilder(); builder.setSpout("test", new TestWordSpout()); builder.setBolt("print1",new PrintBolt("PrintBolt1")).shuffleGrouping("test"); builder.setBolt("print2",new PrintBolt("PrintBolt2")).shuffleGrouping("test"); Config conf = new Config();
conf.setDebug(false);
conf.setNumWorkers(1);
LocalCluster cluster = new LocalCluster();
cluster.submitTopology("test-kafka-1", conf, builder.createTopology());
} }

spout类:

public class TestWordSpout extends BaseRichSpout {

	private static final long serialVersionUID = 1L;
SpoutOutputCollector _collector; public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
_collector = collector;
} public void close() { } public void nextTuple() {
Utils.sleep(1000);
Name name = new Name();
name.setName("123");
_collector.emit(new Values(name));
} public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("word"));
} }

bolt类:

public class PrintBolt extends BaseRichBolt {

	private static final long serialVersionUID = 1L;
private String name;
int taskid; public PrintBolt(String name){
this.name = name;
} @Override
public void prepare(Map stormConf, TopologyContext context,
OutputCollector collector) {
this.taskid = context.getThisTaskId(); } @Override
public void execute(Tuple input) {
Name name = (Name) input.getValueByField("word");
System.out.println(logPrefix()+name.getName());
name.setName(this.name); } private String logPrefix(){
return this.name+":";
} @Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
}
}

可能发生的执行结果:

PrintBolt2:123
PrintBolt1:123
PrintBolt2:123
PrintBolt1:123
PrintBolt2:123
PrintBolt1:123
PrintBolt2:PrintBolt1
PrintBolt2:123
PrintBolt1:123
PrintBolt1:123
PrintBolt2:123
PrintBolt1:123
PrintBolt2:123

  从上边结果可以看到,PrintBolt2打印了PrintBolt1的修改。

  了解了这个情况,以后写代码就得要考虑到这种意外。如果一个对象会同时发送给两个bolt来处理,切bolt都要对此对象进行修改,在做修改之前一定要克隆一份,而不要直接修改!

  

  

  

storm坑之---传递对象的更多相关文章

  1. Message和handler传递对象

    Bundle可以传递对象,message又可以传递Bundle于是就可以利用buddle作为中间载体传递对象了 Message msg = Message.obtain();  Bundle b =  ...

  2. Android 全局获取 Context 与使用 Intent 传递对象

    =====================全局获取 Context======================== Android 开发中很多地方需要用到 Context,比如弹出 Toast.启动活 ...

  3. Android--Intent传递对象

    Intent 传递对象通常有两种实现方式,Serializable 和 Parcelable: 一.Serializable:序列化,表示将一个对象转换成可存储或可传输的状态,序列化后的对象可以在网络 ...

  4. 实现在GET请求下调用WCF服务时传递对象(复合类型)参数

    WCF实现RESETFUL架构很容易,说白了,就是使WCF能够响应HTTP请求并返回所需的资源,如果有人不知道如何实现WCF支持HTTP请求的,可参见我之前的文章<实现jquery.ajax及原 ...

  5. Android中如何使用Intent在Activity之间传递对象[使用Serializable或者Parcelable]

    http://blog.csdn.net/cjjky/article/details/6441104 在Android中的不同Activity之间传递对象,我们可以考虑采用Bundle.putSeri ...

  6. Intent传递对象的两种方法(Serializable,Parcelable) (转)

    今天讲一下Android中Intent中如何传递对象,就我目前所知道的有两种方法,一种是Bundle.putSerializable(Key,Object);另一种是Bundle.putParcela ...

  7. Intent传递对象的两种方法

    Android为intent提供了两种传递对象参数类型的方法 分别需要使实体类实现Serializable接口.Parcelable接口 首先我们要知道,传递对象,需要先将对象序列化 一.那么为什么要 ...

  8. Android中Intent传递对象的两种方法(Serializable,Parcelable)

    今天要给大家讲一下Android中 Intent中如何传递对象,就我目前所知道的有两种方法,一种是Bundle.putSerializable(Key,Object);另一种是 Bundle.putP ...

  9. 利用Bundle在activity之间传递对象

    (2010-12-04 09:45:54) 转载▼ 标签: it 分类: android开发 转自:http://chen592969029.javaeye.com/blog/772656 假如需要在 ...

随机推荐

  1. C# 装箱和拆箱的简单理解

    一.装箱拆箱的意义 主要用途是可以向ArrayList中添加值类型的元素 二.理解 装箱的含义:理解为可以将子类对象隐式的转化为父类对象(保留自己特有的成员,和子类重写的成员) 装箱:例子为典型的装箱 ...

  2. 直接代码POST数据调用WebService

    ps:使用过webservice的童鞋大概都明白它是基于Soap协议交换数据的,同时Soap协议是对HTTP协议的扩展,其实我们就可以认为调用一个WEB服务就是通过http协议GET或POST数据的过 ...

  3. [Xamarin] 動態載入Fragment (转帖)

    這篇我們來動態加入,一樣務求好懂簡單 1.一樣先將專案調整成3.0以上版本 2.首先建立自定Control的Layout \Resources\Layout\MyControlLayout1.axml ...

  4. 【腾讯Bugly干货分享】微信终端跨平台组件 mars 系列(一) - 高性能日志模块xlog

    本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57ff5932cde42f1f03de29b1 本文来源: 微信客户端开发团队 ...

  5. Flume概述和简单实例

    Flume概述 Flume是一个分布式.可靠.和高可用的海量日志采集.聚合和传输的系统.支持在日志系统中定制各类数据发送方,用于收集数据;同时,Flume提供对数据进行简单处理,并写到各种数据接受方( ...

  6. WPF版的权限管理系统

    好多技术人员都有一个通病,不关注用户的需求,产品的可用性,只看使用的技术的新不新,潮不潮,这就是所谓的技术发烧友. 这段时间,断断续续的开发一个WPF的软件,也拿出来Show一下.要不放在硬盘里就发霉 ...

  7. [异常解决] vmware tools 虚拟机 --> 更新/导入wmwera tools菜单变灰,无法导入问题解决

    在虚拟中的装Ubuntu只要下载一个Ubuntu镜像,按照新建的指示一步一步安装 ,但是安装好之后想从原来系统中复制点东西到虚拟机中的Ubuntu中却有点麻烦.幸好Vmware自带了一个VMware ...

  8. AWS系列之三 使用EBS

    Amazon Elastic Block Store(EBS)可作为EC2实例的持久性数据块级存储.其具有高可用性和持久性的特点,可用性高达99.999%.给现有的EC2实例扩展新的存储块只需要几分钟 ...

  9. Hibernate缓存(转)

    来自:http://www.cnblogs.com/wean/archive/2012/05/16/2502724.html 一.why(为什么要用Hibernate缓存?) Hibernate是一个 ...

  10. Yosemite 升级后第三方SSD TRIM失败不能进入系统处理

    no zuo no die, 这把手欠升级到了Yosemite, 然后发现原来在Mavericks里已经激活的TRIM在这里不行了, 又提示trim enable软件不适于此版本. 然后,悲剧就开始了 ...