Flume传输数据事务分析

本文基于ThriftSource,MemoryChannel,HdfsSink三个组件,对Flume传输数据的事务进行分析。假设使用的是其它组件。Flume事务详细的处理方式将会不同。普通情况下。用MemoryChannel就好了,我们公司用的就是这个。FileChannel速度慢,尽管提供日志级别的数据恢复,可是普通情况下,不断电MemoryChannel是不会丢数据的。

Flume提供事物操作。保证用户的数据的可靠性,主要体如今:

  • 数据在传输到下个节点时(一般是批量数据),假设接收节点出现异常,比方网络异常。则回滚这一批数据。

    因此有可能导致数据重发

  • 同个节点内,Source写入数据到Channel,数据在一个批次内的数据出现异常,则不写入到Channel。

    已接收到的部分数据直接抛弃,靠上一个节点重发数据。

编程模型

Flume在对Channel进行Put和Take操作的时候。必需要用事物包住,比方:

Channel ch = new MemoryChannel();
Transaction txn = ch.getTransaction();
//事物開始
txn.begin();
try { Event eventToStage = EventBuilder.withBody("Hello Flume!",
Charset.forName("UTF-8"));
//往暂时缓冲区Put数据
ch.put(eventToStage);
//或者ch.take() //将这些数据提交到channel中
txn.commit();
} catch (Throwable t) {
txn.rollback(); if (t instanceof Error) {
throw (Error)t;
}
} finally {
txn.close();
}

Put事务流程

Put事务能够分为下面阶段:

  • doPut:将批数据先写入暂时缓冲区putList
  • doCommit:检查channel内存队列是否足够合并。
  • doRollback:channel内存队列空间不足,抛弃数据

我们从Source数据接收到写入Channel这个过程对Put事物进行分析。

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd3NzY3kyMDA0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

ThriftSource会spawn多个Worker线程(ThriftSourceHandler)去处理数据,Worker处理数据的接口。我们仅仅看batch批量处理这个接口:

    @Override
public Status appendBatch(List<ThriftFlumeEvent> events) throws TException { List<Event> flumeEvents = Lists.newArrayList();
for(ThriftFlumeEvent event : events) {
flumeEvents.add(EventBuilder.withBody(event.getBody(),
event.getHeaders()));
} //ChannelProcessor,在Source初始化的时候传进来.将数据写入相应的Channel
getChannelProcessor().processEventBatch(flumeEvents);
... return Status.OK;
}

事务逻辑都在processEventBatch这种方法里:

public void processEventBatch(List<Event> events) {
...
//预处理每行数据,有人用来做ETL嘛
events = interceptorChain.intercept(events);
...
//分类数据,划分不同的channel集合相应的数据 // Process required channels
Transaction tx = reqChannel.getTransaction();
...
//事务開始,tx即MemoryTransaction类实例
tx.begin();
List<Event> batch = reqChannelQueue.get(reqChannel);
for (Event event : batch) {
// 这个put操作实际调用的是transaction.doPut
reqChannel.put(event);
}
//提交,将数据写入Channel的队列中
tx.commit();
} catch (Throwable t) {
//回滚
tx.rollback();
...
}
}
...
}

每一个Worker线程都拥有一个Transaction实例,保存在Channel(BasicChannelSemantics)里的ThreadLocal变量currentTransaction.

那么。事务究竟做了什么?

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd3NzY3kyMDA0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

实际上。Transaction实例包括两个双向堵塞队列LinkedBlockingDeque(感觉不是必需用双向队列,每一个线程写自己的putList,又不是多个线程?),分别为:

  • putList
  • takeList

对于Put事物操作,当然是仅仅用到putList了。

putList就是一个暂时的缓冲区。数据会先put到putList,最后由commit方法会检查channel是否有足够的缓冲区,有则合并到channel的队列。

channel.put -> transaction.doPut:

    protected void doPut(Event event) throws InterruptedException {
//计算数据字节大小
int eventByteSize = (int)Math.ceil(estimateEventSize(event)/byteCapacitySlotSize);
//写入暂时缓冲区putList
if (!putList.offer(event)) {
throw new ChannelException(
"Put queue for MemoryTransaction of capacity " +
putList.size() + " full, consider committing more frequently, " +
"increasing capacity or increasing thread count");
}
putByteCounter += eventByteSize;
}

