Storm の基本を始める

創造し続け、成長を加速!「ナゲッツデイリー新プラン・10月アップデートチャレンジ」参加5日目、イベント詳細はこちら

1. コンセプト紹介

1. Storm は、大量のデータを扱うリアルタイム ストリーム コンピューティングです

  • メッセージの処理とリアルタイムでのデータベースの更新、リアルタイムのデータ ストリームのクエリまたは計算、最新の結果の表示用クライアントへのプッシュ、分散 RPC 呼び出しに基づく時間のかかるクエリの並列化など、さまざまなリアルタイム シナリオをサポートします。
  • 高いスケーラビリティ: 拡張、マシンの追加、および並列処理の調整が容易
  • データ損失なしの保証
  • 超堅牢性
  • 使いやすさ: コア セマンティクスは非常にシンプルです

3. 操作手順

WeChat screenshot_20191020103909.png

4. 名詞の紹介

  • 並列処理: タスクです。スパウト/ボルト コードの各コピーがタスクで実行されます。
  • フローのグループ化: タスクとタスク間のデータ フローの関係
    • ストリームのグループ化戦略: シャッフル グループ化: ランダム放出
    • フィールドのグループ化: 1 つ以上のフィールドに基づいて出力

5. 開始例

package com.mmc.storm;

import lombok.extern.slf4j.Slf4j;
import org.apache.storm.Config;
import org.apache.storm.LocalCluster;
import org.apache.storm.StormSubmitter;
import org.apache.storm.generated.AlreadyAliveException;
import org.apache.storm.generated.AuthorizationException;
import org.apache.storm.generated.InvalidTopologyException;
import org.apache.storm.spout.SpoutOutputCollector;
import org.apache.storm.task.OutputCollector;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.topology.TopologyBuilder;
import org.apache.storm.topology.base.BaseRichBolt;
import org.apache.storm.topology.base.BaseRichSpout;
import org.apache.storm.tuple.Fields;
import org.apache.storm.tuple.Tuple;
import org.apache.storm.tuple.Values;

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

/**
 * @description: 单词统计
 * @author: mmc
 * @create: 2019-10-21 22:47
 **/
@Slf4j
public class WordCountTopology {

    /**
     * 负责从数据源获取数据
     */
    public static class RandomSentenceSpout extends BaseRichSpout{

        private SpoutOutputCollector collector;

        private Random random;

        @Override
        public void open(Map map, TopologyContext topologyContext, SpoutOutputCollector spoutOutputCollector) {
            this.collector=spoutOutputCollector;
            this.random=new Random();
        }

        /**
         * 它会运行在task中,也就是说task会不断的循环调用它,就可以不断的发射新的数据,形成一个数据流
         */
        @Override
        public void nextTuple() {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            String[] sentences = new String[]{"the cow jumped over the moon", "an apple a day keeps the doctor away",
                    "four score and seven years ago", "snow white and the seven dwarfs", "i am at two with nature"};
            String sentence=sentences[random.nextInt(sentences.length)];
            log.info("发送一段句子:"+sentence);
            //这个Values,你可以理解为是构建一个Tuple,tuple是最小的数据单位
            collector.emit(new Values(sentence));
        }

        /**
         * 定义发送出去的tuple的字段的名称
         * @param outputFieldsDeclarer
         */
        @Override
        public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
            outputFieldsDeclarer.declare(new Fields("sentence"));
        }
    }


    /**
     * 每一个Bolt代码也是发送到task里面去运行
     */
    public static class SplientSentence extends BaseRichBolt{

        private OutputCollector collector;

        @Override
        public void prepare(Map map, TopologyContext topologyContext, OutputCollector outputCollector) {
            this.collector=outputCollector;
        }

        /**
         * 每接受到一条数据都会交给execute方法去处理
         * @param tuple
         */
        @Override
        public void execute(Tuple tuple) {
            String sentence=tuple.getStringByField("sentence");
            String[] words=sentence.split(" ");
            for (String word:words){
                collector.emit(new Values(word));
            }
        }

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


    public static class WordCount extends BaseRichBolt{

        private OutputCollector collector;

        private Map<String,Long> wordCountMap=new HashMap<>();

        @Override
        public void prepare(Map map, TopologyContext topologyContext, OutputCollector outputCollector) {
            this.collector=outputCollector;
        }

        @Override
        public void execute(Tuple tuple) {
            String word=tuple.getStringByField("word");
            Long count=wordCountMap.get(word);
            if(count==null){
                count=1L;
            }else {
                count++;
            }
            wordCountMap.put(word,count);
            log.info("【单词计数:】{}出现的次数是{}",word,count);
            collector.emit(new Values(word,count));

        }

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

    public static void main(String[] args) throws InterruptedException {
        //将Spolt和Bolts组合起来,形成一个拓扑
        TopologyBuilder builder=new TopologyBuilder();
        builder.setSpout("RandomSentence",new RandomSentenceSpout(),2);
        builder.setBolt("SplitSentence",new SplientSentence(),5).setNumTasks(10).shuffleGrouping("RandomSentence");
        builder.setBolt("WordCount",new WordCount(),10).setNumTasks(20).
                fieldsGrouping("SplitSentence",new Fields("word"));
        Config config=new Config();

        //命令行执行
        if(args!=null&&args.length>0){
            config.setNumWorkers(3);
            try {
                StormSubmitter.submitTopology(args[0],config,builder.createTopology());

            } catch (AlreadyAliveException e) {
                e.printStackTrace();
            } catch (InvalidTopologyException e) {
                e.printStackTrace();
            } catch (AuthorizationException e) {
                e.printStackTrace();
            }
        }else {
            config.setMaxTaskParallelism(20);
            LocalCluster cluster=new LocalCluster();
            cluster.submitTopology("WordCountTopology",config,builder.createTopology());
            Thread.sleep(60000);
            cluster.shutdown();
        }
    }
}

复制代码


2.クラスター展開

  1. ダウンロード ストームの
    ダウンロード アドレス: www.apache.org/dyn/closer.…
  2. 環境変数の設定
    vi ~/.bashrc
export STORM_HOME=/usr/local/storm
export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin:$ZOOKEEPER_HOME/bin:$JAVA_HOME/bin:$STORM_HOME/bin
复制代码

source ~/.bashrc 3. 構成を変更します
storm/conf/storm.yaml を開き、次の構成を追加します。

storm.zookeeper.servers:
     - "192.168.1.12"
     - "192.168.1.13"
     - "192.168.1.14"

nimbus.seeds: ["192.168.1.12"]

storm.local.dir: "/var/storm"
 
supervisor.slots.ports:
   - 6700
   - 6701
   - 6702
   - 6703
复制代码

4. フォルダを作成する

mkdir /var/storm
复制代码

5. 開始

  • 最初に Zookeeper を開始します
  • ノードが嵐のニンバスを開始 >/dev/null 2>&1 &
  • 3 つのノードすべてが、ストーム スーパーバイザー >/dev/null 2>&1 & を実行します。
  • ノード ストーム ui>/dev/null 2>&1 &
  • 2 つのスーパーバイザ ノードが logviewer >/dev/null 2>&1 & をストームします。

6. ストーム キル wordCountTopology を閉じます

おすすめ

転載: juejin.im/post/7149900895164039204