环境
  虚拟机:VMware 10
  Linux版本:CentOS-6.5-x86_64
  客户端:Xshell4
  FTP:Xftp4
  jdk1.8
  storm-0.9
  apache-flume-1.6.0

一、storm三种事务
1、普通事务(常用)
2、Partitioned Transaction - 分区事务
3、Opaque Transaction - 不透明分区事务

二、普通事务设计
1、Design 1
强顺序流(强有序)
(1)引入事务(transaction)的概念,每个transaction(即每个tuple)关联一个transaction id。
(2)Transaction id从1开始,每个tuple会按照顺序+1。
(3)在处理tuple时,将处理成功的tuple结果以及transaction id同时写入数据库中进行存储。

缺点:
一次只能处理一个tuple,无法实现分布式计算

2、Design 2
强顺序的Batch流

(1)事务(transaction)以batch为单位,即把一批tuple称为一个batch,每次处理一个batch。
(2)每个batch(一批tuple)关联一个transaction id
(3)每个batch内部可以并行计算

缺点:
由于维持强有序,当一个batch处理时,其他batch处于闲置状态,效率低。

3、Design 3
将Topology拆分为两个阶段:
1、Processing phase
允许并行处理多个batch
2、Commit phase
保证batch的强有序,一次只能处理一个batch

其他:
Manages state - 状态管理
Storm通过Zookeeper存储所有transaction相关信息(包含了:当前transaction id 以及batch的元数据信息)

Coordinates the transactions - 协调事务
Storm会管理决定transaction应该处理什么阶段(processing、committing)

Fault detection - 故障检测
Storm内部通过Acker机制保障消息被正常处理(用户不需要手动去维护)

First class batch processing API
Storm提供batch bolt接口

三、案例

Topology

package com.sxt.storm.transactional;

import backtype.storm.Config;
import backtype.storm.LocalCluster;
import backtype.storm.StormSubmitter;
import backtype.storm.generated.AlreadyAliveException;
import backtype.storm.generated.InvalidTopologyException;
import backtype.storm.transactional.TransactionalTopologyBuilder; public class MyTopo { /**
* @param args
*/
public static void main(String[] args) {
//
TransactionalTopologyBuilder builder = new TransactionalTopologyBuilder("ttbId","spoutid",new MyTxSpout(),1);
builder.setBolt("bolt1", new MyTransactionBolt(),3).shuffleGrouping("spoutid");
builder.setBolt("committer", new MyCommitter(),1).shuffleGrouping("bolt1") ; Config conf = new Config() ;
conf.setDebug(false); if (args.length > 0) {
try {
StormSubmitter.submitTopology(args[0], conf, builder.buildTopology());
} catch (AlreadyAliveException e) {
e.printStackTrace();
} catch (InvalidTopologyException e) {
e.printStackTrace();
}
}else {
LocalCluster localCluster = new LocalCluster();
localCluster.submitTopology("mytopology", conf, builder.buildTopology());
}
}
}

Spout:

package com.sxt.storm.transactional;

import java.util.HashMap;
import java.util.Map;
import java.util.Random; import backtype.storm.task.TopologyContext;
import backtype.storm.topology.OutputFieldsDeclarer;
import backtype.storm.transactional.ITransactionalSpout;
import backtype.storm.tuple.Fields; public class MyTxSpout implements ITransactionalSpout<MyMeta> { /**
* 数据源
*/
Map<Long, String> dbMap = null; public MyTxSpout() {
Random random = new Random();
dbMap = new HashMap<Long, String>();
String[] hosts = { "www.taobao.com" };
String[] session_id = {
"ABYH6Y4V4SCVXTG6DPB4VH9U123",
"XXYH6YCGFJYERTT834R52FDXV9U34",
"BBYH61456FGHHJ7JL89RG5VV9UYU7",
"CYYH6Y2345GHI899OFG4V9U567",
"VVVYH6Y4V4SFXZ56JIPDPB4V678"
};
String[] time = {
"2017-02-21 08:40:50",
"2017-02-21 08:40:51",
"2017-02-21 08:40:52",
"2017-02-21 08:40:53",
"2017-02-21 09:40:49",
"2017-02-21 10:40:49",
"2017-02-21 11:40:49",
"2017-02-21 12:40:49"
}; for (long i = 0; i < 100; i++) {
dbMap.put(i, hosts[0] + "\t" + session_id[random.nextInt(5)] + "\t" + time[random.nextInt(8)]);
}
} private static final long serialVersionUID = 1L; @Override
public backtype.storm.transactional.ITransactionalSpout.Coordinator<MyMeta> getCoordinator(Map conf,
TopologyContext context) {
return new MyCoordinator();
} @Override
public backtype.storm.transactional.ITransactionalSpout.Emitter<MyMeta> getEmitter(Map conf,
TopologyContext context) {
return new MyEmitter(dbMap);
} @Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("tx", "log"));
} @Override
public Map<String, Object> getComponentConfiguration() {
return null;
} }

