普通事务API详解
1 | public interface ITransactionalSpout<T> extends IComponent { |
2 | public interface Coordinator<X> { |
3 | // 事务初始化 |
4 | X initializeTransaction(BigInteger txid, X prevMetadata); |
5 | // 启动事务,返回true表示开始 |
6 | boolean isReady(); |
7 | // 结束时调用主要用于释放资源 |
8 | void close(); |
9 | } |
10 | |
11 | public interface Emitter<X> { |
12 | // 发射batch中的tuple到下一级Bolt |
13 | void emitBatch(TransactionAttempt tx, X coordinatorMeta, BatchOutputCollector collector); |
14 | // 根据事务ID进行状态数据的清理 |
15 | void cleanupBefore(BigInteger txid); |
16 | // 结束时调用主要用于释放资源 |
17 | void close(); |
18 | } |
19 | |
20 | Coordinator<T> getCoordinator(Map conf, TopologyContext context); |
21 | |
22 | Emitter<T> getEmitter(Map conf, TopologyContext context); |
23 | } |
示例
入口类
1 | public class TestMain { |
2 | |
3 | public static void main(String[] args) { |
4 | |
5 | TransactionalTopologyBuilder builder = new TransactionalTopologyBuilder( |
6 | "ttbId", "spoutid", new TestTransaction(), 1); |
7 | builder.setBolt("bolt1", new TestTransBolt1(), 3).shuffleGrouping( |
8 | "spoutid"); |
9 | builder.setBolt("committer", new TestTransBolt2(), 1).shuffleGrouping( |
10 | "bolt1"); |
11 | |
12 | Config conf = new Config(); |
13 | conf.setDebug(false); |
14 | |
15 | if (args.length > 0) { |
16 | try { |
17 | StormSubmitter.submitTopology(args[0], conf, |
18 | builder.buildTopology()); |
19 | } catch (AlreadyAliveException e) { |
20 | e.printStackTrace(); |
21 | } catch (InvalidTopologyException e) { |
22 | e.printStackTrace(); |
23 | } |
24 | } else { |
25 | LocalCluster localCluster = new LocalCluster(); |
26 | localCluster.submitTopology("mytopology", conf, |
27 | builder.buildTopology()); |
28 | } |
29 | } |
30 | |
31 | } |
普通事务spout
1 | public class TestTransaction implements ITransactionalSpout<TestMetaDate> { |
2 | |
3 | private static final long serialVersionUID = 1L; |
4 | private Map<Long, String> DATA_BASE = null; |
5 | |
6 | public TestTransaction(){ |
7 | DATA_BASE = new HashMap<Long, String>(); |
8 | |
9 | for (long i=0;i<50;i++){ |
10 | DATA_BASE.put(i, "TestTransaction:"+i); |
11 | } |
12 | |
13 | System.out.println("TestTransaction start"); |
14 | } |
15 | |
16 | @Override |
17 | public void declareOutputFields(OutputFieldsDeclarer declarer) { |
18 | declarer.declare(new Fields("tx","count")); |
19 | } |
20 | |
21 | @Override |
22 | public Map<String, Object> getComponentConfiguration() { |
23 | return null; |
24 | } |
25 | |
26 | @Override |
27 | public backtype.storm.transactional.ITransactionalSpout.Coordinator<TestMetaDate> getCoordinator( |
28 | Map conf, TopologyContext context) { |
29 | System.out.println("TestTransaction getCoordinator start"); |
30 | return new TestCoordinator(); |
31 | } |
32 | |
33 | @Override |
34 | public backtype.storm.transactional.ITransactionalSpout.Emitter<TestMetaDate> getEmitter( |
35 | Map conf, TopologyContext context) { |
36 | System.out.println("TestTransaction getEmitter start"); |
37 | return new TestEmitter(DATA_BASE); |
38 | } |
39 | } |
元数据实现类(存储到zookeeper中)
1 | public class TestMetaDate implements Serializable { |
2 | |
3 | private static final long serialVersionUID = 1L; |
4 | |
5 | private long _index; |
6 | private long _size; |
7 | |
8 | public long get_index() { |
9 | return _index; |
10 | } |
11 | public void set_index(long _index) { |
12 | this._index = _index; |
13 | } |
14 | |
15 | public long get_size() { |
16 | return _size; |
17 | } |
18 | public void set_size(long _size) { |
19 | this._size = _size; |
20 | } |
21 | |
22 | @Override |
23 | public String toString() { |
24 | return "[_index=" + _index + ", _size=" + _size + "]"; |
25 | } |
26 | } |
元数据协调处理类
1 | public class TestCoordinator implements ITransactionalSpout.Coordinator<TestMetaDate>{ |
2 | |
3 | public TestCoordinator(){ |
4 | System.out.println("TestCoordinator start"); |
5 | } |
6 | |
7 | @Override |
8 | public TestMetaDate initializeTransaction(BigInteger txid, |
9 | TestMetaDate prevMetadata) { |
10 | long index = 0L; |
11 | if (null == prevMetadata){ |
12 | index = 0L; |
13 | } |
14 | else { |
15 | index = prevMetadata.get_index()+prevMetadata.get_size(); |
16 | } |
17 | TestMetaDate metaDate = new TestMetaDate(); |
18 | metaDate.set_index(index); |
19 | metaDate.set_size(10); |
20 | System.out.println("开始事务:"+metaDate.toString()); |
21 | return metaDate; |
22 | } |
23 | |
24 | @Override |
25 | public boolean isReady() { |
26 | Utils.sleep(1000); |
27 | return true; |
28 | } |
29 | |
30 | @Override |
31 | public void close() { |
32 | } |
33 | |
34 | } |
Batch中的tuple发送处理类
1 | public class TestEmitter implements ITransactionalSpout.Emitter<TestMetaDate> { |
2 | |
3 | private Map<Long, String> _dbMap = null; |
4 | |
5 | public TestEmitter(Map<Long, String> dbMap) { |
6 | System.err.println("start TestEmitter"); |
7 | this._dbMap = dbMap; |
8 | } |
9 | |
10 | @Override |
11 | public void emitBatch(TransactionAttempt tx, TestMetaDate coordinatorMeta, |
12 | BatchOutputCollector collector) { |
13 | long index = coordinatorMeta.get_index(); |
14 | long size = index + coordinatorMeta.get_size(); |
15 | System.err.println("TestEmitter emitBatch size:" + size |
16 | + ",_dbMap size:" + _dbMap.size()); |
17 | if (size > _dbMap.size()) { |
18 | return; |
19 | } |
20 | for (; index < size; index++) { |
21 | if (null == _dbMap.get(index)) { |
22 | System.out.println("TestEmitter continue"); |
23 | continue; |
24 | } |
25 | System.err.println("TestEmitter emitBatch index:"+index); |
26 | collector.emit(new Values(tx, _dbMap.get(index))); |
27 | } |
28 | } |
29 | |
30 | @Override |
31 | public void cleanupBefore(BigInteger txid) { |
32 | } |
33 | |
34 | @Override |
35 | public void close() { |
36 | } |
37 | |
38 | } |
数据单元统计实现类
1 | public class TestTransBolt1 extends BaseTransactionalBolt { |
2 | |
3 | private static final long serialVersionUID = 1L; |
4 | private BatchOutputCollector _outputCollector; |
5 | private TransactionAttempt _tx; |
6 | private int count = 0; |
7 | private TopologyContext _context; |
8 | |
9 | public TestTransBolt1() { |
10 | System.out.println("start TestTransBolt1 "); |
11 | } |
12 | |
13 | @Override |
14 | public void prepare(@SuppressWarnings("rawtypes") Map conf, |
15 | TopologyContext context, BatchOutputCollector collector, |
16 | TransactionAttempt id) { |
17 | this._context = context; |
18 | this._outputCollector = collector; |
19 | System.out.println("1 prepare TestTransBolt1 TransactionId:" |
20 | + id.getTransactionId() + ",AttemptId:" + id.getAttemptId()); |
21 | |
22 | } |
23 | |
24 | @Override |
25 | public void execute(Tuple tuple) { |
26 | _tx = (TransactionAttempt) tuple.getValueByField("tx"); |
27 | String content = tuple.getStringByField("count"); |
28 | System.out.println("1 TaskId:"+_context.getThisTaskId()+",TestTransBolt1 TransactionAttempt " |
29 | + _tx.getTransactionId() + " attemptid" + _tx.getAttemptId()); |
30 | if (null != content && !content.isEmpty()) { |
31 | count++; |
32 | } |
33 | } |
34 | |
35 | @Override |
36 | public void finishBatch() { |
37 | System.out.println("1 TaskId:"+_context.getThisTaskId()+",finishBatch count:"+count); |
38 | _outputCollector.emit(new Values(_tx, count)); |
39 | } |
40 | |
41 | @Override |
42 | public void declareOutputFields(OutputFieldsDeclarer declarer) { |
43 | declarer.declare(new Fields("tx", "count")); |
44 | } |
45 | |
46 | } |
数据汇总统计实现类
1 | public class TestTransBolt2 extends BaseTransactionalBolt implements ICommitter { |
2 | |
3 | private static final long serialVersionUID = 1L; |
4 | private int sum = 0; |
5 | private TransactionAttempt _tx; |
6 | private static int _result = 0; |
7 | private static BigInteger _curtxid=null; |
8 | |
9 | public TestTransBolt2() { |
10 | System.out.println("TestTransBolt2 start!"); |
11 | } |
12 | |
13 | @Override |
14 | public void prepare(@SuppressWarnings("rawtypes") Map conf, |
15 | TopologyContext context, BatchOutputCollector collector, |
16 | TransactionAttempt id) { |
17 | |
18 | this._tx = id; |
19 | System.out.println("TestTransBolt2 prepare TransactionId:" + id); |
20 | } |
21 | |
22 | @Override |
23 | public void execute(Tuple tuple) { |
24 | _tx = (TransactionAttempt) tuple.getValueByField("tx"); |
25 | sum += tuple.getIntegerByField("count"); |
26 | |
27 | System.out.println("TestTransBolt2 execute TransactionAttempt:" + _tx); |
28 | } |
29 | |
30 | @Override |
31 | public void finishBatch() { |
32 | System.out.println("finishBatch _curtxid:" + _curtxid |
33 | + ",getTransactionId:" + _tx.getTransactionId()); |
34 | if (null == _curtxid || !_curtxid.equals(_tx.getTransactionId())) { |
35 | |
36 | System.out.println("****** 1 _curtxid:" + _curtxid |
37 | + ",_tx.getTransactionId():" + _tx.getTransactionId()); |
38 | |
39 | if (null == _curtxid) { |
40 | _result = sum; |
41 | } else { |
42 | _result += sum; |
43 | } |
44 | _curtxid = _tx.getTransactionId(); |
45 | System.out.println("****** 2 _curtxid:" + _curtxid |
46 | + ",_tx.getTransactionId():" + _tx.getTransactionId()); |
47 | } |
48 | |
49 | System.out.println("total==========================:" + _result); |
50 | } |
51 | |
52 | @Override |
53 | public void declareOutputFields(OutputFieldsDeclarer declarer) { |
54 | |
55 | } |
56 | } |
结果:
TestTransBolt2 prepare TransactionId:5:3709460125605136723
TestTransBolt2 execute TransactionAttempt:5:3709460125605136723
TestTransBolt2 execute TransactionAttempt:5:3709460125605136723
TestTransBolt2 execute TransactionAttempt:5:3709460125605136723
finishBatch _curtxid:4,getTransactionId:5
****** 1 _curtxid:4,_tx.getTransactionId():5
****** 2 _curtxid:5,_tx.getTransactionId():5
total==========================:50
开始事务:[_index=50, _size=10]
TestEmitter emitBatch size:60,_dbMap size:50