transaction.commit:

@Override
protected void doCommit() throws InterruptedException {
//检查channel的队列剩余大小是否足够
... int puts = putList.size();
...
synchronized(queueLock) {
if(puts > 0 ) {
while(!putList.isEmpty()) {
//写入到channel的队列
if(!queue.offer(putList.removeFirst())) {
throw new RuntimeException("Queue add failed, this shouldn't be able to happen");
}
}
}
//清除暂时队列
putList.clear();
...
}
...
}

假设在事务期间出现异常,比方channel剩余空间不足,则rollback:

@Override
protected void doRollback() {
...
//抛弃数据。没合并到channel的内存队列
putList.clear();
...
}

Take事务

Take事务分为下面阶段:

  • doTake:先将数据取到暂时缓冲区takeList
  • 将数据发送到下一个节点
  • doCommit:假设数据所有发送成功。则清除暂时缓冲区takeList
  • doRollback:数据发送过程中假设出现异常,rollback将暂时缓冲区takeList中的数据归还给channel内存队列。

Sink事实上是由SinkRunner线程调用Sink.process方法来了处理数据的。我们从HdfsEventSink的process方法说起,Sink类都有个process方法。用来处理数据传输的逻辑。:

public Status process() throws EventDeliveryException {
...
Transaction transaction = channel.getTransaction();
...
//事务開始
transaction.begin();
...
for (txnEventCount = 0; txnEventCount < batchSize; txnEventCount++) {
//take数据到暂时缓冲区,实际调用的是transaction.doTake
Event event = channel.take();
if (event == null) {
break;
}
...
//写数据到HDFS
bucketWriter.append(event);
...
// flush all pending buckets before committing the transaction
for (BucketWriter bucketWriter : writers) {
bucketWriter.flush();
}
//commit
transaction.commit();
...
} catch (IOException eIO) {
transaction.rollback();
...
} finally {
transaction.close();
}
}

大致流程图:

接着看看channel.take。作用是将数据放到暂时缓冲区,实际调用的是transaction.doTake:

protected Event doTake() throws InterruptedException {
...
//从channel内存队列取数据
synchronized(queueLock) {
event = queue.poll();
}
...
//将数据放到暂时缓冲区
takeList.put(event);
...
return event;
}

接着,HDFS写线程bucketWriter将take到的数据写到HDFS,假设批数据都写完了。则要commit了:

protected void doCommit() throws InterruptedException {
...
takeList.clear();
...
}

非常easy。事实上就是清空takeList而已。

假设bucketWriter在写数据到HDFS的时候出现异常。则要rollback:

protected void doRollback() {
int takes = takeList.size();
//检查内存队列空间大小,是否足够takeList写回去
synchronized(queueLock) {
Preconditions.checkState(queue.remainingCapacity() >= takeList.size(), "Not enough space in memory channel " +
"queue to rollback takes. This should never happen, please report");
while(!takeList.isEmpty()) {
queue.addFirst(takeList.removeLast());
}
...
}
...
}

