Muss die Storm-Topologie gemeinsam genutzte Elementvariablen in der Execute- oder nextTuple-Methode synchronisieren?

Hier ist ein einfacher Storm-Topologie-Code, der im Standalone-Modus ausgeführt wird und zur Beobachtung der Ausführungsreihenfolge jedes Moduls in der Storm-Topologie verwendet werden kann.
Es kann mit Storm-0.9.x ausgeführt werden. Verwenden Sie eine IDE, z. B. Idee, um ein Maven-Projekt zu erstellen, und fügen Sie dann die folgenden Abhängigkeiten in pom.xml hinzu:

       <dependency>
            <groupId>org.apache.storm</groupId>
            <artifactId>storm-core</artifactId>
            <version>0.9.3</version>
            <scope>compile</scope>
        </dependency>
import backtype.storm.Config;
import backtype.storm.LocalCluster;
import backtype.storm.StormSubmitter;
import backtype.storm.spout.SpoutOutputCollector;
import backtype.storm.task.OutputCollector;
import backtype.storm.task.TopologyContext;
import backtype.storm.topology.OutputFieldsDeclarer;
import backtype.storm.topology.TopologyBuilder;
import backtype.storm.topology.base.BaseRichBolt;
import backtype.storm.topology.base.BaseRichSpout;
import backtype.storm.tuple.Fields;
import backtype.storm.tuple.Tuple;
import backtype.storm.tuple.Values;
import backtype.storm.utils.Utils;

import java.util.Map;
import java.util.Random;

/**
 * This is a basic example of a Storm topology.
 *
 * 探究对象的变量在被多个线程共享时,Storm是否已经对它进行同步了?
 * 比如ExclamationBolt中的成员变量i,当设置其并行度为13时,其execute方法的打印结果
 * 是同一个i值会被打印13次。
 *
 * 结论:execute()方法中调用的公共方法或共享变量都会被Storm同步。
 */
public class TestCountTopology {
    
    

    public static class ExclamationBolt extends BaseRichBolt {
    
    
        private static final long serialVersionUID = 6618890434446310020L;

        OutputCollector _collector;
        TopologyContext _context;
        int i = 0; //这个变量被多个线程共享时,是否被Storm同步了?

        @Override
        public void prepare(Map conf, TopologyContext context,
                OutputCollector collector) {
            _collector = collector;
            System.out.println("prepare in BOLT is called!");
            _context = context;
        }

        @Override
        public void execute(Tuple tuple) {
            System.out.println("execute in BOLT is called! " + i);
            System.err.println("Worker_port: " + _context.getThisWorkerPort()
                    + " tasks: " + _context.getThisWorkerTasks()
                    + " task_id: " + _context.getThisTaskId() + " BOLT receive: "
                    + new Values(tuple.getString(0)) + " i: " + i);
            inc();
            _collector.emit(tuple, new Values(tuple.getString(0) + "!!!"));
            _collector.ack(tuple);
        }

        @Override
        public void declareOutputFields(OutputFieldsDeclarer declarer) {
            declarer.declare(new Fields("word"));
        }

        private void inc() {
            i++;
            System.err.println("task_id: " + _context.getThisTaskId() + " inc() was called");
        }
    }

    public static class WordSpout extends BaseRichSpout {
    
    
        private static final long serialVersionUID = 6962615351294880911L;

        SpoutOutputCollector _collector;
        int i = 0;

        @Override
        public void open(Map conf, TopologyContext context,
                SpoutOutputCollector collector) {
            _collector = collector;
            System.err.println("open in SPOUT is called!");
        }

        @Override
        public void nextTuple() {
            System.out.println("nextTuple in SPOUT is called! " + i);
            Utils.sleep(100);
            final String[] words = new String[] { "nathan", "mike", "jackson",
                    "golda", "bertels" };
            final Random rand = new Random();
            final String word = words[rand.nextInt(words.length)];
            _collector.emit(new Values(word));
            System.out.println("SPOUI emit: " + new Values(word) + " i: " + i);
            i++;
        }

        @Override
        public void declareOutputFields(OutputFieldsDeclarer declarer) {
            declarer.declare(new Fields("word"));
            System.out.println("declareOutputFields in SPOUT is called!");
        }

        public void ack(Object msgId) {
            System.out.println("ack in SPOUT is called!");
        }

        public void fail(Object msgId) {
            System.out.println("fail in SPOUT is called!");
        }

        public void close() {
            System.out.println("close in SPOUT is called!");
        }

    }

    public static void main(String[] args) throws Exception {
        TopologyBuilder builder = new TopologyBuilder();

        // builder.setSpout("word", new TestWordSpout(), 10);
        builder.setSpout("word", new WordSpout(), 1);
        builder.setBolt("exclaim1", new ExclamationBolt(), 13).shuffleGrouping("word");
        //builder.setBolt("exclaim2", new ExclamationBolt(), 3).shuffleGrouping("exclaim1");

        Config conf = new Config();
        conf.setDebug(false);// TOPOLOGY_DEBUG
        conf.setNumWorkers(2);

        if (args != null && args.length > 0) {
            conf.setNumWorkers(3);// TOPOLOGY_WORKERS

            StormSubmitter.submitTopologyWithProgressBar(args[0], conf,
                    builder.createTopology());
        } else {

            LocalCluster cluster = new LocalCluster();
            cluster.submitTopology("test", conf, builder.createTopology());
            Utils.sleep(10000);
            cluster.killTopology("test");
            cluster.shutdown();
            /*
             * comment out the cluster.killTopology() and cluster.shutdown()
             * methods, to avoid the file deletion error.
             */
        }
    }
}

Die Topologie von zwei Knoten, WordSpout- Methode nextTuple wird wiederholt ausgeführt, wobei jedes Mal ein zufälliger Wortstrom ausgewählt wird , der an die Wörter aus dem Zeichenarray gesendet wird. Der ExclamationBolt liest das Wort aus dem Strom und fügt dahinter drei Ausrufezeichen "!!!" vor dem Senden an den Stream.

Beispielsweise erzeugt WordSpout das Wort "nathan", dann erzeugt ExclamationBolt "nathan !!!".

Im obigen Code wird die Parallelität von ExclamationBolt Bolt auf 13 gesetzt, was bedeutet, dass Storm 13 Threads generiert und jeder Thread die Bolt- Ausführungsmethode wiederholt ausführt und auf den Wert der Variablen i in dieser Methode zugegriffen wird um 1 erhöhen.

F: Müssen wir diese Variable synchronisieren, da sie von mehreren Threads gemeinsam genutzt und geändert wird?

A: Nein. Führen Sie die Topologie aus, um herauszufinden, dass die Ausführungsmethode von * ExclamationBolt jedem empfangenen Wort "!!!" hinzufügt, und drucken Sie es 13 Mal. Die Variable i wird 13 Mal mit demselben Wert gedruckt, bevor sie um 1 erhöht wird Dies zeigt, dass Storm uns geholfen hat, die Synchronisation abzuschließen.

Ich denke du magst

Origin blog.csdn.net/lx1848/article/details/69663755
Empfohlen
Rangfolge