JStorm第一个程序WordCount详解
- nimbus是整个storm任务的管理者,并不实际进行工作。负责在集群中分发代码,对节点分配任务,并监视主机故障。
- supervisor是实际进行工作的节点,负责监听工作节点上已经分配的主机作业,启动和停止Nimbus已经分配的工作进程。
- Worker是具体处理Spout/Bolt逻辑的进程,worker数量由拓扑中的conf.setNumWorkers来定义,storm会在每个Worker上均匀分配任务,一个Worker只能执行一个topology,但是可以执行其中的多个任务线程。
- 一个worker是一个进程,被启动的时候表现为一个JVM进程(内存更改需要配置storm.yaml里面的worker.childopts: "-Xmx2048m"参数),里面可以同时运行多个线程,这些线程就是task。
- Tuple是spout与bolt、bolt与bolt之间传递消息(流)的基本单元,对于Storm来说是一个无边界的链表,每个值要事先声明它的域(field)
- task是spout和bolt执行的最小单元。
- 下面的结构图显示了各个component之间的关系
图片来自:http://www.cnblogs.com/foreach-break/p/storm_worker_executor_spout_bolt_simbus_supervisor_mk-assignments.html
参考:http://blog.csdn.net/cuihaolong/article/details/52652686(storm各个节点介绍和容错机制)

