Storm学习笔记
//open()方法中
int spoutsSize = context.getComponentTasks(context.getThisComponentId()).size();
int myIdx = context.getThisTaskIndex();
String[] tracks = ((String) conf.get("track")).split(",");
一个完整的Spout code:输入参数track代表了多个流,在open()方法中用取模%初始化track,在execute()方法读取track的数据,发送。由于spout的多个实例的myIdx不同,它们可以获得各自的一个track,可以实现一个spout读取多个流。
//ApiStreamingSpout.java
package twitter.streaming; import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue; import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.log4j.Logger;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException; 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; public class ApiStreamingSpout extends BaseRichSpout { static String STREAMING_API_URL = "https://stream.twitter.com/1/statuses/filter.json?track=";
private String track;
private String user;
private String password;
private DefaultHttpClient client;
private SpoutOutputCollector collector;
private UsernamePasswordCredentials credentials;
private BasicCredentialsProvider credentialProvider; LinkedBlockingQueue<String> tweets = new LinkedBlockingQueue<String>(); static Logger LOG = Logger.getLogger(ApiStreamingSpout.class);
static JSONParser jsonParser = new JSONParser(); @Override
public void nextTuple() {
/*
* Create the client call
*/
client = new DefaultHttpClient();
client.setCredentialsProvider(credentialProvider);
HttpGet get = new HttpGet(STREAMING_API_URL + track); // 每个spout实例track是唯一的。
HttpResponse response;
try {
// Execute
response = client.execute(get);
StatusLine status = response.getStatusLine();
if (status.getStatusCode() == 200) {
InputStream inputStream = response.getEntity().getContent();
BufferedReader reader = new BufferedReader(
new InputStreamReader(inputStream));
String in;
// Read line by line
while ((in = reader.readLine()) != null) {
try {
// Parse and emit
Object json = jsonParser.parse(in);
collector.emit(new Values(track, json));
} catch (ParseException e) {
LOG.error("Error parsing message from twitter", e);
}
}
}
} catch (IOException e) {
LOG.error("Error in communication with twitter api ["
+ get.getURI().toString() + "]");
try {
Thread.sleep(10000);
} catch (InterruptedException e1) {
}
}
} /**
* spoutsSize、myIdx实现了一个spout读取多个流tracks。
*/
@Override
public void open(Map conf, TopologyContext context,
SpoutOutputCollector collector) {
int spoutsSize = context
.getComponentTasks(context.getThisComponentId()).size();
int myIdx = context.getThisTaskIndex();
String[] tracks = ((String) conf.get("track")).split(",");
StringBuffer tracksBuffer = new StringBuffer();
for (int i = 0; i < tracks.length; i++) {
if (i % spoutsSize == myIdx) {
tracksBuffer.append(",");
tracksBuffer.append(tracks[i]);
}
} if (tracksBuffer.length() == 0)
throw new RuntimeException("No track found for spout"
+ " [spoutsSize:" + spoutsSize + ", tracks:"
+ tracks.length + "] the amount"
+ " of tracks must be more then the spout paralellism"); this.track = tracksBuffer.substring(1).toString(); user = (String) conf.get("user");
password = (String) conf.get("password"); credentials = new UsernamePasswordCredentials(user, password);
credentialProvider = new BasicCredentialsProvider();
credentialProvider.setCredentials(AuthScope.ANY, credentials);
this.collector = collector;
} @Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("criteria", "tweet"));
}
}
通过这种技术,可以在数据源间分布收集器。相同的技术可以被应用在其他的场景-例如,从web服务器收集日志文件。PS:没有试过。
2.Bolt可以使用emit(streamId, tuple)发射元组到多条流,每条流由字符串streamId来识别。然后,在TopologyBuilder 中,你可以决定订阅哪条流。
没有试过。2个疑问:如何declare呢?spout有这个功能么?
解答:1.declareOutputFields()方法中声明多条流,不就可以了。
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("line"));
declarer.declareStream("second", new Fields("line2"));
}
2.Bolt和spout的实现来看,应该都是可以的。
3.BaseRichSpout是否是自动调用ack方法的,实现IBasicBolt接口可以自动ack?
BaseBasicBolt, is used to do the acking automatically.意思就是说,这个是自动调用ack的 (测试结果:使用BaseBasicBolt,不主动使用input.ack(),那么storm ui界面上看不到ack的个数。)so,最好使用input.ack().。PS:目前的项目编程是如下方法。
collector.emit();
input.ack();
通过IBasicBolt可以自动ack,用法如下。Storm UI可以看到该bolt的ack数目。
public class TotalBolt implements IBasicBolt{
private static final long serialVersionUID = 1L;
static Integer Total = new Integer(0);
//必须要实现的方法,使用BasicOutputCollector
public void execute(Tuple input,BasicOutputCollector collector) {
try {
String clear = input.getStringByField("PROVINCE_ID");
Total++;
collector.emit(new Values(Total));
} catch (IllegalArgumentException e) {
if (input.getSourceStreamId().equals("signals24Hour")) {
Total = 0;
}
}
}
}
4.关于bolt的锚定
记录原始的spout实例的最好方式是在消息元组中包含一个原始spout的引用。这个技术叫做锚定。
collector.emit(tuple,new Values(word));
每个消息都通过这种方式被锚定:把输入消息作为emit方法的第一个参数。因为word消息被锚定在了输入消息上,这个输入消息是spout发送过来的tuple tree的根节点,如果任意一个word消息处理失败,派生这个tuple tree那个spout 消息将会被重新发送。(锚定的好处是什么)
但是,这样会不会导致 元组被重发,计数重复? 会。
系统使用一种哈希算法来根据spout消息的messageId确定由哪个acker跟踪此消息派生出来的tuple tree。
下面这张图是OutputCollector(Bolt)中的emit方法:

