一、关联代码

使用maven,代码如下。

pom.xml  参考 http://www.cnblogs.com/hd3013779515/p/6970551.html

MessageTopology.java

  1. package cn.ljh.storm.reliability;
  2.  
  3. import org.apache.storm.Config;
  4. import org.apache.storm.LocalCluster;
  5. import org.apache.storm.topology.TopologyBuilder;
  6. import org.apache.storm.utils.Utils;
  7.  
  8. public class MessageTopology {
  9. public static void main(String[] args) throws Exception {
  10. TopologyBuilder builder = new TopologyBuilder();
  11.  
  12. builder.setSpout("MessageSpout", new MessageSpout(), 1);
  13. builder.setBolt("SpilterBolt", new SpliterBolt(), 5).shuffleGrouping("MessageSpout");
  14. builder.setBolt("WriterBolt", new WriterBolt(), 1).shuffleGrouping("SpilterBolt");
  15.  
  16. Config conf = new Config();
  17. conf.setDebug(false);
  18.  
  19. LocalCluster cluster = new LocalCluster();
  20. cluster.submitTopology("messagetest", conf, builder.createTopology());
  21. Utils.sleep(20000);
  22. cluster.killTopology("messagetest");
  23. cluster.shutdown();
  24. }
  25. }

MessageSpou.java

  1. package cn.ljh.storm.reliability;
  2.  
  3. import org.apache.storm.topology.OutputFieldsDeclarer;
  4.  
  5. import java.util.Map;
  6. import org.apache.storm.spout.SpoutOutputCollector;
  7. import org.apache.storm.task.TopologyContext;
  8. import org.apache.storm.topology.base.BaseRichSpout;
  9. import org.apache.storm.tuple.Fields;
  10. import org.apache.storm.tuple.Values;
  11.  
  12. import org.slf4j.Logger;
  13. import org.slf4j.LoggerFactory;
  14.  
  15. public class MessageSpout extends BaseRichSpout {
  16. public static Logger LOG = LoggerFactory.getLogger(MessageSpout.class);
  17. private SpoutOutputCollector _collector;
  18.  
  19. private int index = 0;
  20. private String[] subjects = new String[]{
  21. "Java,Python",
  22. "Storm,Kafka",
  23. "Spring,Solr",
  24. "Zookeeper,FastDFS",
  25. "Dubbox,Redis"
  26. };
  27.  
  28. public void open(Map conf, TopologyContext context, SpoutOutputCollector collector) {
  29. _collector = collector;
  30. }
  31.  
  32. public void nextTuple() {
  33.  
  34. if(index < subjects.length){
  35. String sub = subjects[index];
  36. //使用messageid参数,使可靠性机制生效
  37. _collector.emit(new Values(sub), index);
  38. index++;
  39. }
  40. }
  41.  
  42. public void declareOutputFields(OutputFieldsDeclarer declarer) {
  43. declarer.declare(new Fields("subjects"));
  44. }
  45.  
  46. @Override
  47. public void ack(Object msgId) {
  48. LOG.info("【消息发送成功!】(msgId = " + msgId + ")");
  49. }
  50.  
  51. @Override
  52. public void fail(Object msgId) {
  53. LOG.info("【消息发送失败!】(msgId = " + msgId + ")");
  54. LOG.info("【重发进行中。。。】");
  55. _collector.emit(new Values(subjects[(Integer)msgId]), msgId);
  56. LOG.info("【重发成功!】");
  57. }
  58.  
  59. }

SpliterBolt.java

  1. package cn.ljh.storm.reliability;
  2.  
  3. import java.util.Map;
  4.  
  5. import org.apache.storm.task.OutputCollector;
  6. import org.apache.storm.task.TopologyContext;
  7. import org.apache.storm.topology.OutputFieldsDeclarer;
  8. import org.apache.storm.topology.base.BaseRichBolt;
  9. import org.apache.storm.tuple.Fields;
  10. import org.apache.storm.tuple.Tuple;
  11. import org.apache.storm.tuple.Values;
  12.  
  13. public class SpliterBolt extends BaseRichBolt {
  14. OutputCollector _collector;
  15. private boolean flag = false;
  16.  
  17. public void prepare(Map conf, TopologyContext context, OutputCollector collector) {
  18. _collector = collector;
  19. }
  20.  
  21. public void execute(Tuple tuple) {
  22.  
  23. try{
  24. String subjects = tuple.getStringByField("subjects");
  25.  
  26. // if(!flag && subjects.equals("Spring,Solr")){
  27. // flag = true;
  28. // int a = 1/0;
  29. // }
  30.  
  31. String[] words = subjects.split(",");
  32. for(String word : words){
  33. //注意:要携带tuple对象,用于处理异常时重发策略。
  34. _collector.emit(tuple, new Values(word));
  35. }
  36.  
  37. //对tuple进行ack
  38. _collector.ack(tuple);
  39. }catch(Exception ex){
  40. ex.printStackTrace();
  41. //对tuple进行fail,使重发。
  42. _collector.fail(tuple);
  43. }
  44. }
  45.  
  46. public void declareOutputFields(OutputFieldsDeclarer declarer) {
  47. declarer.declare(new Fields("word"));
  48. }
  49.  
  50. }

