Storm常见模式——批处理

消息流是storm里面的最关键的抽象。一个消息流是一个没有边界的tuple序列, 而这些tuples会被以一种 分布式的方式并行地创建和处理。 对消息流的定义主要是对消息流里面的tuple的定义, 我们会给tuple里的每个字段一个名字。 并且不同tuple的对应字段的类型必须一样。 也就是说: 两个tuple的第一个字段的类型必须一样, 第二个字段的类型必须一样, 但是第一个字段和第二个字段可以有不同的类型。 在默认的情况下, tuple的字段类型可以是: integer, long, short, byte, string, double, float, boolean和byte array。 你还可以自定义类型 — 只要你实现对应的序列化器。
更多概念可以参考:
导读:
1.Storm对流数据进行实时处理时,如何处理tuple?
2.ConcurrentLinkedQueue是否可存储tuple?

在读文章内容的时候,经常会忘掉里面的术语是什么,这里在strom中都补充一张图:
Storm对流数据进行实时处理时,一种常见场景是批量一起处理一定数量的tuple元组,而不是每接收一个tuple就立刻处理一个tuple,这样可能是性能的考虑,或者是具体业务的需要。
例如,批量查询或者更新数据库,如果每一条tuple生成一条sql执行一次数据库操作,数据量大的时候,效率会比批量处理的低很多,影响系统吞吐量。
当然,如果要使用Storm的可靠数据处理机制的话,应该使用容器将这些tuple的引用缓存到内存中,直到批量处理的时候,ack这些tuple。
下面给出一个简单的代码示例:
现在,假设我们已经有了一个DBManager数据库操作接口类,它至少有两个接口:
(1)getConnection(): 返回一个 java.sql.Connection对象;
(2)getSQL(Tuple tuple): 根据tuple元组生成 数据库操作语句。
为了在Bolt中缓存一定数量的tuple,构造Bolt时传递int n参数赋给Bolt的成员变量int count,指定每个n条tuple批量处理一次。
同时,为了在内存中缓存缓存Tuple,使用java concurrent中的ConcurrentLinkedQueue来 存储tuple,每当攒够count条tuple,就触发批量处理。
另外,考虑到数据量小(如很长时间内都没有攒够count条tuple)或者count条数设置过大时,因此,Bolt中加入了一个定时器,保证最多每个1秒钟进行一次批量处理tuple。
下面是Bolt的完整代码(仅供参考):
  1. import java.util.Map;
  2. import java.util.Queue;
  3. import java.util.concurrent.ConcurrentLinkedQueue;
  4. import java.sql.Connection;
  5. import java.sql.SQLException;
  6. import java.sql.Statement;

  7. import backtype.storm.task.OutputCollector;
  8. import backtype.storm.task.TopologyContext;
  9. import backtype.storm.topology.IRichBolt;
  10. import backtype.storm.topology.OutputFieldsDeclarer;
  11. import backtype.storm.tuple.Tuple;

  12. public class BatchingBolt implements IRichBolt {
  13.     private static final long serialVersionUID = 1L;
  14.     private OutputCollector collector;
  15.     private Queue<Tuple> tupleQueue = new ConcurrentLinkedQueue<Tuple>();
  16.     private int count;
  17.     private long lastTime;
  18.     private Connection conn;

  19.     public BatchingBolt(int n) {
  20.         count = n; //批量处理的Tuple记录条数
  21.         conn = DBManger.getConnection(); //通过DBManager获取数据库连接
  22.         lastTime = System.currentTimeMillis(); //上次批量处理的时间戳
  23.     }

  24.     @Override
  25.     public void prepare(Map stormConf, TopologyContext context,
  26.             OutputCollector collector) {
  27.         this.collector = collector;
  28.     }

  29.     @Override
  30.     public void execute(Tuple tuple) {
  31.         tupleQueue.add(tuple);
  32.         long currentTime = System.currentTimeMillis();
  33.         // 每count条tuple批量提交一次,或者每个1秒钟提交一次
  34.         if (tupleQueue.size() >= count || currentTime >= lastTime + 1000) {
  35.             Statement stmt = conn.createStatement();
  36.             conn.setAutoCommit(false);
  37.             for (int i = 0; i < count; i++) {
  38.                 Tuple tup = (Tuple) tupleQueue.poll();
  39.                 String sql = DBManager.getSQL(tup); //生成sql语句
  40.                 stmt.addBatch(sql); //加入sql
  41.                 collector.ack(tup); //进行ack
  42.             }
  43.             stmt.executeBatch(); //批量提交sql
  44.             conn.commit();
  45.             conn.setAutoCommit(true);
  46.             System.out.println("batch insert data into database, total records: " + count);
  47.             lastTime = currentTime;
  48.         }
  49.     }

  50.     @Override
  51.     public void cleanup() {
  52.     }

  53.     @Override
  54.     public void declareOutputFields(OutputFieldsDeclarer declarer) {
  55.     }

  56.     @Override
  57.     public Map<String, Object> getComponentConfiguration() {
  58.         // TODO Auto-generated method stub
  59.         return null;
  60.     }
  61. }
复制代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

0X码上链

你的鼓将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值