Storm 从入门到精通 第二十四讲 Storm 批处理事务 - Storm自带的例子TransactionalGlobalCount

TransactionalGlobalCount :统计多个分区的单词数总和。此处3个分区,共计19个单词。分区的概念:学习MQ,kafka分区等等,主要用于提高消息read吞吐量。


MemoryTransactionalSpout 

MemoryTransactionalSpout spout = new MemoryTransactionalSpout(DATA, new Fields("word"),PARTITION_TAKE_PER_BATCH);

参数说明: 第一个 分区数据,第二个 下一个Bolt接收Stream数field名称, 第三个参数指定每个batch的最大tuple数量

TransactionalGlobalCount Topology:TransactionalTopologyBuilder 将batch的计算分为两个阶段:process阶段和commit阶段。process阶段可以同时处理多个batch,不用保证顺序性,commit阶段保证batch的强顺序性,并且在commit阶段每次只能处理一个batch。

public static void main(String[] args) throws Exception {

		MemoryTransactionalSpout spout = new MemoryTransactionalSpout(DATA, new Fields("word"),
				PARTITION_TAKE_PER_BATCH);
		TransactionalTopologyBuilder builder = new TransactionalTopologyBuilder("global-count", "spout", spout, 3);
		builder.setBolt("partial-count", new BatchCount(), 5).noneGrouping("spout"); //shuffle group一样的,但在同一个Executor内存中运行
		builder.setBolt("sum", new UpdateGlobalCount()).globalGrouping("partial-count"); //dreict min task id 的 bolt task 中运行

		Config config = new Config();
		config.setDebug(true);
		config.setMaxSpoutPending(3);

		// StormSubmitter.submitTopology("global-count-topology", config,
		// builder.buildTopology());

		LocalCluster localCluster = new LocalCluster();
		localCluster.submitTopology("global-count-topology", config, builder.buildTopology());

	}
MemoryTransactionalSpout --》 BatchCount --》UpdateGlobalCount

BatchCount:按照每批Txid,统计word出现次数。Object id:transaction id

public static class BatchCount extends BaseBatchBolt<Object> {
		Object _id;
		BatchOutputCollector _collector;

		int _count = 0;

		public void prepare(Map conf, TopologyContext context, BatchOutputCollector collector, Object id) {
			_collector = collector;
			_id = id;
		}

		@Override
		public void execute(Tuple tuple) {
			_count++;

		}

		@Override
		public void finishBatch() {
			_collector.emit(new Values(_id, _count));
		}

		@Override
		public void declareOutputFields(OutputFieldsDeclarer declarer) {
			declarer.declare(new Fields("id", "count"));
		}
	}

      BatchCount的prepare方法最后一个参数是batchid,在Transactional Topology里面这个id是一个TransactionAttempt对象,Transactional Topology里面发送的tuple,读必须以TransactionAttempt作为第一个field,Storm根据这个field爱判断tuple属于哪个batch。

  TransactionAttempt里面包含两个值,一个是txid,两外一个是attemptid,txid就是上面我们介绍的对于每一个batch里的tuple是唯一的。attemptid是每个batch唯一的一个ID,但是对每一个batch,它reply之后的attemptid和reply之前的attemptid是不一样的,我们可以吧attemptid理解为reply-times,Storm利用这个ID来区别一个batch发射的tuple的版本。

  execute方法会为batch中的每一个tuple执行一次,你应该把这个batch里面的计算状态保持在一个本地变量里面。对于这个例子来说,它在execute方法里面递增tuple的个数。

  最后,当这个Bolt接收到每个batch的所有的tuple之后,finishBatch方法会被执行。

UpdateGlobalCount  :UpdateGlobalCount实现了ICommitter接口,所以Storm会在commit阶段调用finishBatch方法,而execute方法可以在任何阶段完成。

public static class UpdateGlobalCount extends BaseTransactionalBolt implements ICommitter {
		TransactionAttempt _attempt;
		BatchOutputCollector _collector;

		int _sum = 0;
		boolean error = true;

		@Override
		public void prepare(Map conf, TopologyContext context, BatchOutputCollector collector,
				TransactionAttempt attempt) {
			_collector = collector;
			_attempt = attempt;
		}

		@Override
		public void execute(Tuple tuple) {
			_sum += tuple.getInteger(1);

		}

		@Override
		public void finishBatch() {
			Value val = DATABASE.get(GLOBAL_COUNT_KEY);
			Value newval;
			if (val == null || !val.txid.equals(_attempt.getTransactionId())) { //数据有新的更新
				newval = new Value();
				newval.txid = _attempt.getTransactionId();
				if (val == null) {
					newval.count = _sum;
				} else {
					newval.count = _sum + val.count; //数据库已经记录上一个txid 的单词次数出现总和
				}
				DATABASE.put(GLOBAL_COUNT_KEY, newval);
			} else {
				newval = val;
			}
			_collector.emit(new Values(_attempt, newval.count));

			System.err.println("val sum:" + newval.count);
		}

		@Override
		public void declareOutputFields(OutputFieldsDeclarer declarer) {
			declarer.declare(new Fields("id", "sum"));
		}
	}

在UpdateGlobalCount的finishBatch方法中将当前的txid与数据库中的id作比较。

如果相同,则忽略这个batch,说明已经完成统计,

如果不同则吧这个batch的计算结果合并到总的结果中,并更新数据库。

Transactional Topology的运行示意图如下:
  

Transnational Topology特性:

  1.Transactional Topology将事物机制封装好,其内部使用CoordinateBolt保证一个batch中的tuple被处理完

  2.TransactionalSpout只有一个,它将所有的tuple分组为一个一个的batch,而且保证同一个batch的txid始终一样

  3.BatchBolt处理一个batch中的每一个tuple,对每一个tuple调用execute方法,并在所有的tuple都处理完后调用finishBatch方法

  4.如果batchBolt实现了ICommitter接口,则只能在commit阶段调用finishBatch


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值