WriterBolt.java

  1. package cn.ljh.storm.reliability;
  2.  
  3. import java.io.FileWriter;
  4. import java.io.IOException;
  5. import java.util.Map;
  6.  
  7. import org.apache.storm.task.OutputCollector;
  8. import org.apache.storm.task.TopologyContext;
  9. import org.apache.storm.topology.OutputFieldsDeclarer;
  10. import org.apache.storm.topology.base.BaseRichBolt;
  11. import org.apache.storm.tuple.Tuple;
  12. import org.slf4j.Logger;
  13. import org.slf4j.LoggerFactory;
  14.  
  15. public class WriterBolt extends BaseRichBolt {
  16. private static Logger LOG = LoggerFactory.getLogger(WriterBolt.class);
  17. OutputCollector _collector;
  18.  
  19. private FileWriter fileWriter;
  20. private boolean flag = false;
  21.  
  22. public void prepare(Map conf, TopologyContext context, OutputCollector collector) {
  23. _collector = collector;
  24.  
  25. if(fileWriter == null){
  26. try {
  27. fileWriter = new FileWriter("D:\\test\\"+"words.txt");
  28. } catch (IOException e) {
  29. e.printStackTrace();
  30. }
  31. }
  32.  
  33. }
  34.  
  35. public void execute(Tuple tuple) {
  36. try {
  37. String word = tuple.getStringByField("word");
  38.  
  39. // if(!flag && word.equals("Kafka")){
  40. // flag = true;
  41. // int a = 1/0;
  42. // }
  43. fileWriter.write(word + "\r\n");
  44. fileWriter.flush();
  45. } catch (Exception e) {
  46. e.printStackTrace();
  47. //对tuple进行fail,使重发。
  48. _collector.fail(tuple);
  49. }
  50. //对tuple进行ack
  51. _collector.ack(tuple);
  52. }
  53.  
  54. public void declareOutputFields(OutputFieldsDeclarer declarer) {
  55. }
  56. }

二、执行效果

1、代码要点说明

MessageSpout.java

(1)发射tuple时要设置messageId来使可靠性机制生效

  1. _collector.emit(new Values(sub), index);

(2)重写ack和fail方法

  1. @Override
  2. public void ack(Object msgId) {
  3. LOG.info("【消息发送成功!】(msgId = " + msgId + ")");
  4. }
  5.  
  6. @Override
  7. public void fail(Object msgId) {
  8. LOG.info("【消息发送失败!】(msgId = " + msgId + ")");
  9. LOG.info("【重发进行中。。。】");
  10. _collector.emit(new Values(subjects[(Integer)msgId]), msgId);
  11. LOG.info("【重发成功!】");
  12. }

SpliterBolt.java

(1)发射新tuple时设置输入tuple参数,以使新tuple和输入tuple为一个整体

  1. _collector.emit(tuple, new Values(word));

(2)完成处理后进行ack,失败时进行fail

  1. _collector.ack(tuple);
  2.  
  3. _collector.fail(tuple);

WriterBolt.java

(1)完成处理后进行ack,失败时进行fail

  1. _collector.ack(tuple);
  2.  
  3. _collector.fail(tuple);

2、正常处理结果

3、放开SpliterBolt 的错误代码

结果显示能够正确的重发。

4、放开SpliterBolt 的错误代码

能够正确进行重发,但是文件中storm字符串出现了两次。

5、总结

通过以上测试,如果在第一个bolt处理时出现异常,可以让整个数据进行重发,如果第二个bolt处理时出现异常,也可以让整个数据进行重发,但是同时出现了重复处理的事务性问题,需要进行特殊的处理。

(1)如果数据入库的话,可以把messageId也进行入库保存。此messageId可以用来判断是否重复处理。

(2)事务性tuple尽量不要拆分。

(3)使用storm的Trident框架。

 

