Storm之——简单编程案例

转载请注明出处:http://blog.csdn.net/l1028386804/article/details/78336236

一、案例概述

今天,就带着大家一起来实现一个简单的Storm实例,这个实例很简单,实现以下功能:

我们定义一个数组,比如:String[] words = {"iphone","xiaomi","mate","sony","sumsung","moto","meizu"};  通过Strom不断输出类似输出以下的结果:

IPHONE_itisok
XIAOMI_itisok
MATE_itisok
SONY_itisok
SUMSUNG_itisok
MOTO_itisok
MEIZU_itisok
即,通过Storm先将数组中的单词变为大写,然后再后面加上后缀_itisok。

二、实现

1、创建项目

首先我们先创建一个Java工程,并将STORM_HOME/lib目录下的jar包添加到项目的classpath路径下。

2、创建RandomWordSpout类

创建RandomWordSpout类,此类继承backtype.storm.topology.base.BaseRichSpout,主要的功能是,从数组中随机获取元素,并产生消息。

具体代码如下:

package com.lyz.storm.demo;

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

import backtype.storm.spout.SpoutOutputCollector;
import backtype.storm.task.TopologyContext;
import backtype.storm.topology.OutputFieldsDeclarer;
import backtype.storm.topology.base.BaseRichSpout;
import backtype.storm.tuple.Fields;
import backtype.storm.tuple.Values;
import backtype.storm.utils.Utils;

/**
 * 模拟产生随机商品,产生消息
 * @author liuyazhuang
 *
 */
public class RandomWordSpout extends BaseRichSpout{

	private static final long serialVersionUID = -5694853370249658735L;

	private SpoutOutputCollector collector;
	
	//模拟一些数据
	String[] words = {"iphone","xiaomi","mate","sony","sumsung","moto","meizu"};
	
	//不断地往下一个组件发送tuple消息
	//这里面是该spout组件的核心逻辑
	@Override
	public void nextTuple() {

		//可以从kafka消息队列中拿到数据,简便起见,我们从words数组中随机挑选一个商品名发送出去
		Random random = new Random();
		int index = random.nextInt(words.length);
		
		//通过随机数拿到一个商品名
		String godName = words[index];
		
		//将商品名封装成tuple,发送消息给下一个组件
		collector.emit(new Values(godName));
		
		//每发送一个消息,休眠500ms
		Utils.sleep(500);
		
	}

	//初始化方法,在spout组件实例化时调用一次
	@Override
	public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
		this.collector = collector;
	}

	//声明本spout组件发送出去的tuple中的数据的字段名
	@Override
	public void declareOutputFields(OutputFieldsDeclarer declarer) {

		declarer.declare(new Fields("orignname"));
		
	}
}

3、创建UpperBolt类

创建UpperBolt类,此类继承backtype.storm.topology.base.BaseRichSpout,主要的功能是接收RandomWordSpout类产生的消息,并将消息中的单词转化为大写,同时,将单词发送给下一业务逻辑。

具体代码如下:

package com.lyz.storm.demo;

import backtype.storm.topology.BasicOutputCollector;
import backtype.storm.topology.OutputFieldsDeclarer;
import backtype.storm.topology.base.BaseBasicBolt;
import backtype.storm.tuple.Fields;
import backtype.storm.tuple.Tuple;
import backtype.storm.tuple.Values;

/**
 * 将得到的模拟商品名称转化为大写
 * @author liuyazhuang
 *
 */
public class UpperBolt extends BaseBasicBolt{
	
	private static final long serialVersionUID = 3968956714937045377L;

	//业务处理逻辑
	@Override
	public void execute(Tuple tuple, BasicOutputCollector collector) {
		
		//先获取到上一个组件传递过来的数据,数据在tuple里面
		String godName = tuple.getString(0);
		
		//将商品名转换成大写
		String godName_upper = godName.toUpperCase();
		
		//将转换完成的商品名发送出去
		collector.emit(new Values(godName_upper));
	}
	
	//声明该bolt组件要发出去的tuple的字段
	@Override
	public void declareOutputFields(OutputFieldsDeclarer declarer) {
		
		declarer.declare(new Fields("uppername"));
	}

}

4、创建SuffixBolt类

创建SuffixBolt类,此类继承backtype.storm.topology.base.BaseRichSpout,主要的功能是:接收UpperBolt发送的消息,获取单词,并在单词后面添加后缀_itisok,输出的文件。

具体代码如下:

package com.lyz.storm.demo;

import java.io.FileWriter;
import java.io.IOException;
import java.util.Map;
import java.util.UUID;

import backtype.storm.task.TopologyContext;
import backtype.storm.topology.BasicOutputCollector;
import backtype.storm.topology.OutputFieldsDeclarer;
import backtype.storm.topology.base.BaseBasicBolt;
import backtype.storm.tuple.Tuple;