Bolt:

package com.sxt.storm.transactional;

import java.util.Map;

import backtype.storm.coordination.BatchOutputCollector;
import backtype.storm.task.TopologyContext;
import backtype.storm.topology.OutputFieldsDeclarer;
import backtype.storm.topology.base.BaseTransactionalBolt;
import backtype.storm.transactional.TransactionAttempt;
import backtype.storm.tuple.Fields;
import backtype.storm.tuple.Tuple;
import backtype.storm.tuple.Values; public class MyTransactionBolt extends BaseTransactionalBolt { /**
*
*/
private static final long serialVersionUID = 1L; Integer count = 0;
BatchOutputCollector collector;
TransactionAttempt tx ; @Override
public void prepare(Map conf, TopologyContext context,
BatchOutputCollector collector, TransactionAttempt id) {
this.collector = collector;
System.err.println("MyTransactionBolt prepare txid:"+id.getTransactionId() +"; attemptid: "+id.getAttemptId());
} /**
* 处理batch中每一个tuple
*/
@Override
public void execute(Tuple tuple) { tx = (TransactionAttempt) tuple.getValue(0);
System.err.println("MyTransactionBolt TransactionAttempt txid:"+tx.getTransactionId() +"; attemptid:"+tx.getAttemptId());
String log = tuple.getString(1);
if (log != null && log.length()>0) {
count ++ ;
}
} /**
* 同一个batch处理完成后,会调用一次finishBatch方法
*/
@Override
public void finishBatch() {
System.err.println("finishBatch: "+count );
collector.emit(new Values(tx,count));
} @Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
declarer.declare(new Fields("tx","count"));
} }
package com.sxt.storm.transactional;

import java.math.BigInteger;
import java.util.HashMap;
import java.util.Map; import backtype.storm.coordination.BatchOutputCollector;
import backtype.storm.task.TopologyContext;
import backtype.storm.topology.OutputFieldsDeclarer;
import backtype.storm.topology.base.BaseTransactionalBolt;
import backtype.storm.transactional.ICommitter;
import backtype.storm.transactional.TransactionAttempt;
import backtype.storm.tuple.Tuple; public class MyCommitter extends BaseTransactionalBolt implements ICommitter { /**
*
*/
private static final long serialVersionUID = 1L; public static final String GLOBAL_KEY = "GLOBAL_KEY";
public static Map<String, DbValue> dbMap = new HashMap<String, DbValue>();
int sum = 0;
TransactionAttempt id;
BatchOutputCollector collector; @Override
public void execute(Tuple tuple) {
sum += tuple.getInteger(1);
} @Override
public void finishBatch() { DbValue value = dbMap.get(GLOBAL_KEY);
DbValue newValue;
//
if (value == null || !value.txid.equals(id.getTransactionId())) {
// 更新数据库
newValue = new DbValue();
newValue.txid = id.getTransactionId();
if (value == null) {
newValue.count = sum;
} else {
newValue.count = value.count + sum;
}
dbMap.put(GLOBAL_KEY, newValue);
} else {
newValue = value;
}
System.out.println("total==========================:" + dbMap.get(GLOBAL_KEY).count);
// collector.emit(tuple)
} @Override
public void prepare(Map conf, TopologyContext context, BatchOutputCollector collector, TransactionAttempt id) {
this.id = id;
this.collector = collector;
} @Override
public void declareOutputFields(OutputFieldsDeclarer declarer) { } public static class DbValue {
BigInteger txid;
int count = 0;
} }
package com.sxt.storm.transactional;

