storm坑之---传递对象

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

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

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

拓扑构建类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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) {
     }
}

可能发生的执行结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
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都要对此对象进行修改,在做修改之前一定要克隆一份,而不要直接修改!

转载于:https://www.cnblogs.com/cxhfuujust/p/8950315.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值