- 本地模式(Local Mode): 即Topology(相当于一个任务,后续会详细讲解) 运行在本地机器的单一JVM上,这个模式主要用来开发、调试。
- 远程模式(Remote Mode):在这个模式,我们把我们的Topology提交到集群,在这个模式中,Storm的所有组件都是线程安全的,因为它们都会运行在不同的Jvm或物理机器上,这个模式就是正式的生产模式。
- spout随机发送一个准备好的字符串数组里面的一个字符串(sentence)
- 第一层SplitBolt,负责对spout发过来的数据(sentence)进行split,分解成独立的单词,并按照一定的规则发往下一层bolt处理
- 第二层CountBolt,接收第一层bolt传过来的数据,并对各个单词进行数量计算
- spout数据源
- bolt1进行split操作
- bolt2进行count操作
- Topolgy运行程序
- setSpout,setBolt,shuffleGrouping——见代码注释和之后的Grouping方式介绍,
- setNumWorkers——设置worker数量,每个worker占用一个端口(storm.yaml里面的supervisor.slots.ports配置)
- setNumTasks——设置每个executor跑多少个task(本实例中没有配置这个参数,jstorm默认每个executor跑一个task[spout/bolt])
- setMaxTaskParallelism——设置此拓扑中组件允许的最大并行度。(此配置通常用于测试以限制所生成的线程数)
package act.chenkh.study.jstormPlay; import java.io.File; import backtype.storm.Config;
import backtype.storm.LocalCluster;
import backtype.storm.StormSubmitter;
import backtype.storm.topology.TopologyBuilder;
import backtype.storm.tuple.Fields; public class WordCountTopology {
public static void main(String[] args) throws Exception {
/**第一步,设计一个Topolgy*/
TopologyBuilder builder = new TopologyBuilder();
/*
* 设置spout和bolt,完整参数为
* 1,spout的id(即name)
* 2,spout对象
* 3,executor数量即并发数,也就是设置多少个executor来执行spout/bolt(此项没有默认null)
*/
//setSpout
builder.setSpout("sentence-spout",new RandomSentenceSpout(),1);
//setBolt:SplitBolt的grouping策略是上层随机分发,CountBolt的grouping策略是按照上层字段分发
//如果想要从多个Bolt获取数据,可以继续设置grouping
builder.setBolt("split-bolt", new SplitBolt(),1)
.shuffleGrouping("sentence-spout");
builder.setBolt("count-bolt", new CountBolt(),1)
.fieldsGrouping("split-bolt", new Fields("word"))
.fieldsGrouping("sentence-spout",new Fields("word"));
/**第二步,进行基本配置*/
Config conf = new Config();
//作用和影响???????????
conf.setDebug(true);
if (args != null && args.length > 0) {
conf.setNumWorkers(1);
StormSubmitter.submitTopology(args[0], conf, builder.createTopology());
}
else {
/*
* run in local cluster, for test in eclipse.
*/
conf.setMaxTaskParallelism(3);
LocalCluster cluster = new LocalCluster();
cluster.submitTopology("Getting-Started-Toplogie", conf, builder.createTopology());
Thread.sleep(Integer.MAX_VALUE);
cluster.shutdown();
}
}
}
- open——spout初始化调用
- nextTuple——系统不断调用
- declareOutputFields——声明输出tuple包含哪些字段
package act.chenkh.study.jstormPlay; import java.util.Map;
import java.util.Random; import org.apache.log4j.Logger;
import backtype.storm.spout.SpoutOutputCollector;
import backtype.storm.task.TopologyContext;
import backtype.storm.topology.IRichSpout;
import backtype.storm.topology.OutputFieldsDeclarer;
import backtype.storm.tuple.Fields;
import backtype.storm.tuple.Values;
import backtype.storm.utils.Time;
import backtype.storm.utils.Utils;
/*
* RandomSentenceSpout实现了IRichSpout接口
* Spout需要实现的接口可以是:
* 1,IRichSpout:最基本的Spout,继承自ISpout, IComponent,沒有任何特殊方法(一般用这个)
* 2,IControlSpout:继承自IComponent,包括open,close,activate,deactivate,nextTuple,ack(Object msgId),fail等方法
*/
public class RandomSentenceSpout implements IRichSpout { /**
*
*/
private static final long serialVersionUID = 4058847280819269954L;
private static final Logger logger = Logger.getLogger(RandomSentenceSpout.class);
SpoutOutputCollector _collector;
Random _rand;
String component;
/*
* Spout初始化的时候调用
*/
public void open(Map conf, TopologyContext context, SpoutOutputCollector collector){
_collector = collector;
_rand = new Random();
component = context.getThisComponentId();
}
/*
* 系统框架会不断调用
*/
public void nextTuple() {
String[] sentences = new String[] { "Hello world! This is my first programme of JStorm",
"Hello JStorm,Nice to meet you!", "Hi JStorm, do you have a really good proformance",
"Goodbye JStorm,see you tomorrow" };
String sentence = sentences[_rand.nextInt(sentences.length)];
_collector.emit(new Values(sentence), Time.currentTimeSecs());
Utils.sleep(1000);
}
@Override
public void ack(Object arg0) {
logger.debug("ACK!");
} public void activate() {
logger.debug("ACTIVE!");
} public void close() { } public void deactivate() { } public void fail(Object arg0) {
logger.debug("FAILED!");
}
/*
* 声明框架有哪些输出的字段
*/
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("word"));
} public Map<String, Object> getComponentConfiguration() {
return null;
} }
2,SplitBolt类:接收上层tuple,进行split,分发给下一层
重要方法和参数解释:
- cleanup,execute,prepare,declareOutputFields——见代码注释
package act.chenkh.study.jstormPlay; import java.util.Map; //import org.slf4j.Logger;
//import org.slf4j.LoggerFactory; import org.apache.log4j.Logger; 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.Fields;
import backtype.storm.tuple.Tuple;
import backtype.storm.tuple.Values;
/*
*
* IBasicBolt:继承自IComponent,包括prepare,execut,cleanup等方法
*/
public class SplitBolt extends BaseBasicBolt {
/**
*
*/
private static final long serialVersionUID = 7104767103420386784L;
private static final Logger logger = Logger.getLogger(SplitBolt.class);
String component;
/* cleanup方法在bolt被关闭的时候调用, 它应该清理所有被打开的资源。(基本只能在local mode使用)
* 但是集群不保证这个方法一定会被执行。比如执行task的机器down掉了,那么根本就没有办法来调用那个方法。
* cleanup设计的时候是被用来在local mode的时候才被调用(也就是说在一个进程里面模拟整个storm集群),
* 并且你想在关闭一些topology的时候避免资源泄漏。
* (非 Javadoc)
* @see backtype.storm.topology.base.BaseBasicBolt#cleanup()
*/
public void cleanup() { }
//接收消息之后被调用的方法
public void execute(Tuple input,BasicOutputCollector collector) {
String sentence = input.getString(0);
String[] words = sentence.split("[,|\\s+]");
for(String word : words){
word = word.trim();
if(!word.isEmpty()){
word = word.toLowerCase();
collector.emit(new Values(word));
}
}
}
/*
* prepare方法在worker初始化task的时候调用.
*
* prepare方法提供给bolt一个Outputcollector用来发射tuple。
* Bolt可以在任何时候发射tuple — 在prepare, execute或者cleanup方法里面, 或者甚至在另一个线程里面异步发射。
* 这里prepare方法只是简单地把OutputCollector作为一个类字段保存下来给后面execute方法 使用。
*/ public void prepare(Map stromConf, TopologyContext context) {
component = context.getThisComponentId();
} /*
* declearOutputFields方法仅在有新的topology提交到服务器,
* 用来决定输出内容流的格式(相当于定义spout/bolt之间传输stream的name:value格式),
* 在topology执行的过程中并不会被调用.
* (非 Javadoc)
* @see backtype.storm.topology.IComponent#declareOutputFields(backtype.storm.topology.OutputFieldsDeclarer)
*/
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("word"));
}
}
3,CountBolt类:接收上层tuple,进行count,展示输出
package act.chenkh.study.jstormPlay; import java.util.HashMap;
import java.util.Map; import org.apache.log4j.Logger; import com.alibaba.jstorm.callback.AsyncLoopThread;
import com.alibaba.jstorm.callback.RunnableCallback; 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.Fields;
import backtype.storm.tuple.Tuple;
import clojure.inspector__init; public class CountBolt extends BaseBasicBolt {
Integer id;
String name;
Map<String, Integer> counters;
String component;
private static final Logger LOG = Logger.getLogger(CountBolt.class);
private AsyncLoopThread statThread;
/**
* On create
*/
@Override
public void prepare(Map stormConf, TopologyContext context) {
this.counters = new HashMap<String, Integer>();
this.name = context.getThisComponentId();
this.id = context.getThisTaskId();
this.statThread = new AsyncLoopThread(new statRunnable()); LOG.info(stormConf.get("abc")+"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
component = context.getThisComponentId();
} public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("word","count"));
// declarer.declareStream("coord-"+"word-counter", new Fields("epoch","ebagNum"));
// LOG.info("set stream coord-"+component);
} //接收消息之后被调用的方法
public void execute(Tuple input, BasicOutputCollector collector) {
// String str = input.getString(0);
String str = input.getStringByField("word");
if(!counters.containsKey(str)){
counters.put(str, 1);
}else{
Integer c = counters.get(str) + 1;
counters.put(str, c);
}
}
class statRunnable extends RunnableCallback { @Override
public void run() {
while(true){
try {
Thread.sleep(10000);
} catch (InterruptedException e) { }
LOG.info("\n-- Word Counter ["+name+"-"+id+"] --");
for(Map.Entry<String, Integer> entry : counters.entrySet()){
LOG.info(entry.getKey()+": "+entry.getValue());
}
LOG.info("");
} }
} }
参考:http://fireinwind.iteye.com/blog/2153699(第一个Storm应用)
三、Grouping的几种方式
四、Bolt的声明周期
1、在定义Topology实例过程中,定义好Spout实例和Bolt实例
2、在提交Topology实例给Nimbus的过程中,会调用TopologyBuilder实例的createTopology()方法,以获取定义的Topology实例。在运行createTopology()方法的过程中,会去调用Spout和Bolt实例上的declareOutputFields()方法和getComponentConfiguration()方法,declareOutputFields()方法配置Spout和Bolt实例的输出,getComponentConfiguration()方法输出特定于Spout和Bolt实例的配置参数值对。Storm会将以上过程中得到的实例,输出配置和配置参数值对等数据序列化,然后传递给Nimbus。
3、在Worker Node上运行的thread,从Nimbus上复制序列化后得到的字节码文件,从中反序列化得到Spout和Bolt实例,实例的输出配置和实例的配置参数值对等数据,在thread中Spout和Bolt实例的declareOutputFields()和getComponentConfiguration()不会再运行。
4、在thread中,反序列化得到一个Bolt实例后,它会先运行Bolt实例的prepare()方法,在这个方法调用中,需要传入一个OutputCollector实例,后面使用该OutputCollector实例输出Tuple
5、接下来在该thread中按照配置数量建立task集合,然后在每个task中就会循环调用thread所持有Bolt实例的execute()方法
6、在关闭一个thread时,thread所持有的Bolt实例会调用cleanup()方法
不过如果是强制关闭,这个cleanup()方法有可能不会被调用到
五、Stream里面的Tuple
public List<Integer> emit(List<Object> tuple, Object messageId) {
return emit(Utils.DEFAULT_STREAM_ID, tuple, messageId);
}
这里的tuple, 实际上是List<Object> 对象,返回的是 List<Integer> 是要发送的tast的IdsList
在bolt接收的时候, 变成一个Tuple对象, 结构应该也是一个list, List<Field1, value1, Field2, value2..>这样的一个结构, FieldList ValueList, 我们根据对应的fieldname就可以取出对应的getIntegerByField方法
JStorm第一个程序WordCount详解的更多相关文章
- (转载)Hadoop示例程序WordCount详解
最近在学习云计算,研究Haddop框架,费了一整天时间将Hadoop在Linux下完全运行起来,看到官方的map-reduce的demo程序WordCount,仔细研究了一下,算做入门了. 其实Wor ...
- Hadoop示例程序WordCount详解及实例(转)
1.图解MapReduce 2.简历过程: Input: Hello World Bye World Hello Hadoop Bye Hadoop Bye Hadoop Hello Hadoop M ...
- struts2第一个程序的详解(配图)
首先我们在struts2中要写上一个action <packagename="fish"namespace="/test"extends="st ...
- VS2010开发程序打包详解
VS2010开发程序打包详解 转自:http://blog.sina.com.cn/s/blog_473b385101019ufr.html 首先打开已经完成的工程,如图: 下面开始制作安装程序包. ...
- 嵌入式Linux应用程序开发详解------(创建守护进程)
嵌入式Linux应用程序开发详解 华清远见 本文只是阅读文摘. 创建一个守护进程的步骤: 1.创建一个子进程,然后退出父进程: 2.在子进程中使用创建新会话---setsid(): 3.改变当前工作目 ...
- Linux Bash命令关于程序调试详解
转载:http://os.51cto.com/art/201006/207230.htm 参考:<Linux shell 脚本攻略>Page22-23 Linux bash程序在程序员的使 ...
- 一个简单的C语言程序(详解)
C Primer Plus之一个简单的C语言程序(详解) #include <stdio.h> int main(void) //一个简单的 C程序 { int num; //定义一个名为 ...
- 入木三分学网络第一篇--VRRP协议详解第一篇(转)
因为keepalived使用了VRRP协议,所有有必要熟悉一下. 虚拟路由冗余协议(Virtual Router Redundancy Protocol,简称VRRP)是解决局域网中配置静态网关时,静 ...
- hadoop集群配置方法---mapreduce应用:xml解析+wordcount详解---yarn配置项解析
注:以下链接均为近期hadoop集群搭建及mapreduce应用开发查找到的资料.使用hadoop2.6.0,其中hadoop集群配置过程下面的文章都有部分参考. hadoop集群配置方法: ---- ...
随机推荐
- 诺基亚XL中Intent.ACTION_VIEW无效的问题
今天测试播放视频的时候,发现在诺基亚XL机型里不能弹出视频应用列表. 我的代码是: Intent intent = new Intent(Intent.ACTION_VIEW); intent.set ...
- LintCode Search Insert Position
找出指定target的位置(没有此数时为按顺序应当位置). public class Solution { /** * param A : an integer sorted array * para ...
- ios获取CELLID,LAC等信息方法
搞了一个来月的这个东西了,还是没有完全解决问题,下面方法可以获取简单的Cell信息,方法一://CoreTelephony.h//主要就这两个结构体,其他需要的话,自己添加struct CTServe ...
- 如何做好APP测试?
测试一个App具体包括哪些方面,以及每个方面有什么关键点呢? 测试人员常被看作bug寻找者,但你曾想过他们实际是如何开展测试的吗? 你是否好奇他们究竟都做些什么,以及他们如何在一个典型的技术项目中体现 ...
- Spring AOP 简单理解
AOP技术即(面向切面编程)技术是在面向对象编程基础上的发展,AOP技术是对所有对象或一类对象编程.核心是在不增加代码的基础上,还增加了新的功能.AOP编程在开发框架本身用的比较多,而实际项目中,用的 ...
- 【uTenux实验】集合点端口
这个是头一次接触的概念.比较不好理解.内核规范中的说明就要20页! 看了王总写的uTenux内核规范之后,有那么一点明白了但理解不深. 集合点端口就像每次工作前的收集情况会.首长下达收集情况指令,各个 ...
- [转]App Store 审核、限时免费、排行、推荐机制技巧精华汇总
在 App Store 上,什么样的应用会得到推荐? 这个问题问的非常大,而且编辑推荐很多个人元素在里面,我试着用推荐Ovi Store应用的思路来回答一下: 关于应用: 1.首先这个应用最基本的功能 ...
- 51nod 1290 Counting Diff Pairs 莫队 + bit
一个长度为N的正整数数组A,给出一个数K以及Q个查询,每个查询包含2个数l和r,对于每个查询输出从A[i]到A[j]中,有多少对数,abs(A[i] - A[j]) <= K(abs表示绝对值) ...
- MEF load plugin from directory
var catalog = new AggregateCatalog(); catalog.Catalogs.Add(new DirectoryCatalog(".")); var ...
- Python基础篇【第2篇】: Python文件操作
Python文件操作 在Python中一个文件,就是一个操作对象,通过不同属性即可对文件进行各种操作.Python中提供了许多的内置函数和方法能够对文件进行基本操作. Python对文件的操作概括来说 ...