• 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都要对此对象进行修改,在做修改之前一定要克隆一份,而不要直接修改!

  • 相关阅读:
    Redis基本数据结构总结之SET、ZSET和HASH
    C# .Net计算函数执行的时间
    千万级规模高性能、高并发的网络架构经验分享
    c#单元测试:使用Moq框架Mock对象
    spring bean的构造器参数
    Java并发编程:ThreadLocal
    redis过期策略
    JAVA线程的生命周期状态
    jdk1.8新特性之Optional
    对Java中interrupt、interrupted和isInterrupted的理解
  • 原文地址:https://www.cnblogs.com/cxhfuujust/p/8950315.html
Copyright © 2020-2023  润新知