package com.sid.bigdata.storm.sum;
import java.util.Map;
import org.apache.storm.Config;
import org.apache.storm.LocalCluster;
import org.apache.storm.spout.SpoutOutputCollector;
import org.apache.storm.task.OutputCollector;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.topology.TopologyBuilder;
import org.apache.storm.topology.base.BaseRichBolt;
import org.apache.storm.topology.base.BaseRichSpout;
import org.apache.storm.tuple.Fields;
import org.apache.storm.tuple.Tuple;
import org.apache.storm.tuple.Values;
import org.apache.storm.utils.Utils;
/**
* @author liyijie
* @date 2018年6月11日下午2:19:44
* @email 37024760@qq.com
* @remark
* @version
*
* ack和fail机制
*/
public class LocalSumStormTopology {
/**
* Spout需要继承BaseRichSpout
* 产生数据并且发送出去
* */
public static class DataSourceSpout extends BaseRichSpout{
private SpoutOutputCollector collector;
/**
* 初始化方法,在执行前只会被调用一次
* @param conf 配置参数
* @param context 上下文
* @param collector 数据发射器
* */
public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
this.collector = collector;
}
int number = 0;
/**
* 产生数据,生产上一般是从消息队列中获取数据
* */
public void nextTuple() {
++number;
//messageId是数据唯一编号,建议使用数据库中的主键
this.collector.emit(new Values(number),number);
System.out.println("spout发出:"+number);
Utils.sleep(1000);
}
/**
* 数据在topology中处理成功调用这个方法
* */
@Override
public void ack(Object msgId) {
System.out.println(" ack invoked ..."+msgId);
}
/**
* 数据在topology中处理失败调用这个方法
* */
@Override
public void fail(Object msgId) {
System.out.println(" fail invoked ..."+msgId);
//TODO... 对失败的数据进行重发或者保存到数据库
//this.collector.emit(new Values(number));
//this.dao.saveMsg(new Values(number));
}
/**
* 声明输出字段
* @param declarer
* */
public void declareOutputFields(OutputFieldsDeclarer declarer) {
/**
* num是上nextTuple中emit中的new Values对应的。上面发几个,这里就要定义几个字段。
* 在bolt中获取的时候,只需要获取num这个字段就行了。
* */
declarer.declare(new Fields("num"));
}
}
/**
* 数据的累计求和Bolt
* 接收数据并且处理
* */
public static class SumBolt extends BaseRichBolt{
private OutputCollector collector;
/**
* 初始化方法,只会被执行一次
* */
public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
this.collector = collector;
}
int sum=0;
/**
* 获取spout发送过来的数据
* */
public void execute(Tuple input) {
try{
//这里的num就是在spout中的declareOutputFields定义的字段名
//可以根据index获取,也可以根据上一个环节中定义的名称获取
Integer value = input.getIntegerByField("num");
sum+=value;
System.out.println("Bolt:sum="+sum);
//假设值大于10就是失败的,这里只是测试一下处理失败后会调用spout的方法,实际上应该是try-catch中用的
if(value>10){
this.collector.fail(input);
}
this.collector.ack(input);
}catch(Exception e){
this.collector.fail(input);
}
}
/**
* 声明输出字段
* @param declarer
* */
public void declareOutputFields(OutputFieldsDeclarer declarer) {
}
}
public static void main (String[] args){
//本地模式,没有提交到服务器集群上,不需要搭建storm集群
LocalCluster cluster = new LocalCluster();
//TopologyBuilder根据spout和bolt来构建Topology
//storm中任何一个作业都是通过Topology方式进行提交的
//Topology中需要指定spout和bolt的执行顺序
TopologyBuilder tb = new TopologyBuilder();
tb.setSpout("DataSourceSpout", new DataSourceSpout());
//SumBolt以随机分组的方式从DataSourceSpout中接收数据
tb.setBolt("SumBolt", new SumBolt()).shuffleGrouping("DataSourceSpout");
//第一个参数是topology的名称,第三个参数是Topology
cluster.submitTopology("LocalSumStormTopology", new Config(), tb.createTopology());
}
}
maven pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.sid.bigdata</groupId>
<artifactId>storm</artifactId>
<version>0.0.1</version>
<packaging>jar</packaging>
<name>storm</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<storm.version>1.1.1</storm.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.storm</groupId>
<artifactId>storm-core</artifactId>
<version>${storm.version}</version>
</dependency>
</dependencies>
</project>