测试结果:做了anchors锚定后,没有看到实际的效果。
A lot of bolts follow a common pattern of reading an input tuple, emitting tuples based on it, and then acking the tuple at the end of the execute method. These bolts fall into the categories of filters and simple functions. Storm has an interface called IBasicBolt that encapsulates this pattern for you. The SplitSentence example can be written as a IBasicBolt like follows:
public class SplitSentence implements IBasicBolt {
public void execute(Tuple tuple, BasicOutputCollector collector) {
String sentence = tuple.getString(0);
for(String word: sentence.split(" ")) {
collector.emit(new Values(word));
}
}
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("word"));
}
}
This implementation is simpler than the implementation from before and is semantically identical. Tuples emitted to BasicOutputCollectorare automatically anchored to the input tuple, and the input tuple is acked for you automatically when the execute method completes.
In contrast, bolts that do aggregations or joins may delay acking a tuple until after it has computed a result based on a bunch of tuples. Aggregations and joins will commonly multi-anchor their output tuples as well. These things fall outside the simpler pattern of IBasicBolt.
5 集群的各级容错
5. 疑问:主动调用input.ack(),日志中没有看到调用了spout的ack方法?这是为什么呢?
原因:Spout中SpoutOutputCollector.emit()方法中,没有加入messageID,也就是说采用了以下第一种emit方法,用第二种方法便可以看到。加入后在storm ui界面看到。
SpoutOutputCollector的emit方法:(messageID用long或者Integer型都是可以的。If the messageId was null, Storm will not track the tuple and no callback will be received. The emitted values must be immutable.)
collector.emit(new Values(str), messageID++);//messageID is type long.

一个消息默认被成功处理的timeOut是30s,超过30s就会触发spout的fail方法。这个值可以根据实际的集群情况进行调整。在Topology中 Conf conf.setMessageTimeoutSecs(int secs) 设置。
storm ui界面:

