Storm中的定时任务
1.全局定时器
1 import java.util.Map; 2 3 import backtype.storm.Config; 4 import backtype.storm.Constants; 5 import backtype.storm.LocalCluster; 6 import backtype.storm.spout.SpoutOutputCollector; 7 import backtype.storm.task.OutputCollector; 8 import backtype.storm.task.TopologyContext; 9 import backtype.storm.topology.OutputFieldsDeclarer; 10 import backtype.storm.topology.TopologyBuilder; 11 import backtype.storm.topology.base.BaseRichBolt; 12 import backtype.storm.topology.base.BaseRichSpout; 13 import backtype.storm.tuple.Fields; 14 import backtype.storm.tuple.Tuple; 15 import backtype.storm.tuple.Values; 16 import backtype.storm.utils.Utils; 17 18 /** 19 * 全局定时器 20 * 21 * 数字累加求和 22 * 先添加storm依赖 23 * 24 * @author Administrator 25 * 26 */ 27 public class LocalTopologySumTimer1 { 28 29 30 /** 31 * spout需要继承baserichspout,实现未实现的方法 32 * @author Administrator 33 * 34 */ 35 public static class MySpout extends BaseRichSpout{ 36 private Map conf; 37 private TopologyContext context; 38 private SpoutOutputCollector collector; 39 40 /** 41 * 初始化方法,只会执行一次 42 * 在这里面可以写一个初始化的代码 43 * Map conf:其实里面保存的是topology的一些配置信息 44 * TopologyContext context:topology的上下文,类似于servletcontext 45 * SpoutOutputCollector collector:发射器,负责向外发射数据(tuple) 46 */ 47 @Override 48 public void open(Map conf, TopologyContext context, 49 SpoutOutputCollector collector) { 50 this.conf = conf; 51 this.context = context; 52 this.collector = collector; 53 } 54 55 int num = 1; 56 /** 57 * 这个方法是spout中最重要的方法, 58 * 这个方法会被storm框架循环调用,可以理解为这个方法是在一个while循环之内 59 * 每调用一次,会向外发射一条数据 60 */ 61 @Override 62 public void nextTuple() { 63 System.out.println("spout发射:"+num); 64 //把数据封装到values中,称为一个tuple,发射出去 65 this.collector.emit(new Values(num++)); 66 Utils.sleep(1000); 67 } 68 69 /** 70 * 声明输出字段 71 */ 72 @Override 73 public void declareOutputFields(OutputFieldsDeclarer declarer) { 74 //给values中的数据起个名字,方便后面的bolt从这个values中取数据 75 //fields中定义的参数和values中传递的数值是一一对应的 76 declarer.declare(new Fields("num")); 77 } 78 79 } 80 81 82 /** 83 * 自定义bolt需要实现baserichbolt 84 * @author Administrator 85 * 86 */ 87 public static class MyBolt extends BaseRichBolt{ 88 private Map stormConf; 89 private TopologyContext context; 90 private OutputCollector collector; 91 92 /** 93 * 和spout中的open方法意义一样 94 */ 95 @Override 96 public void prepare(Map stormConf, TopologyContext context, 97 OutputCollector collector) { 98 this.stormConf = stormConf; 99 this.context = context; 100 this.collector = collector; 101 } 102 103 int sum = 0; 104 /** 105 * 是bolt中最重要的方法,当spout发射一个tuple出来,execute也会被调用,需要对spout发射出来的tuple进行处理 106 */ 107 @Override 108 public void execute(Tuple input) { 109 if(input.getSourceComponent().equals(Constants.SYSTEM_COMPONENT_ID)){ 110 //如果满足,就说明这个tuple是系统几倍的组件发送的,也就意味着定时时间到了 111 System.out.println("定时任务执行了。"); 112 113 }else{//这个地方必须要做判断,否则让系统级别的tuple去取"num"会取不到报错的. 114 //这个地方的逻辑可以将产生的数据封装成一个map或者是list放在内存中.到达定时任务的时候取出来,使用batch批处理向数据库中操作. 115 //然后再把集合中的数据清空...之后再添加. 116 117 //input.getInteger(0);//也可以根据角标获取tuple中的数据 118 Integer value = input.getIntegerByField("num"); 119 sum+=value; 120 System.out.println("和:"+sum); 121 } 122 123 } 124 125 /** 126 * 声明输出字段 127 */ 128 @Override 129 public void declareOutputFields(OutputFieldsDeclarer declarer) { 130 //在这没必要定义了,因为execute方法中没有向外发射tuple,所以就不需要声明了。 131 //如果nextTuple或者execute方法中向外发射了tuple,那么declareOutputFields必须要声明,否则不需要声明 132 } 133 134 } 135 /** 136 * 注意:在组装topology的时候,组件的id在定义的时候,名称不能以__开头。__是系统保留的 137 * @param args 138 */ 139 public static void main(String[] args) { 140 //组装topology 141 TopologyBuilder topologyBuilder = new TopologyBuilder(); 142 topologyBuilder.setSpout("spout1", new MySpout()); 143 //.shuffleGrouping("spout1"); 表示让MyBolt接收MySpout发射出来的tuple 144 topologyBuilder.setBolt("bolt1", new MyBolt()).shuffleGrouping("spout1"); 145 146 //创建本地storm集群 147 LocalCluster localCluster = new LocalCluster(); 148 Config config = new Config(); 149 //下面这样设置就是一个全局的定时任务 还有局部的定时任务. 150 config.put(Config.TOPOLOGY_TICK_TUPLE_FREQ_SECS, 5);//表示每隔5秒storm会给Topology中的所有bolt发射一个系统级别的tuple 151 //前面的单词计数的例子 我们可能只需要在最后一个CountBolt中做定时任务 SpiltBolt中不需要做定时任务 但是两个Bolt中都可以收到这个系统级别的tuple 152 //所以需要每个Bolt中都做判断...SplitBolt可以加上一个判断 没有方法体...if(input.getSourceComponent().equals(Constants.SYSTEM_COMPONENT_ID)){ } 153 //否则会出错...从系统级别的tuple取你定义的值 取不到 报错. 154 localCluster.submitTopology("sumTopology", config, topologyBuilder.createTopology()); 155 156 } 157 158 159 }
局部定时器
1 /** 2 * 局部定时器 3 * 4 * 数字累加求和 5 * 先添加storm依赖 6 * 7 * @author Administrator 8 * 9 */ 10 public class LocalTopologySumTimer2 { 11 12 13 /** 14 * spout需要继承baserichspout,实现未实现的方法 15 * @author Administrator 16 * 17 */ 18 public static class MySpout extends BaseRichSpout{ 19 private Map conf; 20 private TopologyContext context; 21 private SpoutOutputCollector collector; 22 23 /** 24 * 初始化方法,只会执行一次 25 * 在这里面可以写一个初始化的代码 26 * Map conf:其实里面保存的是topology的一些配置信息 27 * TopologyContext context:topology的上下文,类似于servletcontext 28 * SpoutOutputCollector collector:发射器,负责向外发射数据(tuple) 29 */ 30 @Override 31 public void open(Map conf, TopologyContext context, 32 SpoutOutputCollector collector) { 33 this.conf = conf; 34 this.context = context; 35 this.collector = collector; 36 } 37 38 int num = 1; 39 /** 40 * 这个方法是spout中最重要的方法, 41 * 这个方法会被storm框架循环调用,可以理解为这个方法是在一个while循环之内 42 * 每调用一次,会向外发射一条数据 43 */ 44 @Override 45 public void nextTuple() { 46 System.out.println("spout发射:"+num); 47 //把数据封装到values中,称为一个tuple,发射出去 48 this.collector.emit(new Values(num++)); 49 Utils.sleep(1000); 50 } 51 52 /** 53 * 声明输出字段 54 */ 55 @Override 56 public void declareOutputFields(OutputFieldsDeclarer declarer) { 57 //给values中的数据起个名字,方便后面的bolt从这个values中取数据 58 //fields中定义的参数和values中传递的数值是一一对应的 59 declarer.declare(new Fields("num")); 60 } 61 62 } 63 64 65 /** 66 * 自定义bolt需要实现baserichbolt 67 * @author Administrator 68 * 69 */ 70 public static class MyBolt extends BaseRichBolt{ 71 private Map stormConf; 72 private TopologyContext context; 73 private OutputCollector collector; 74 75 /** 76 * 和spout中的open方法意义一样 77 */ 78 @Override 79 public void prepare(Map stormConf, TopologyContext context, 80 OutputCollector collector) { 81 this.stormConf = stormConf; 82 this.context = context; 83 this.collector = collector; 84 } 85 86 int sum = 0; 87 /** 88 * 是bolt中最重要的方法,当spout发射一个tuple出来,execute也会被调用,需要对spout发射出来的tuple进行处理 89 */ 90 @Override 91 public void execute(Tuple input) { 92 if(input.getSourceComponent().equals(Constants.SYSTEM_COMPONENT_ID)){ 93 //如果满足,就说明这个tuple是系统几倍的组件发送的,也就意味着定时时间到了 94 System.out.println("定时任务执行了。"); 95 96 }else{ 97 //input.getInteger(0);//也可以根据角标获取tuple中的数据 98 Integer value = input.getIntegerByField("num"); 99 sum+=value; 100 System.out.println("和:"+sum); 101 } 102 103 } 104 105 /** 106 * 声明输出字段 107 */ 108 @Override 109 public void declareOutputFields(OutputFieldsDeclarer declarer) { 110 //在这没必要定义了,因为execute方法中没有向外发射tuple,所以就不需要声明了。 111 //如果nextTuple或者execute方法中向外发射了tuple,那么declareOutputFields必须要声明,否则不需要声明 112 } 113 114 /** 115 * 局部定时任务 116 * 只针对当前的bolt 对其他的bolt中没有影响 117 * 加对系统级别tuple的判断只需要在当前bolt中判断就可以...其他bolt不需要.. 118 * 这种在工作中最常用.... 119 * 全局定时任务在 main方法中 设置 局部的定时任务只需要在Bolt类中覆盖getComponentConfiguration()方法 120 * 这个还是比较有用,有意思的 121 */ 122 @Override 123 public Map<String, Object> getComponentConfiguration() { 124 HashMap<String, Object> hashMap = new HashMap<String, Object>(); 125 hashMap.put(Config.TOPOLOGY_TICK_TUPLE_FREQ_SECS, 5); 126 return hashMap; 127 } 128 } 129 /** 130 * 注意:在组装topology的时候,组件的id在定义的时候,名称不能以__开头。__是系统保留的 131 * @param args 132 */ 133 public static void main(String[] args) { 134 //组装topology 135 TopologyBuilder topologyBuilder = new TopologyBuilder(); 136 topologyBuilder.setSpout("spout1", new MySpout()); 137 //.shuffleGrouping("spout1"); 表示让MyBolt接收MySpout发射出来的tuple 138 topologyBuilder.setBolt("bolt1", new MyBolt()).shuffleGrouping("spout1"); 139 140 //创建本地storm集群 141 LocalCluster localCluster = new LocalCluster(); 142 Config config = new Config(); 143 localCluster.submitTopology("sumTopology", config, topologyBuilder.createTopology()); 144 145 } 146 147 148 }
作者:SummerChill 出处:http://www.cnblogs.com/DreamDrive/ 本博客为自己总结亦或在网上发现的技术博文的转载。 如果文中有什么错误,欢迎指出。以免更多的人被误导。 |