Strom数据流分组解析
本文可作为 <<Storm-分布式实时计算模式>>一书1.5节的读书笔记
数据流分组定义了一个数据流中的tuple如何分发给topology中不同bolt的task。
Shuffle grouping(随机分组):这种方式会随机分发 tuple 给 bolt 的各个 task,每个bolt 实例接收到的相同数量的 tuple。
Fields grouping(按字段分组):根据指定字段的值进行分组。比如说,一个数据流根据“word”字段进行分组,所有具有相同“word”字段值的 tuple 会路由到同一个 bolt 的 task 中。
All grouping(全复制分组):将所有的 tuple 复制后分发给所有 bolt task。每个订阅数据流的 task 都会接收到 tuple 的拷贝。
Globle grouping(全局分组):这种分组方式将所有的 tuples 路由到唯一一个 task 上。Storm 按照最小的 task ID 来选取接收数据的 task。注意,当使用全局分组方式时,设置 bolt 的 task 并发度是没有意义的,因为所有 tuple 都转发到同一个 task 上了。使用全局分组的时候需要注意,因为所有的 tuple 都转发到一个 JVM 实例上,可能会引起 Storm 集群中某个 JVM 或者服务器出现性能瓶颈或崩溃。
None grouping(不分组):在功能上和随机分组相同,是为将来预留的。
Direct grouping(指向型分组):数据源会调用 emitDirect() 方法来判断一个 tuple 应该由哪个 Storm 组件来接收。只能在声明了是指向型的数据流上使用。
Local or shuffle grouping(本地或随机分组):和随机分组类似,但是,会将 tuple 分发给同一个 worker 内的 bolt task(如果 worker 内有接收数据的 bolt task)。其他情况下,采用随机分组的方式。取决于 topology 的并发度,本地或随机分组可以减少网络传输,从而提高 topology 性能。
随机分组
最经常用的也就是Shuffle grouping,Fields grouping,Direct grouping等等
现在我们看一个例子:
就是最经常见的数单词的例子
public class WordCountBolt extends BaseRichBolt{
private OutputCollector collector;
private HashMap<String, Long> counts = null;
public void prepare(Map config, TopologyContext context,
OutputCollector collector) {
this.collector = collector;
this.counts = new HashMap<String, Long>();
}
public void execute(Tuple tuple) {
String word = tuple.getStringByField("word");
Long count = this.counts.get(word);
if(count == null){
count = 0L;
}
count++;
this.counts.put(word, count);
this.collector.emit(new Values(word, count));
}
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("word", "count"));
}
}
在添加这个bolt的时候,使用的是按字段分组,如下
builder.setBolt(COUNT_BOLT_ID, countBolt,4)
.fieldsGrouping(SPLIT_BOLT_ID, new Fields("word"));
如果我们分组模式改成
builder.setBolt(COUNT_BOLT_ID, countBolt,4)
.shuffleGrouping(SPLIT_BOLT_ID);
那么对单词的统计就会偏少。
为什么?
大家想想恩,有4个countbolt实例(咱们暂时称之为countbolta,b,c,d),如果我是随机分组,the这个单词出现了3回,前两回被分配到了countbolta,第三回被分配到了countboltb,那么后面的reportbolt先收到了<the,2>这个tuple(来自countbolta),然后又收到了<the,1>这个tuple(来自countboltb),最后的输出肯定是the:1喽
那么如果使用
builder.setBolt(COUNT_BOLT_ID, countBolt,4)
.fieldsGrouping(SPLIT_BOLT_ID, new Fields("word"));
自然就不会出现刚才的问题了,为什么,大家自己想。
直接分组
这里我引用一个用storm给句子加感叹号的例子,代码在最后
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
以下为16-7-4修改
其实我下面这例子不好
直接分组,主要是保证把消息给bolt中某一个特定的task
而下面的例子的实际效果是想吧 messagea给bolta,messageb给boltb
那么其实还有更方便的做法,就是
在发送是:
public void execute(Tuple tuple, BasicOutputCollector collector) {
tpsCounter.count();
Long tupleId = tuple.getLong(0);
Object obj = tuple.getValue(1);
if (obj instanceof TradeCustomer) {
TradeCustomer tradeCustomer = (TradeCustomer)obj;
Pair trade = tradeCustomer.getTrade();
Pair customer = tradeCustomer.getCustomer();
collector.emit(SequenceTopologyDef.TRADE_STREAM_ID,
new Values(tupleId, trade));
collector.emit(SequenceTopologyDef.CUSTOMER_STREAM_ID,
new Values(tupleId, customer));
}else if (obj != null){
LOG.info("Unknow type " + obj.getClass().getName());
}else {
LOG.info("Nullpointer " );
}
}
在提交时:
builder.setBolt(SequenceTopologyDef.SPLIT_BOLT_NAME, new SplitRecord(), 2).shuffleGrouping(
SequenceTopologyDef.SEQUENCE_SPOUT_NAME);
builder.setBolt(SequenceTopologyDef.TRADE_BOLT_NAME, new PairCount(), 1).shuffleGrouping(
SequenceTopologyDef.SPLIT_BOLT_NAME, // --- 发送方名字
SequenceTopologyDef.TRADE_STREAM_ID); // --- 接收发送方该stream 的tuple
builder.setBolt(SequenceTopologyDef.CUSTOMER_BOLT_NAME, new PairCount(), 1)
.shuffleGrouping(SequenceTopologyDef.SPLIT_BOLT_NAME, // --- 发送方名字
SequenceTopologyDef.CUSTOMER_STREAM_ID); // --- 接收发送方该stream 的tuple
定义输出格式
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declareStream(SequenceTopologyDef.TRADE_STREAM_ID, new Fields("ID", "TRADE"));
declarer.declareStream(SequenceTopologyDef.CUSTOMER_STREAM_ID, new Fields("ID", "CUSTOMER"));
}
最后接收的时候还得判断一下
if (input.getSourceStreamId().equals(SequenceTopologyDef.TRADE_STREAM_ID) ) {
customer = pair;
customerTuple = input;
tradeTuple = tradeMap.get(tupleId);
if (tradeTuple == null) {
customerMap.put(tupleId, input);
return;
}
trade = (Pair) tradeTuple.getValue(1);
}
参考资料
以上为16-7-4修改
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
最开始的时候
运行的结果如下:
mystorm.PrintBolt@67178f5d String recieved: edi:I'm happy! mystorm.PrintBolt@67178f5d String recieved: marry:I'm angry! mystorm.PrintBolt@393ddf54 String recieved: ted:I'm excited! mystorm.PrintBolt@393ddf54 String recieved: john:I'm sad! mystorm.PrintBolt@5f97cfcb String recieved: marry:I'm angry!
不同的task都平均收到了tuple
然后我想让指定某些句子只让某个task接受,怎么办?
首先看ExclaimBasicBolt
public class ExclaimBasicBolt extends BaseBasicBolt {
/**
*
*/
private static final long serialVersionUID = -6239845315934660303L;
private List<Integer> list;
private List<Integer> list2;
@Override
public void execute(Tuple tuple, BasicOutputCollector collector) {
//String sentence = tuple.getString(0);
String sentence = (String) tuple.getValue(0);
String out = sentence + "!";
if (out.startsWith("e")) {
collector.emitDirect(list.get(0),new Values(out));
}else {
collector.emitDirect(list2.get(0),new Values(out));
}
}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(true,new Fields("excl_sentence"));
}
@Override
public void prepare(Map stormConf, TopologyContext context) {
list =context.getComponentTasks("print");
list2=context.getComponentTasks("print2");
}
}
在构建topology的时候
使用directGrouping
builder.setSpout("spout", new RandomSpout());
builder.setBolt("exclaim", new ExclaimBasicBolt(),3).shuffleGrouping("spout");
builder.setBolt("print", new PrintBolt(),3).directGrouping("exclaim");
builder.setBolt("print2", new PrintBolt2(),3).directGrouping("exclaim");
PrintBolt2与PrintBolt类似
只是打印的时候打印出 System.err.println(this+" i am two String recieved: " + rec);
OK这下运行的时候我们就能看到
mystorm.PrintBolt2@238ac8bf String recieved: ted:I'm excited! mystorm.PrintBolt2@238ac8bf String recieved: john:I'm sad! mystorm.PrintBolt2@238ac8bf String recieved: marry:I'm angry! mystorm.PrintBolt2@238ac8bf String recieved: ted:I'm excited! mystorm.PrintBolt@611b7a20 i am two String recieved: edi:I'm happy! mystorm.PrintBolt@611b7a20 i am two String recieved: edi:I'm happy! mystorm.PrintBolt@611b7a20 i am two String recieved: edi:I'm happy! mystorm.PrintBolt@611b7a20 i am two String recieved: edi:I'm happy! mystorm.PrintBolt@611b7a20 i am two String recieved: edi:I'm happy! mystorm.PrintBolt@611b7a20 i am two String recieved: edi:I'm happy! mystorm.PrintBolt@611b7a20 i am two String recieved: edi:I'm happy! mystorm.PrintBolt@611b7a20 i am two String recieved: edi:I'm happy! mystorm.PrintBolt@611b7a20 i am two String recieved: edi:I'm happy! mystorm.PrintBolt2@238ac8bf String recieved: marry:I'm angry! mystorm.PrintBolt2@238ac8bf String recieved: ted:I'm excited! mystorm.PrintBolt2@238ac8bf String recieved: marry:I'm angry!
所有e开头的句子 都跑到Print2这个Bolt的某个task里面了。
本节的整体代码见
package mystorm;
public class ExclaimBasicTopo {
public static void main(String[] args) throws Exception {
TopologyBuilder builder = new TopologyBuilder();
builder.setSpout("spout", new RandomSpout());
builder.setBolt("exclaim", new ExclaimBasicBolt(),3).shuffleGrouping("spout");
builder.setBolt("print", new PrintBolt(),3).shuffleGrouping("exclaim");
Config conf = new Config();
conf.setDebug(false);
if (args != null && args.length > 0) {
conf.setNumWorkers(3);
StormSubmitter.submitTopology(args[0], conf, builder.createTopology());
} else {
LocalCluster cluster = new LocalCluster();
cluster.submitTopology("test", conf, builder.createTopology());
}
}
}
package mystorm;
public class RandomSpout extends BaseRichSpout {
private SpoutOutputCollector collector;
private Random rand;
private int index;
private static String[] sentences = new String[] {
"edi:I'm happy", "marry:I'm angry", "john:I'm sad", "ted:I'm excited", "laden:I'm dangerous"};
@Override
public void open(Map conf, TopologyContext context,SpoutOutputCollector collector) {
this.collector = collector;
this.rand = new Random();
}
@Override
public void nextTuple() {
if (index<10*sentences.length) {
String toSay = sentences[rand.nextInt(sentences.length)];
this.collector.emit(new Values(toSay));
index++;
}else {
try {
Thread.sleep(1000);
System.out.println("我停了一秒");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("sentence"));
}
}
package mystorm;
public class ExclaimBasicBolt extends BaseBasicBolt {
@Override
public void execute(Tuple tuple, BasicOutputCollector collector) {
//String sentence = tuple.getString(0);
String sentence = (String) tuple.getValue(0);
String out = sentence + "!";
collector.emit(new Values(out));
}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("excl_sentence"));
}
}
package mystorm;
public class PrintBolt extends BaseBasicBolt {
@Override
public void execute(Tuple tuple, BasicOutputCollector collector) {
String rec = tuple.getString(0);
System.err.println(this+" String recieved: " + rec);
}
@Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
// do nothing
}
}
Strom数据流分组解析的更多相关文章
- 使用Java正则表达式的分组解析身份证的年月日
根据Java的Pattern和Matcher类通过分组解析出身份证的年月日: public class GetDateInIdCard { public static void main(String ...
- 022_STM32中断优先级分组解析
(0)STM32有十六个优先级 (一)STM32分组为:组0-4 (二)分组配置在寄存器SCB->AIRCR中: (三)解析第二点 1. 组0就是4位都用来设置成响应优先级,2^4=16位都是响 ...
- wordcount数据流过程解析
(1)执行hadoopFile()操作,其中有生成HadoopRDD的new 方法.然后执行map方法.pair => pair._2.toString,只对Value值进行操作.在textFi ...
- 大数据处理框架之Strom:认识storm
Storm是分布式实时计算系统,用于数据的实时分析.持续计算,分布式RPC等. (备注:5种常见的大数据处理框架:· 仅批处理框架:Apache Hadoop:· 仅流处理框架:Apache Stor ...
- 简单聊聊Storm的流分组策略
简单聊聊Storm的流分组策略 首先我要强调的是,Storm的分组策略对结果有着直接的影响,不同的分组的结果一定是不一样的.其次,不同的分组策略对资源的利用也是有着非常大的不同,本文主要讲一讲loca ...
- kcp-go源码解析
概念 ARQ:自动重传请求(Automatic Repeat-reQuest,ARQ)是OSI模型中数据链路层的错误纠正协议之一.RTO:Retransmission TimeOutFEC:Forwa ...
- cdnbest如何让用户访问走最近最快的线路(分组线路)
用户访问网站有时网络有互通的问题,cdnbest的分组解析可以细分线路,让用户访问自动走最优线路,线路不细分都加默认里,访问的节点是随机分配的 下面我们讲下如何设置: 比如你有电信,移动,和国外的节点 ...
- 【原】Storm基本概念
Storm入门教程 1. Storm基础 Storm Storm主要特点 Storm基本概念 Topologies Streams Spouts Bolts Stream groupings Reli ...
- Android WebRTC 音视频开发总结
www.cnblogs.com/lingyunhu/p/3621057.html 前面介绍了WebRTCDemo的基本结构,本节主要介绍WebRTC音视频服务端的处理,,转载请说明出处(博客园RTC. ...
随机推荐
- [SDOI2010]代码拍卖会
题目描述 随着iPig在P++语言上的造诣日益提升,他形成了自己一套完整的代码库.猪王国想参加POI的童鞋们都争先恐后问iPig索要代码库.iPig不想把代码库给所有想要的小猪,只想给其中的一部分既关 ...
- noip模拟题-赛斯石
题目背景 白露横江,水光接天,纵一苇之所如,凌万顷之茫然.--苏轼 真程海洋近来需要进购大批赛斯石,你或许会问,什么是赛斯石? 首先我们来了解一下赛斯,赛斯是一个重量单位,我们用sisi作为其单位.比 ...
- bzoj 1085: [SCOI2005]骑士精神
Description 在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士,且有一个空位.在任何时候一个骑士都能按照骑士的走法(它可以走到和它横坐标相差为1,纵坐标相差为2或者横坐标相差为2,纵 ...
- 10-8 uva1262密码
题意:有两个图,每一列都存在的字母选作密码,就第k大的密码 思路: 找出各个位置上的密码, 假设: 第1个字母只能是{A,C,D,W}, 第2个字母只能是{B,O,P}, 第3个字母只能是{G,M,O ...
- 如何在Windows系统中设置Python程序定时运行
文章出处:http://blog.csdn.net/wwy11/article/details/51100432 首先,我们肯定是要用到Windows下的[计划任务]功能 之后点击右侧的[创建基本任务 ...
- win10下python环境变量设置
我用的是python_2.7.3.msi,从官网下载之后,一路按照默认进行安装. 安装之后配置环境变量的步骤如下: 1,点“我的电脑”,右键选“属性” 2,选择“高级系统设置”--->选“环境变 ...
- RTX 无法刷新组织架构的处理方法总结
文章一: 刷新组织架构问题1."客户端不能获取正确的组织架构"或"新增加的人员刷新不了组织架构"首先要判断是RTX服务器引起的异常还是一些客户端出现的异常,判断 ...
- ThreadLocal基本原理及运用
ThreadLocal提供本地线程变量.这个变量里面的值(通过get方法获取)是和其他线程分割开来的,变量的值只有当前线程能访问到,不像一般的类型比如Person,Student类型的变量,只要访问到 ...
- 详解linux进程间通信-管道 popen函数 dup2函数
前言:进程之间交换信息的唯一方法是经由f o r k或e x e c传送打开文件,或通过文件系统.本章将说明进程之间相互通信的其他技术-I P C(InterProcess Communication ...
- Python安装与环境变量
Python安装与环境变量的配置 python下载: Python安装包下载地址:http://www.python.org/ 根据实际的操作系统,安装合适的安装版本. Python安装: 本 ...