Storm学习笔记的更多相关文章
- Storm学习笔记 - 消息容错机制
Storm学习笔记 - 消息容错机制 文章来自「随笔」 http://jsynk.cn/blog/articles/153.html 1. Storm消息容错机制概念 一个提供了可靠的处理机制的spo ...
- Storm学习笔记 - Storm初识
Storm学习笔记 - Storm初识 1. Strom是什么? Storm是一个开源免费的分布式计算框架,可以实时处理大量的数据流. 2. Storm的特点 高性能,低延迟. 分布式:可解决数据量大 ...
- Twitter Storm学习笔记
官方英文文档:http://storm.apache.org/documentation/Documentation.html 本文是学习笔记,转载整合加翻译,主要是为了便于学习. 一.基本概念 参考 ...
- Storm学习笔记——高级篇
1. Storm程序的并发机制 1.1 概念 Workers (JVMs): 在一个物理节点上可以运行一个或多个独立的JVM 进程.一个Topology可以包含一个或多个worker(并行的跑在不同的 ...
- Storm学习笔记六
1 Storm的通信机制 说明:1.worker与worker之间跨进程通信: 2.worker内部中各个executor间的通信,Task对象--->输入队列queue--->执行--- ...
- storm学习笔记(一)
1.storm介绍 storm是一种用于事件流处理的分布式计算框架,它是有BackType公司开发的一个项目,于2014年9月加入了Apahche孵化器计划并成为其旗下的顶级项目之一. ...
- apache Storm 学习笔记
Storm流之FieldGrouping字段分组: https://blog.csdn.net/Simon_09010817/article/details/80092080
- Storm学习笔记1:Storm基本组件
Storm概念及组件 Nimbus:负责资源分配和任务调度. Supervisor:负责接受nimbus分配的任务,启动和停止属于自己管理的worker进程. Worker:运行具体处理组件逻辑的进程 ...
- Storm学习笔记——安装配置
1.安装一个zookeeper集群 2.上传storm的安装包,解压 3.修改配置文件conf/storm.yaml #所使用的zookeeper集群主机storm.zookeeper.servers ...
随机推荐
- oracle口令管理之允许某个用户最多尝试三次登录
如果一个用户连续三次登录失败,则锁定该用户两天,两天之后该用户才能重新登录. 创建profile文件: 更新账户: 三次登录失败后用户就会被锁定: 用户锁住之后要怎么给他解锁: 解锁之后就可以正常登录 ...
- Java Stax操作XML简介
使用stax操作xml 非常的简单,它的读取过程像是一个光标在移动.针对不同的节点做不同的处理. 先看一个基于光标的模型处理xml: public class StaxTest { @Test pub ...
- Java基础知识强化之IO流笔记30:字节流4种方式复制mp4并测试效率
1. 需求:把e:\\哥有老婆.mp4 复制到当前项目目录下的copy.mp4中 字节流四种方式复制文件: • 基本字节流一次读写一个字节 • 基本字节流一次读写一个字节数组 • 高效字节流一次读写一 ...
- ASP.NET中常用重置数据的方法
aspx: <asp:Repeater ID="rptProlist" runat="server" onitemdatabound="rptP ...
- C#基础入门--关于C#背景介绍以及变量相关
在正式探索C#的奥秘之前,我们先谈一谈关于学习方法的问题吧.你会不会有这样的感悟,自己努力奋斗得到的东西倍加珍惜,飘到眼前的,却不屑一顾.我认为,学习的整个历程亦是如此.在学习过程中,只有我们遇到了问 ...
- WisDom.Net 框架设计(七) 验证框架
WisDom.Net-验证框架 1.分类 这里我们将数据验证分为以下几种 数据类型校验 主要用于确保数据类型输入的正确 比如年龄一项输入 A岁 ,显然不合法 域检查 ...
- c# HttpWebRequest与HttpWebResponse 绝技(转载)
c# HttpWebRequest与HttpWebResponse 绝技 如果你想做一些,抓取,或者是自动获取的功能,那么就跟我一起来学习一下Http请求吧.本文章会对Http请求时的Get和P ...
- C#中堆和栈的区别分析(有待更新总结2)
转载:http://blog.csdn.net/Zevin/article/details/5731965 线程堆栈:简称栈 Stack 托管堆: 简称堆 Heap 使用.Net框架开发程序的时候,我 ...
- AsyncTask理解- Day36or37
AsyncTask理解- Day36or37 mobile 5.0 1.手机归属地查询 AtoolsActivity Assets目录特点 该文件是原生文件,不会对里面的文件进行编码 该文件只支持读取 ...
- MSSQL生成整个数据库的SQL脚本的工具 scptxfr.exe
scptxfr.exe的路径要正确declare @cMd varchar(1000)set @cmd = 'master.dbo.xp_cmdshell ' + '''c:\"Micros ...