import java.math.BigInteger;

import backtype.storm.transactional.ITransactionalSpout;
import backtype.storm.utils.Utils; public class MyCoordinator implements ITransactionalSpout.Coordinator<MyMeta>{ // batch中消息条数
public static int BATCH_NUM = 10 ; /**
* 在initializeTransaction前执行
* 确认数据源是否已经准备就绪,可以读取数据
* 返回值 true、false
*/
@Override
public boolean isReady() {
Utils.sleep(2000);
return true;
} /**
* txid:事务序列号
* prevMetadata:之前事务的元数据(如果第一次启动事务,则为null)
* 返回值:当前事务的元数据
*/
@Override
public MyMeta initializeTransaction(BigInteger txid, MyMeta prevMetadata) {
long beginPoint = 0;
if (prevMetadata == null) {
beginPoint = 0 ;
}else {
beginPoint = prevMetadata.getBeginPoint() + prevMetadata.getNum() ;
} MyMeta meta = new MyMeta() ;
meta.setBeginPoint(beginPoint);
meta.setNum(BATCH_NUM);
System.err.println("启动一个事务:"+meta.toString());
return meta;
} @Override
public void close() { }
}
package com.sxt.storm.transactional;

import java.io.Serializable;

public class MyMeta implements Serializable{

    /**
*
*/
private static final long serialVersionUID = 1L; private long beginPoint ;//事务开始位置 private int num ;//batch 的tuple个数 @Override
public String toString() {
return getBeginPoint()+"----"+getNum();
} public long getBeginPoint() {
return beginPoint;
} public void setBeginPoint(long beginPoint) {
this.beginPoint = beginPoint;
} public int getNum() {
return num;
} public void setNum(int num) {
this.num = num;
} }
package com.sxt.storm.transactional;

import java.math.BigInteger;
import java.util.Map; import backtype.storm.coordination.BatchOutputCollector;
import backtype.storm.transactional.ITransactionalSpout;
import backtype.storm.transactional.TransactionAttempt;
import backtype.storm.tuple.Values; public class MyEmitter implements ITransactionalSpout.Emitter<MyMeta>{ Map<Long, String> dbMap = null;
public MyEmitter(Map<Long, String> dbMap) {
this.dbMap = dbMap;
} @Override
public void cleanupBefore(BigInteger txid) { } @Override
public void close() { } /**
* 发送tuple的batch
*/
@Override
public void emitBatch(TransactionAttempt tx, MyMeta coordinatorMeta,
BatchOutputCollector collector) { long beginPoint = coordinatorMeta.getBeginPoint() ;
int num = coordinatorMeta.getNum() ; for (long i = beginPoint; i < num+beginPoint; i++) {
if (dbMap.get(i)==null) {
continue;
}
/**
* 必须以TransactionAttempt第一位发送
* _txid: transaction id 每组batch中的tuple必须为同一id,不论replay多少次
* _attemptId
*/
collector.emit(new Values(tx,dbMap.get(i)));
}
} }

