Storm实现word count例子与Storm启动流程分析

本文详细解析了使用Storm实现Word Count的例子,并深入分析了Storm的启动流程,包括客户端提交任务、Nimbus调度、Supervisor执行、Worker运行Spout和Bolt等关键步骤。

利用Storm实现word count例子与Storm启动流程分析

main函数

public static void main(String[] args) throws AlreadyAliveException, InvalidTopologyException, AuthorizationException, InterruptedException {
		
		//准备一个TopologyBuilder
		TopologyBuilder builder=new TopologyBuilder();
		builder.setSpout("spout",new RandomSentenceSpout(),Integer.valueOf(5));
		builder.setBolt("split",new SplitSentenceBolt(),Integer.valueOf(8)).shuffleGrouping("spout");
		builder.setBolt("count",new WordCountBolt(),Integer.valueOf(12)).fieldsGrouping("split",new Fields("word"));
		
		//创建一个configuration,用来制定当前topology需要的数量
		Config conf=new Config();
		conf.setNumWorkers(2);
		
		//提交任务
		//storm有两种运行模式:
		//集群模式——在集群上运行
		//本地模式——当前编辑器中运行
		StormSubmitter.submitTopology("word-count",conf,builder.createTopology());
	}

WordCountBolt(),Integer.valueOf(12)).fieldsGrouping(“split”,new Fields(“word”)); 申明分组是按照“word”字段,而用fieldGrouping进行分组,是因为要让同一个字段同时到一个task中,才能够统计得到完成的结果。
Spout

public class RandomSentenceSpout extends BaseRichSpout{

	private static final long serialVersionUID=56343879980567L;
	SpoutOutputCollector _collector;//用来收集Spout输出的tuple
	Random _rand;
	
	//该方法调用一次,主要由storm框架传入SpoutOutputCollector
		@Override
		public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
			this._collector=collector;
			this._rand=new Random();
		}

	//storm框架在while(true)调用nextTuple方法
	@Override
	public void nextTuple() {
		Utils.sleep(100L);
		String[] sentences= {"keep moving","an apple a day keeps the docotr away","just do it"};
		String sentence=sentences[this._rand.nextInt(sentences.length)];
		this._collector.emit(new Values(sentence));
	}

    //消息源可以发射多条消息流stream,多条消息流可以理解为多种类型的数据
	@Override
	public void declareOutputFields(OutputFieldsDeclarer declarer) {
		declarer.declare(new Fields("word"));
	}

Split_Bolt

public class SplitSentenceBolt extends BaseRichBolt{
	
	private static final long serialVersionUID = 1L;
	OutputCollector collector;
	//该方法只会被调用一次,用来初始化
	public void prepare(Map stormConf,TopologyContext context,OutputCollector collector) {
		this.collector=collector;
	}
	
	/*
	 * 接受的参数是RandomSentenceSpout发出的句子,即input的内容是句子execute方法,将句子切割形成的单词发出
	 */
	 public void execute(Tuple input) {
	    	String sentence=input.getString(0);
	    	String[] words=sentence.split(" ");
	    	for(String word:words) {
	    			collector.emit(new Values(word,1));
	    	}
	    }
	    //消息源可以发射多条消息流stream,多条消息流可以理解为多种类型的数据
		public void declareOutputFields(OutputFieldsDeclarer declarer) {
			declarer.declare(new Fields("word","num"));//这里申明的两个字段的index分别对应着collector.emit(new Values(word,1));  中的word和1
		}

Count_Bolt

public class WordCountBolt extends BaseRichBolt{
	private static final long serialVersionUID=765657677676642L;
	private Map<String,Integer> counters=new HashMap<String,Integer>();//用来保存最后计算的结果key=单词,value=单词个数
	OutputCollector collector;
	
	//该方法只会被调用一次,用来初始化
	public void prepare(Map stormConf,TopologyContext context,OutputCollector collector) {
		this.collector=collector;
	}
	
