Storm ExclamationTopology源码解析

ExclamationTopology源码解析


/*这个Topology包含一个Spout和两个Bolt。Spout发射单词, 每个bolt在每个单词后面加个”!!!”。这三个节点被排成一条线: spout发射单词给第一个bolt加三个“!”, 第一个bolt把处理好的单词发射给第二个bolt再加三个“!”。*/

public class FirstTopology {

  /*这个例子的Spout组件是调用的storm-core包里的一个TestWordSpout类,它主要是随机发射一个单词,Spout类的定义方式我们在下个例子中讲,这个例子只用定义一个Bolt组件ExclaimtionBolt,它继承自BaseRichBolt,,实现IRichBolt接口,功能就是加感叹号,在Bolt组件中有两个方法是我们常用的,prepare方法主要做一些准备工作,当该组件的任务在群集中的工作程序中初始化时调用。它为Bolt提供执行的环境,并给它提供一个Outputcollector(输出集合)用来发射tuple;第二个是execute方法,它用来处理一个单独的输入元组,在这个方法里用户可以定义想要实现的计算功能。*/

public static class ExclamationBolt extends BaseRichBolt {

//首先创建一个输出集合用来存放和发射消息
      OutputCollector _collector;

    /*接下来重写函数prepare,当该组件的任务在集群中初始化时调用。它需要输入三个参数,第一个conf是这个Bolt的storm配置文件中的配置,;第二个是TopologyContext类类型context,用于获取有关拓扑中该任务位置的信息,包括任务ID和组件ID,输入和输出信息等;第三个是OutputcoCollector输出集合类型的发射器collector,该发射器用于从该Bolt发出元组Tuple。这里prepare方法只是简单地把OutputCollector作为一个类字段保存下来给后面execute方法使用,也就是初始化发射器*/
public void prepare(Map conf, TopologyContext context, OutputCollector collector) 
{
      _collector = collector;
    }

    /*下一步重写函数execute,它只有一个输入参数就是要处理的消息输入元组tuple, 此处execute方法从bolt的一个输入接收tuple(一个bolt可能有多个输入源)。ExclamationBolt获取tuple的第一个字段,加上”!!!”之后再发射出去。*/
public void execute(Tuple tuple) {
      //tuple为输入的数据,在它后面加三个感叹号作为新的值被集合发射给下一个Bolt
      _collector.emit(tuple, new Values(tuple.getString(0) + "!!!"));
      //这个ack是storm的一种消息传输保证机制,简单说就是监督tuple有没有在各个组件之间正常传输。
      _collector.ack(tuple);
    }

    /*前面我们讲过源源不断的消息tuple会形成数据流,各个组件之间的消息是以流的形式传递的, 所以最后我们还应该声明此拓扑流的输出模式,declarer用于声明输出流ID,输出字段以及每个输出流是否是直接流等,此处是声明了一个字段word用于下一个组件进行消息流的识别*/
    public void declareOutputFields(OutputFieldsDeclarer declarer) {
      declarer.declare(new Fields("word"));
    }
  }

 /*至此,Bolt组件就定义完了,有了发射组件类spout,执行组件类Bolt,接下来我们开始实例化并且创建拓扑提交器了。*/
  public static void main(String[] args) throws Exception 
{
      //创建拓扑构建器
      TopologyBuilder builder = new TopologyBuilder();

    //接下来创建Spout对象,取名为word,并行度设置为10,意思是storm处理该拓扑时给该Spout分10个线程来运行它
builder.setSpout("word", new TestWordSpout(), 10);

//创建Bolt,该Bolt的名字是exclaim1,分配三个线程来处理它,它的上游是名为“word”的Spout(即,接收名为word的Spout的数据),spout和这个bolt之间流的分组方式是随机分组。
builder.setBolt("exclaim1", new ExclamationBolt(), 3).shuffleGrouping("word");

//创建第二个Bolt,该Bolt的名字是exclaim2,分配两个个线程来处理它,它的上游是名为“Exclamation”的Bolt,这两个bolt之间流的分组方式也是随机分组。
      builder.setBolt("exclaim2", new ExclamationBolt(), 2).shuffleGrouping("exclaim1");

    //创建输入的配置信息,它使用的是storm的配置文件,并设置为debug模式。这写的是一个简单的例子,如果要运行一些复杂的例子,需要在storm的配置文件中加入自己开发的拓扑需要用到的的配置信息。
      Config conf = new Config();
      conf.setDebug(true);

/*接下来就是提交拓扑了,storm的运行有两种模式: 本地模式和分布式模式. 在本地模式中, storm用一个进程里面的线程来模拟所有的spout和bolt. 本地模式对开发和测试来说比较有用。在分布式模式下, storm由一堆机器组成。当你提交topology给主节点的时候, 你同时也把topology的代码提交了。主节点负责分发你的代码并且负责给你的topolgoy分配工作进程。如果一个工作进程挂掉了,它会把任务重新分配到其它节点。*/
if (args != null && args.length > 0) 
{
//如果。。。(这个是storm内部处理参数,是用clojure语言写的,如果是集群模式提交拓扑的clojure代码里会有参数args),说明在集群模式上提交,然后创建三个进程来执行此拓扑
      conf.setNumWorkers(3);
StormSubmitter.submitTopologyWithProgressBar(args[0],conf,builder.createTopology()); //args是集群提交的一个参数
    }
else 
{
      //本地模式通过定义一个LocalCluster对象来定义一个进程内的集群。提交topology给这个虚拟的集群和提交topology给分布式集 群是一样的。通过调用submitTopology方法来提交topology,它接受三个参数:要运行的topology的名字,一个配置对象以及要运行的topology本身。topology的名字是用来唯一区别一个topology的,这样你然后可以用这个名字来杀死这个topology的。前面已经说过了,你必须显式的杀掉一个topology, 否则它会一直运行。Conf对象可以配置很多东西。
        LocalCluster cluster = new LocalCluster();
        cluster.submitTopology("test", conf, builder.createTopology());
        Utils.sleep(10000);  //用来睡眠一段时间
      cluster.killTopology("test");  //这个句子是用来杀死拓扑
        cluster.shutdown();  //关闭集群
    }
  }
}

你可能感兴趣的:(Storm ExclamationTopology源码解析)