Storm入门(七)可靠性机制代码示例的更多相关文章

  1. Storm入门(四)WordCount示例

    一.关联代码 使用maven,代码如下. pom.xml  和Storm入门(三)HelloWorld示例相同 RandomSentenceSpout.java /** * Licensed to t ...

  2. Linux信号机制代码示例

    1 基本功能: 本Blog创建了两个进程(父子进程): 父进程: 执行文本复制操作,当收到 SIGUSR1信号后,打印出现在文件复制的进度: 子进程: 每个固定时间段向父进程发送一个 SIGUSR1 ...

  3. Storm入门(三)HelloWorld示例

    一.配置开发环境 storm有两种操作模式: 本地模式和远程模式.使用本地模式的时候,你可以在你的本地机器上开发测试你的topology, 一切都在你的本地机器上模拟出来; 用远程模式的时候你提交的t ...

  4. <MyBatis>入门七 缓存机制

    缓存机制 MyBatis包含强大的查询缓存特性,它可以非常方便的定制和配置.缓存可以极大的提升查询效率. MyBatis默认定义了两级缓存:一级缓存和二级缓存 1.默认情况下,只有一级缓存(sqlSe ...

  5. Storm入门(六)深入理解可靠性机制

    转自http://blog.csdn.net/zhangzhebjut/article/details/38467145 一 可靠性简介 Storm的可靠性是指Storm会告知用户每一个消息单元是否在 ...

  6. My.Ioc 代码示例——使用观察者机制捕获注册项状态的变化

    在 My.Ioc 中,要想在服务注销/注册时获得通知,可以通过订阅 ObjectBuilderRegistered 和 ObjectBuilderUnregistering 这两个事件来实现.但是,使 ...

  7. 中文代码示例之Angular入门教程尝试

    原址: https://zhuanlan.zhihu.com/p/30853705 原文: 中文代码示例教程之Angular尝试 为了检验中文命名在Angular中的支持程度, 把Angular官方入 ...

  8. 中文代码示例之Vuejs入门教程(一)

    原址: https://zhuanlan.zhihu.com/p/30917346 为了检验中文命名在主流框架中的支持程度, 在vuejs官方入门教程第一部分的示例代码中尽量使用了中文命名. 所有演示 ...

  9. 2017-10-31 中文代码示例教程之Vuejs入门&后续计划

    "中文编程"知乎专栏原链 为了检验中文命名在主流框架中的支持程度, 这里把vuejs官方入门教程第一部分的示例代码中尽量使用了中文命名. 过程中有一些发现, 初步看来Vuejs对中 ...

随机推荐

  1. linux中~/cut/argus/

    1.Linux shell 截取字符变量的前8位 实现方法有如下几种: expr substr "$a" 1 8 echo $a|awk '{print substr(,1,8)} ...

  2. JavaScript Array+String对象的常用方法

    Array 对象 Array 对象用于在单个的变量中存储多个值. 创建 Array 对象的语法: new Array(); new Array(size); new Array(element0, e ...

  3. 远程连接MySQL(MariaDB)数据库

    网络环境: MySQL(MariaDB)服务器的操作系统为 CentOS 7 MySQL(MariaDB)服务器IP:172.16.230.15 客户端操作系统为 Windows 2008 R2 客户 ...

  4. Robomongo连接MongoDB 报 Authorization failed 解决办法

    首先将MongoDB安装文件的bin目录添加到环境变量Path中 如图: 这样就可以直接在cmd命令行,不需要进行目录切换,就可以直接使用啦 打开dos命令框 依次输入下图修改admin密码

  5. 根据高德API知道坐标获取详细地址信息

    /** * 根据坐标获取具体地址 * @param coor 坐标字符串 * @return */ public static String getAdd(String coor){ String u ...

  6. 关于find命令的一些知识

    在服务器运维的过程中,我们会用到这样一个命令,关于这个命令,你知道多少呢?接下来,咱们一起来研究一下它的用途. find命令主要用来在硬盘上搜索文件, find命令主要用于文件查找,列出当前目录及子目 ...

  7. client_v1.go

    package nsqlookupd import (     "net" ) //客户端 结构体 type ClientV1 struct {     net.Conn //客户 ...

  8. java.lang.IllegalArgumentException异常 数据库别名问题

    java.lang.IllegalArgumentException: org.hibernate.hql.internal.ast.QuerySyntaxException: Path expect ...

  9. 【BZOJ 3626】 [LNOI2014]LCA【在线+主席树+树剖】

    题目链接: TP 题解:   可能是我比较纱布,看不懂题解,只好自己想了…… 先附一个离线版本题解[Ivan] 我们考虑对于询问区间是可以差分的,然而这并没有什么卵用,然后考虑怎么统计答案. 首先LC ...

  10. [Poi2014]FarmCraft 树状dp

    对于每个点,处理出走完其子树所需要的时间和其子树完全下载完软件的时间 易证,对于每个点的所有子节点,一定优先选择差值大的来给后面的时间 树规+贪心. #include<cstdio> #i ...