/**
 * 将收到的商品加上后缀"_itisok"
 * @author liuyazhuang
 *
 */
public class SuffixBolt extends BaseBasicBolt{
	
	private static final long serialVersionUID = 5122871763103743706L;
	
	private FileWriter fileWriter = null;
	
	//在bolt组件运行过程中只会被调用一次
	@Override
	public void prepare(Map stormConf, TopologyContext context) {

		try {
			fileWriter = new FileWriter("/usr/local/storm_data/"+UUID.randomUUID());
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}
	
	//该bolt组件的核心处理逻辑
	//每收到一个tuple消息,就会被调用一次
	@Override
	public void execute(Tuple tuple, BasicOutputCollector collector) {

		//先拿到上一个组件发送过来的商品名称
		String upper_name = tuple.getString(0);
		//为上一个组件发送过来的商品名称添加后缀
		String suffix_name = upper_name + "_itisok";
		try {
			fileWriter.write(suffix_name);
			fileWriter.write("\n");
			fileWriter.flush();
		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}
	
	//本bolt已经不需要发送tuple消息到下一个组件,所以不需要再声明tuple的字段
	@Override
	public void declareOutputFields(OutputFieldsDeclarer arg0) {

		
	}

}

5、创建TopoMain类

创建TopoMain类,主要的功能是,作为程序启动的入口,同时组织各个处理组件形成一个完整的处理流程,并且将该topology提交给storm集群去运行,topology提交到集群后就将永无休止地运行,除非人为或者异常退出。

具体代码如下:

package com.lyz.storm.demo;

import backtype.storm.Config;
import backtype.storm.StormSubmitter;
import backtype.storm.generated.StormTopology;
import backtype.storm.topology.TopologyBuilder;

/**
 * 组织各个处理组件形成一个完整的处理流程,就是所谓的topology(类似于mapreduce程序中的job)
 * 并且将该topology提交给storm集群去运行,topology提交到集群后就将永无休止地运行,除非人为或者异常退出
 * @author liuyazhuang
 *
 */
public class TopoMain {

	public static void main(String[] args) throws Exception {
		
		TopologyBuilder builder = new TopologyBuilder();
		
		//将我们的spout组件设置到topology中去 
		//parallelism_hint :4  表示用4个excutor来执行这个组件
		//setNumTasks(8) 设置的是该组件执行时的并发task数量,也就意味着1个excutor会运行2个task
		builder.setSpout("randomspout", new RandomWordSpout(), 4).setNumTasks(8);
		
		//将大写转换bolt组件设置到topology,并且指定它接收randomspout组件的消息
		//.shuffleGrouping("randomspout")包含两层含义:
		//1、upperbolt组件接收的tuple消息一定来自于randomspout组件
		//2、randomspout组件和upperbolt组件的大量并发task实例之间收发消息时采用的分组策略是随机分组shuffleGrouping
		builder.setBolt("upperbolt", new UpperBolt(), 4).shuffleGrouping("randomspout");
		
		//将添加后缀的bolt组件设置到topology,并且指定它接收upperbolt组件的消息
		builder.setBolt("suffixbolt", new SuffixBolt(), 4).shuffleGrouping("upperbolt");
		
		//用builder来创建一个topology
		StormTopology demotop = builder.createTopology();
		
		//配置一些topology在集群中运行时的参数
		Config conf = new Config();
		//这里设置的是整个demotop所占用的槽位数,也就是worker的数量
		conf.setNumWorkers(4);
		conf.setDebug(true);
		conf.setNumAckers(0);
		
		//将这个topology提交给storm集群运行
		StormSubmitter.submitTopology("demotopo", conf, demotop);
		
	}
}

三、打包运行

1、创建文件目录

我们在类SuffixBolt中有一行代码如下:

fileWriter = new FileWriter("/usr/local/storm_data/"+UUID.randomUUID());
说明,我们要将结果文件输出到目录/usr/local/storm_data/中,所以,我们首先在服务器上执行如下命令:

mkdir -p /usr/local/storm_data/
类创建文件夹。

2、打包程序

我们将写好的Java工程打包成jar包,比如在Eclipse中导出为Jar包,这个我将这个Jar包的名字定义为storm_test.jar。

3、上传Jar包

这里我直接将Jar包上传到服务器的/usr/local/storm_data/目录下。

4、运行Jar包

我们输入命令:

storm jar storm_test.jar com.lyz.storm.demo.TopoMain
来运行我们的Jar包,此时Storm会提示Jar包已提交到Storm集群,并在服务器的/usr/local/storm_data/下创建了四个随机文件如下:


我们打开其中的一个文件内容如下:


达到了我们的预期效果,注意:这四个文件的内容是不断追加的,除非我们自己手动关闭任务。

至此,这个案例已开发完毕。



评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冰 河

可以吃鸡腿么?

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值