欢迎转载,转载请注明出处,徽沪一郎.

本文通过BasicDRPCTopology的实例来分析DRPCTopology在提交的时候, Topology中究竟含有哪些内容?

BasicDRPCTopology

main函数

DRPC 分布式远程调用(这个说法有意思,远程调用本来就是分布的,何须再加个D, <头文字D>看多了, :)

public static void main(String[] args) throws Exception {
LinearDRPCTopologyBuilder builder = new LinearDRPCTopologyBuilder("exclamation");
builder.addBolt(new ExclaimBolt(), 3); Config conf = new Config(); if (args == null || args.length == 0) {
LocalDRPC drpc = new LocalDRPC();
LocalCluster cluster = new LocalCluster(); cluster.submitTopology("drpc-demo", conf, builder.createLocalTopology(drpc)); for (String word : new String[]{ "hello", "goodbye" }) {
System.out.println("Result for \"" + word + "\": " + drpc.execute("exclamation", word));
} cluster.shutdown();
drpc.shutdown();
}
else {
conf.setNumWorkers(3);
StormSubmitter.submitTopology(args[0], conf, builder.createRemoteTopology());
}
}

问题: 上面的代码中只是添加了一个bolt,并没有设定Spout. 我们知道一个topology中最起码得有一个Spout,那么这里的Spout又隐身于何处呢?

关键的地方就在builder.createLocalTopology, 调用关系如下

  • LinearDRPCTopologyBuilder::createLocalTopology

    •   LinearDRPCTopologyBuilder::createTopology()

      •   LinearDRPCTopologyBuilder::createTopology(new DRPCSpout(_function))

原来DRPCTopology中使用的Spout是DRPCSpout.

LinearDRPCTopology::createTopology

既然代码已经读到此处,何不再进一步看看createTopology的实现.

简要说明一下该段代码的处理逻辑:

  1. 设置DRPCSpout
  2. 以bolt为入参,创建CoordinatedBolt
  3. 添加JoinResult Bolt
  4. 添加ReturnResult Bolt: ReturnResultBolt连接到DRPCServer,并返回结果
    private StormTopology createTopology(DRPCSpout spout) {
final String SPOUT_ID = "spout";
final String PREPARE_ID = "prepare-request"; TopologyBuilder builder = new TopologyBuilder();
builder.setSpout(SPOUT_ID, spout);
builder.setBolt(PREPARE_ID, new PrepareRequest())
.noneGrouping(SPOUT_ID);
int i=0;
for(; i<_components.size();i++) {
Component component = _components.get(i); Map<String, SourceArgs> source = new HashMap<String, SourceArgs>();
if (i==1) {
source.put(boltId(i-1), SourceArgs.single());
} else if (i>=2) {
source.put(boltId(i-1), SourceArgs.all());
}
IdStreamSpec idSpec = null;
if(i==_components.size()-1 && component.bolt instanceof FinishedCallback) {
idSpec = IdStreamSpec.makeDetectSpec(PREPARE_ID, PrepareRequest.ID_STREAM);
}
BoltDeclarer declarer = builder.setBolt(
boltId(i),
new CoordinatedBolt(component.bolt, source, idSpec),
component.parallelism); for(Map conf: component.componentConfs) {
declarer.addConfigurations(conf);
} if(idSpec!=null) {
declarer.fieldsGrouping(idSpec.getGlobalStreamId().get_componentId(), PrepareRequest.ID_STREAM, new Fields("request"));
}
if(i==0 && component.declarations.isEmpty()) {
declarer.noneGrouping(PREPARE_ID, PrepareRequest.ARGS_STREAM);
} else {
String prevId;
if(i==0) {
prevId = PREPARE_ID;
} else {
prevId = boltId(i-1);
}
for(InputDeclaration declaration: component.declarations) {
declaration.declare(prevId, declarer);
}
}
if(i>0) {
declarer.directGrouping(boltId(i-1), Constants.COORDINATED_STREAM_ID);
}
} IRichBolt lastBolt = _components.get(_components.size()-1).bolt;
OutputFieldsGetter getter = new OutputFieldsGetter();
lastBolt.declareOutputFields(getter);
Map<String, StreamInfo> streams = getter.getFieldsDeclaration();
if(streams.size()!=1) {
throw new RuntimeException("Must declare exactly one stream from last bolt in LinearDRPCTopology");
}
String outputStream = streams.keySet().iterator().next();
List<String> fields = streams.get(outputStream).get_output_fields();
if(fields.size()!=2) {
throw new RuntimeException("Output stream of last component in LinearDRPCTopology must contain exactly two fields. The first should be the request id, and the second should be the result.");
} builder.setBolt(boltId(i), new JoinResult(PREPARE_ID))
.fieldsGrouping(boltId(i-1), outputStream, new Fields(fields.get(0)))
.fieldsGrouping(PREPARE_ID, PrepareRequest.RETURN_STREAM, new Fields("request"));
i++;
builder.setBolt(boltId(i), new ReturnResults())
.noneGrouping(boltId(i-1));
return builder.createTopology();
}

Bolt

处理逻辑: 在接收到的每一个单词后面添加'!'.

 public static class ExclaimBolt extends BaseBasicBolt {
@Override
public void execute(Tuple tuple, BasicOutputCollector collector) {
String input = tuple.getString(1);
collector.emit(new Values(tuple.getValue(0), input + "!"));
} @Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("id", "result"));
}
}