	/*
	 * 将collector中的元素存放在成员变量counters(Map)中,
	 * 如果counters(Map)中已经存在该元素,getValue并对Value进行累加操作。
	 */
	public void execute(Tuple input) {
		String str=input.getString(0);
		Integer num=input.getInteger(1);
		input.getFields();
		if(!counters.containsKey(str)) {
			counters.put(str,num);
		}else {
			Integer c=counters.get(str)+num;
			counters.put(str,c);
		}
		System.out.println(str+" "+counters.get(str));
	}
	public void declareOutputFields(OutputFieldsDeclarer declarer) {
		//不输出
	}

Storm启动流程分析
1、客户端运行storm nimbus时,会调用storm的python脚本,该脚本中为每个命令编写一个方法,每个方法都可以生成一条相应的java命令。命令格式如下:

java -server xxx.ClassName -args
nimbus---->Running:/export/servers/jdk/bin/java -server backtype.storm.daemon.nimbus
supervisor--->Running:/export/servers/jdk/bin/java -server backtype.storm.daemon.supervisor

2、nimbus启动之后,接受客户端提交任务,命令格式如下:

java -server xxx.ClassName -args
storm jar xxx.jar  xx驱动类  参数
Running:/export/servers/jdk/bin/java -client -D storm.jar=/export/servers/storm/examples/storm-starters-topologies-0.9.6.jar
storm.starter.WordCountTopology wordcount-28

该命令会执行storm-starters-topologies-0.9.6.jar中的storm-starter-topologies-0.9.6.jar的main方法,main方法中会执行以下代码:

StormSubmitter.submitTopology("word-count",conf,builder.createTopology());

builder.createTopology()会将Spout对象和Bolt对象序列化。然后将用户的jar上传到nimbus物理节点的/export/data/workdir/nimbus/inbox目录下,并且按规则改名,即:添加一个UUID字符串。在nimbus物理节点的/export/data/storm/workdir/nimbus/stormdist目录下,有当前正在运行的topology的jar包和配置文件,序列化对象文件。
3、接受到任务之后,会将任务进行分配,分配会产生一个assignment对象,该对象会保存到ZooKeeper中,目录是/storm/assignments,该目录只保存正在运行的topology任务。
4、supervisor通过watch机制,感知到nimbus在ZooKeeper上的任务分配信息,从ZooKeeper上拉取任务信息,分辨出属于自己的任务。

ResourceWorkerSlot[hostname=192.168.1.106,nameSize=0,cpu=0,tasks=[1,23,45,67,8],jvn=<null>,nodeId=61ce10a7-4c47-9fb3-c21f43a331ba,port=6900]

5、supervisor根据自己的任务信息,启动自己的worker,并分配一个端口。

'/export/servers/jdk/bin/java''-server''-Xmx768m' export/data/storm/workdir/supervisor/stormdist/wordcount1-3-1461483066/stormjar.jar
'backtype.storm.daemon.worker''wordcount1-3-1461683066''a69bb8fc-e08e-b51f-e539b066f90b''6701'
'9fac2805-7d2b-4e40-aabc-1c85c9856d64'

6、worker启动之后,连接ZooKeeper,拉取任务

ResourceWorkerSlot[hostname=192.168.1.106,nameSize=0,cpu=0,tasks=[1,23,45,67,8],jvn=<null>,nodeId=61ce10a7-4c47-9fb3-c21f43a331ba,port=6900]

假设任务信息:
1---->Spout----type:Spout
2---->Bolt----type:Bolt
3---->Bolt----type:Bolt
worker通过反序列化,得到之前被序列化的Spout和Bolt对象。
7、worker根据任务类型,分别执行Spout任务或者Bolt任务。Spout的声明周期为:open->nextTuple->declareOutputFields。Bolt的生命周期为:prepare->execute->declareOutputFields。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值