Flume传输数据事务分析的更多相关文章

  1. Flume数据传输事务分析[转]

    本文基于ThriftSource,MemoryChannel,HdfsSink三个组件,对Flume数据传输的事务进行分析,如果使用的是其他组件,Flume事务具体的处理方式将会不同.一般情况下,用M ...

  2. Flume使用小结

    本文介绍初次使用Flume传输数据到MongoDB的过程,内容涉及环境部署和注意事项. 1 环境搭建 需要jdk.flume-ng.mongodb java driver.flume-ng-mongo ...

  3. Flume简介及安装

    Hadoop业务的大致开发流程以及Flume在业务中的地位: 从Hadoop的业务开发流程图中可以看出,在大数据的业务处理过程中,对于数据的采集是十分重要的一步,也是不可避免的一步,从而引出我们本文的 ...

  4. 海量日志采集系统flume架构与原理

    1.Flume概念 flume是分布式日志收集系统,将各个服务器的数据收集起来并发送到指定地方. Flume是Cloudera提供的一个高可用.高可靠.分布式的海量日志采集.聚合和传输的系统.Flum ...

  5. Flume - Kafka日志平台整合

    1. Flume介绍 Flume是Cloudera提供的一个高可用的,高可靠的,分布式的海量日志采集.聚合和传输的系统,Flume支持在日志系统中定制各类数据发送方,用于收集数据:同时,Flume提供 ...

  6. 使用Flume消费Kafka数据到HDFS

    1.概述 对于数据的转发,Kafka是一个不错的选择.Kafka能够装载数据到消息队列,然后等待其他业务场景去消费这些数据,Kafka的应用接口API非常的丰富,支持各种存储介质,例如HDFS.HBa ...

  7. 利用Flume将MySQL表数据准实时抽取到HDFS

    转自:http://blog.csdn.net/wzy0623/article/details/73650053 一.为什么要用到Flume 在以前搭建HAWQ数据仓库实验环境时,我使用Sqoop抽取 ...

  8. Flume架构以及应用介绍[转]

    在具体介绍本文内容之前,先给大家看一下Hadoop业务的整体开发流程: 从Hadoop的业务开发流程图中可以看出,在大数据的业务处理过程中,对于数据的采集是十分重要的一步,也是不可避免的一步,从而引出 ...

  9. Flume架构以及应用介绍

    在具体介绍本文内容之前,先给大家看一下Hadoop业务的整体开发流程:  从Hadoop的业务开发流程图中可以看出,在大数据的业务处理过程中,对于数据的采集是十分重要的一步,也是不可避免的一步,从而引 ...

随机推荐

  1. poj1459 Power Network --- 最大流 EK/dinic

    求从电站->调度站->消费者的最大流,给出一些边上的容量.和电站和消费者能够输入和输出的最大量. 加入一个超级源点和汇点,建边跑模板就能够了. 两个模板逗能够. #include < ...

  2. linux 压缩和解压文件

    一.压缩:20120715文件下面所有的文件 如下: tar -zcvf 20120715.tar.gz  20120715* 二.解压20120715.tar.gz压缩包 如下: tar -xzvf ...

  3. node-inspector使用

    nodejs.gulp调试工具node-inspector使用 俗话说欲善其功,必先利其器. 作为目前新型的Web Server开发栈倍受开发者关注的Nodejs来说,调试技术是学习开发的基石,所以对 ...

  4. python学习——截图工具编写

    学习一门语言最好的方法便是实践,想要拿Python写一个截图工具,网上一搜资料果然已经很多,前辈们都已经做的很到位了.现在就一步步来学习一下: 首先学习截图整个桌面的方法,可以使用Python中的PI ...

  5. 【Demo 0008】Java基础-抽象类

    本掌学习要点:       1.  了解抽象类的定义及使用场景:       2.  掌握final修饰的类.方法以及变量作用及用法:       3.  掌握abstract 修饰的类及方法作用及用 ...

  6. [置顶] JSP分页,使用Hibernate+mysql

    此代码为博主参考巴巴运动网源码所得,大部分一样,略有修改,在这里分享给大家,也方便自己以后写代码直接copy,看网上很多分页代码JSP里是用JAVA代码,博主原来也是这样,看到源码了解了JSTL,建议 ...

  7. hadoop深入研究:(五)——Archives

    转载请注明来源地址:http://blog.csdn.net/lastsweetop/article/details/9123155 简介 我们在hadoop深入研究:(一)——hdfs介绍里已讲过, ...

  8. Mac OS设置rootpassword

    不知怎么忘记mac os系统的rootpassword了 方法一: 首先,启动机器,启动时按住Apple和S键,以单用户模式(single user mode)进入系统.输入:mount -uw / ...

  9. 关于Delphi中的字符串的浅析(瓢虫大作,里面有内存错误的举例)

    关于Delphi中的字符串的浅析 只是浅浅的解析下,让大家可以快速的理解字符串. 其中的所有代码均在Delphi7下测试通过. Delphi 4,5,6,7中有字符串类型包括了: 短字符串(Short ...

  10. uva 10131 Is Bigger Smarter?(DAG最长路)

    题目连接:10131 - Is Bigger Smarter? 题目大意:给出n只大象的属性, 包括重量w, 智商s, 现在要求找到一个连续的序列, 要求每只大象的重量比前一只的大, 智商却要小, 输 ...