大数据处理框架之Strom:事务的更多相关文章

  1. 大数据处理框架之Strom: Storm----helloword

    大数据处理框架之Strom: Storm----helloword Storm按照设计好的拓扑流程运转,所以写代码之前要先设计好拓扑图.这里写一个简单的拓扑: 第一步:创建一个拓扑类含有main方法的 ...

  2. 大数据处理框架之Strom:认识storm

    Storm是分布式实时计算系统,用于数据的实时分析.持续计算,分布式RPC等. (备注:5种常见的大数据处理框架:· 仅批处理框架:Apache Hadoop:· 仅流处理框架:Apache Stor ...

  3. 大数据处理框架之Strom:Flume+Kafka+Storm整合

    环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 jdk1.8 storm-0.9 apache-flume-1.6.0 ...

  4. 大数据处理框架之Strom: Storm拓扑的并行机制和通信机制

    一.并行机制 Storm的并行度 ,通过提高并行度可以提高storm程序的计算能力. 1.组件关系:Supervisor node物理节点,可以运行1到多个worker,不能超过supervisor. ...

  5. 大数据处理框架之Strom:DRPC

    环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 jdk1.8 storm-0.9 一.DRPC DRPC:Distri ...

  6. 大数据处理框架之Strom:Storm集群环境搭建

    搭建环境 Red Hat Enterprise Linux Server release 7.3 (Maipo)      zookeeper-3.4.11 jdk1.7.0_80      Pyth ...

  7. 大数据处理框架之Strom:redis storm 整合

    storm 引入redis ,主要是使用redis缓存库暂存storm的计算结果,然后redis供其他应用调用取出数据. 新建maven工程 pom.xml <project xmlns=&qu ...

  8. 大数据处理框架之Strom:kafka storm 整合

    storm 使用kafka做数据源,还可以使用文件.redis.jdbc.hive.HDFS.hbase.netty做数据源. 新建一个maven 工程: pom.xml <project xm ...

  9. 大数据处理框架之Strom:容错机制

    1.集群节点宕机Nimbus服务器 单点故障,大部分时间是闲置的,在supervisor挂掉时会影响,所以宕机影响不大,重启即可非Nimbus服务器 故障时,该节点上所有Task任务都会超时,Nimb ...

随机推荐

  1. 虚拟机在 OpenStack 里没有共享存储条件下的在线迁移

    虚拟机在 OpenStack 里没有共享存储条件下的在线迁移 本文尝试回答与 Live migration 相关的几个问题:Live migration 是什么?为什么要做 Live migratio ...

  2. cs231n线性分类器作业 svm代码 softmax

    CS231n之线性分类器 斯坦福CS231n项目实战(二):线性支持向量机SVM CS231n 2016 通关 第三章-SVM与Softmax cs231n:assignment1——Q3: Impl ...

  3. javascipt——原型

    1.原型存在的意义 JS不是面向对象的语言,没有类的概念,但是提供了构造器函数,其也可以创建一个对象.构造器函数如下: function people(name, age, sex) { this.n ...

  4. JanusGraph : 图和图数据库的简介

    JanusGraph:图数据库系统简介 图(graph)是<数据结构>课中第一次接触到的一个概念,它是一种用来描述现实世界中个体和个体之间网络关系的数据结构. 为了在计算机中存储图,< ...

  5. 201671010140. 2016-2017-2 《Java程序设计》java学习第一周

       java学习第一周        本周是新学期的开端,也是新的学习进程的开端,第一次接触java这门课程,首先书本的厚度就给我一种无形的压力,这注定了,这门课程不会是轻松的,同时一种全新的学习方 ...

  6. Vue基础以及指令, Vue组件

    Vue基础篇一 Vue指令 Vue的指令directive很像我们所说的自定义属性,指令时Vue模板中最常用的功能,它带有v-前缀,功能是当表达式改变的时候,相应的行为作用在DOM上. <div ...

  7. 【总结整理】关于GrowingIO、友盟、google analysis等数据分析

    作者:纯银V链接:https://www.jianshu.com/p/394ec6c96c98來源:简书简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处. 埋点主要分为四步:第一步是 ...

  8. SaeMysql操作示例

    新浪sae的官方说明文档:http://apidoc.sinaapp.com/sae/SaeMysql.html Class SaeMysql 具体实现:http://apidoc.sinaapp.c ...

  9. 调用req.getParameter方法出现中文乱码(全是问号???)

    在java开发中,如果编码配置不统一,很容易出现中文乱码的情况,这里就记录下自己遇到的调用req.getParameter方法出现中文乱码,并解决这一情况的方法 注意修改以下几个地方 1.jsp页面中 ...

  10. Azure 执行模型

    最后更新时间(英文版):01/20/2015 最后更新时间(中文版):04/11/2015 Azure 提供了用于运行应用程序的不同执行模型.每种模型提供一组不同服务,而你选择哪种模型完全取决于你要做 ...