运行

java -cp $(lein classpath) storm.starter.BasicDRPCTopology

Apache Storm技术实战之2 -- BasicDRPCTopology的更多相关文章

  1. Apache Storm技术实战之1 -- WordCountTopology

    欢迎转载,转载请注意出处,徽沪一郎. “源码走读系列”从代码层面分析了storm的具体实现,接下来通过具体的实例来说明storm的使用.因为目前storm已经正式迁移到Apache,文章系列也由twi ...

  2. Apache Storm技术实战之3 -- TridentWordCount

    欢迎转载,转载请注明出处. 介绍TridentTopology的使用,重点分析newDRPCStream和stateQuery的实现机理. 使用TridentTopology进行数据处理的时候,经常会 ...

  3. Apache Spark技术实战之6 --Standalone部署模式下的临时文件清理

    问题导读 1.在Standalone部署模式下,Spark运行过程中会创建哪些临时性目录及文件? 2.在Standalone部署模式下分为几种模式? 3.在client模式和cluster模式下有什么 ...

  4. Apache Spark技术实战之4 -- 利用Spark将json文件导入Cassandra

    欢迎转载,转载请注明出处. 概要 本文简要介绍如何使用spark-cassandra-connector将json文件导入到cassandra数据库,这是一个使用spark的综合性示例. 前提条件 假 ...

  5. Apache Spark技术实战之3 -- Spark Cassandra Connector的安装和使用

    欢迎转载,转载请注明出处,徽沪一郎. 概要 前提 假设当前已经安装好如下软件 jdk sbt git scala 安装cassandra 以archlinux为例,使用如下指令来安装cassandra ...

  6. Apache Spark技术实战之9 -- 日志级别修改

    摘要 在学习使用Spark的过程中,总是想对内部运行过程作深入的了解,其中DEBUG和TRACE级别的日志可以为我们提供详细和有用的信息,那么如何进行合理设置呢,不复杂但也绝不是将一个INFO换为TR ...

  7. Apache Spark技术实战之8:Standalone部署模式下的临时文件清理

    未经本人同意严禁转载,徽沪一郎. 概要 在Standalone部署模式下,Spark运行过程中会创建哪些临时性目录及文件,这些临时目录和文件又是在什么时候被清理,本文将就这些问题做深入细致的解答. 从 ...

  8. Apache Spark技术实战之7 -- CassandraRDD高并发数据读取实现剖析

    未经本人同意,严禁转载,徽沪一郎. 概要 本文就 spark-cassandra-connector 的一些实现细节进行探讨,主要集中于如何快速将大量的数据从cassandra 中读取到本地内存或磁盘 ...

  9. Apache Spark技术实战之6 -- spark-submit常见问题及其解决

    除本人同意外,严禁一切转载,徽沪一郎. 概要 编写了独立运行的Spark Application之后,需要将其提交到Spark Cluster中运行,一般会采用spark-submit来进行应用的提交 ...

随机推荐

  1. solr6.0学习

    solr6.0学习(一)环境搭建准备工作:目前最新版本6.0.下载solr 6.0:Solr6.0下载JDK8 下载jdk1.8:jdk1.8[solr6.0是基于jdk8开发的]tomcat8.0 ...

  2. p235习题1

  3. js伪数组及转换

    什么是伪数组 能通过Array.prototype.slice转换为真正的数组的带有length属性的对象. 这种对象有很多,比较特别的是arguments对象,还有像调用getElementsByT ...

  4. C#开发微信公众平台-就这么简单(附Demo)(转载)

    转载地址:http://www.cnblogs.com/xishuai/p/3625859.html 写在前面 服务号和订阅号 URL配置 创建菜单 查询.删除菜单 接受消息 发送消息(图文.菜单事件 ...

  5. C/C++知识点

    1 cout<<endl;什么意思? 就是回车的意思~ 相当于C语言里面的printf("\n"); 2 cin>> 键盘输入 例子:double  r=1 ...

  6. sql 截取字符串与 截取字符串最长的字符串

    ); set @str='aa,32,22,55,7'; ) as '第一个逗号的索引值' )),),),'') as '第一个值' ),len(@str)) as '从第一逗号开始截取出后面的字符串 ...

  7. Xamarin.iOS编译时无法连接苹果系统

    Xamarin.iOS编译时无法连接苹果系统   错误信息:Unable to connect to Address=’***.***.***.***’ with User=’***’   即使Vis ...

  8. 编程中、遇到问题、bug多思考

    偶然间看到一篇很好的文章,关于编程过程中的思考. http://www.cnblogs.com/dongqingswt/archive/2012/12/26/2834675.html#3457256 ...

  9. PHP中常见的页面跳转方法

    转载自冠威博客 [ http://www.guanwei.org/ ]本文链接地址:http://www.guanwei.org/post/PHPnotes/04/php-redirect-metho ...

  10. linux fork 进程后 主进程的全局变量

    fork一个进程后,复制出来的task_struct结构与系统的堆栈空间是父进程独立的,但其他资源却是与父进程共享的,比如文件指针,socket描述符等 不同的进程使用不同的地址空间,子进程被创建后, ...