org.apache.flume.channel.MemoryChannel类是Flume-NG的memory-channel。

private LinkedBlockingDeque<Event> queue;//mem-channel存放数据的地方

private Semaphore queueRemaining;//queue存量信号量

private Semaphore queueStored;//queue存量的信号量,保证channel里面有数据

private Semaphore bytesRemaining;//剩余字节信号量,以100字节为一个单位,也是动态调整的

Flume-NG的组件(source、sink、channel)总是先通过configure(Context context)方法,获取配置文件中的配置信息,在这配置了mem的最大容量capacity、事务的event最大容量transCapacity、缓存百分比byteCapacityBufferPercentage、最大内存所有事件允许总字节数      byteCapacity。还有信号量的初始化:

synchronized(queueLock) {//初始化mem

queue = new LinkedBlockingDeque<Event>(capacity);

queueRemaining = new Semaphore(capacity);

queueStored = new Semaphore(0);

}

以及:bytesRemaining = new Semaphore(byteCapacity);

queueStored这个比较特殊,初始为0表示开始时,queue没有数据,只要queue的大小有所调整时就需要调整这个信号量,增加就release,减少就tryAcquire。

当然在configure方法中可以看到如果配置文件修改后是如何动态修改的(flume默认每30s扫描加载一次配置文件)。

然后start()方法进行一些初始化操作。

resizeQueue(capacity)方法用来动态加载配置文件,调整mem容量的。

createTransaction()方法,返回MemoryTransaction实例。

estimateEventSize(Event event)方法,返回event.body的字节长度。

该类有一个内部类MemoryTransaction是mem-channel从source取(put)数据、给(take)sink的操作类。其初始化时会创建两个LinkedBlockingDeque,一个是takeList用于sink的take;一个是putList用于source的put,两个队列的容量都是事务的event最大容量transCapacity。两个队列是用于事务回滚rollback和提交commit的。

Source交给channel处理的一般是调用ChannelProcessor类的processEventBatch(List<Event> events)方法或者processEvent(Event event)方法;在sink端可以直接使用channel.take()方法获取其中的一条event数据。这俩方法在将event提交至channel时,都需要:

一、获取channel列表。List<Channel> requiredChannels = selector.getRequiredChannels(event);

二、通过channel获取Transaction。Transaction tx = reqChannel.getTransaction();

三、tx.begin();

四、reqChannel.put(event)(在sink中这是take(event)方法);

五、tx.commit();

六、tx.rollback();

七、tx.close()。

上面的三~七中的方法,最终调用的是MemoryTransaction的doBegin(未重写,默认空方法)、doPut、doCommit、doRollback、doClose(未重写,默认空方法)方法。

其中doPut方法,先计算event的大小可以占用bytesRemaining的多大空间,然后在有限的时间内等待获取写入空间,获取之后写入putList暂存。

doTake方法,先检查takeList的剩余容量;再检查是否有许可进行取操作(queueStored使得可以不用阻塞其它线程获取许可信息);然后同步的从queue中取一个event,再放入takeList,并返回此event。

doCommit方法,不管在sink还是source端都会调用。首先检查queue队列中是否有足够空间放得下从source过来的数据,依据就是queueRemaining是否有remainingChange = takeList.size-putList.size个许可。然后是将putList中的所有数据提交到内存队列queue之中,并将putList和takeList清空。清空表明:运行到这步说明takeList中的数据无需再保留,putList中的数据可以放入queue中。由于在doTake中从queue取数据,所以queueStored在减,但在doCommit中会把putList中的数据放入queue所以需要增加queueStored:queueStored.release(puts);bytesRemaining在doPut中获得了一些许可会减少,在doCommit中由于takeList会清空所有会增加bytesRemaining:bytesRemaining.release(takeByteCounter);而queueRemaining在doPut和doTake中并未进行操作,而且doCommit方法在sink和source中都会调用,故而在此方法中修改takeList和putList的差值即可:queueRemaining.release(remainingChange)(在此有个细节,在doCommit的开始remainingChange如果小于0,说明剩余空间不足以放入整个putList,要么超时报错退出;要么获得足够的许可,如果是后者的话就不需要再调整queueRemaining因为是在现在的基础之上减,如果remainingChange大于0,说明去除takeList大小后不仅足以放入整个putList,而且还有剩余,queueRemaining需要释放remainingChange)。其他就是修改计数器。

doRollback方法是在上面三、四、五出现异常的时候调用的,用于事务回滚。不管是在sink还是source中,都会调用。将takeList中的所有数据重新放回queue中:

while(!takeList.isEmpty()) {

queue.addFirst(takeList.removeLast());//回滚时,重新放回queue中。可能会重复(commit阶段出错,已经take的数据需要回滚,批量的情况)

}

然后清空putList:

putList.clear(); //这个方法可能发生在put中,也可能发生在take中,所以需要同步清空。可能会丢数据(还在put的阶段,没到commit阶段,出错会导致回滚,导致已经put还未放入queue中的数据会丢失)

由于putList清空了,所以bytesRemaining.release(putByteCounter);

由于takeList又返回给了queue所以queue的量增加了:queueStored.release(takes)。

  在分层的分布式flume中,一旦汇总节点中断,而采集节点使用mem,则采集会大量的丢失数据,因为channel会因为put而快速的填满,填满之后再调用put会迸发异常,致使出现异常引起事务回滚,回滚会直接清空putList,使数据丢失,只留下channel中的数据(这些数据是一开始放入进去的后来的会丢失)。putList.offer会因为填满数据返回false,add方法如果队列满了则会爆异常。

讲解并不一定完全正确,希望大伙踊跃交流。

flume-ng源码阅读memory-channel(原创)的更多相关文章

  1. Flume-NG源码阅读之SpoolDirectorySource(原创)

    org.apache.flume.source.SpoolDirectorySource是flume的一个常用的source,这个源支持从磁盘中某文件夹获取文件数据.不同于其他异步源,这个源能够避免重 ...

  2. Flume-NG源码阅读之Interceptor(原创)

    有的时候希望通过Flume将读取的文件再细分存储,比如讲source的数据按照业务类型分开存储,具体一点比如类似:将source中web.wap.media等的内容分开存储:比如丢弃或修改一些数据.这 ...

  3. Flume-NG源码阅读之SourceRunner,及选择器selector和拦截器interceptor的执行

    在AbstractConfigurationProvider类中loadSources方法会将所有的source进行封装成SourceRunner放到了Map<String, SourceRun ...

  4. Netty源码阅读之如何将TCP的读写操作和指定线程绑定

    原文链接:http://xueliang.org/article/detail/20200712234015993 前言 在Netty的线程模型中,对于一个TCP连接的读写操作,都是由一个单线程完成的 ...

  5. JDK1.8源码阅读系列之四:HashMap (原创)

    本篇随笔主要描述的是我阅读 HashMap 源码期间的对于 HashMap 的一些实现上的个人理解,用于个人备忘,有不对的地方,请指出- 接下来会从以下几个方面介绍 HashMap 源码相关知识: 1 ...

  6. [原创]chromium源码阅读-进程间通信IPC.消息的接收与应答

    chromium源码阅读-进程间通信IPC.消息的接收与应答   chromium源码阅读-进程间通信IPC.消息的接收与应答 介绍 chromium进程间通信在win32下是通过命名管道的方式实现的 ...

  7. Spark源码阅读之存储体系--存储体系概述与shuffle服务

    一.概述 根据<深入理解Spark:核心思想与源码分析>一书,结合最新的spark源代码master分支进行源码阅读,对新版本的代码加上自己的一些理解,如有错误,希望指出. 1.块管理器B ...

  8. TiDB 源码阅读系列文章(一)序

    原创: 申砾 PingCAP  2018-02-28 在 TiDB DevCon2018 上,我们对外宣布了 TiDB 源码阅读分享活动,承诺对外发布一系列文章以及视频帮助大家理解 TiDB 源码.大 ...

  9. 【Dubbo源码阅读系列】服务暴露之远程暴露

    引言 什么叫 远程暴露 ?试着想象着这么一种场景:假设我们新增了一台服务器 A,专门用于发送短信提示给指定用户.那么问题来了,我们的 Message 服务上线之后,应该如何告知调用方服务器,服务器 A ...

  10. Flume-NG源码阅读之AvroSink

    org.apache.flume.sink.AvroSink是用来通过网络来传输数据的,可以将event发送到RPC服务器(比如AvroSource),使用AvroSink和AvroSource可以组 ...

随机推荐

  1. Android 界面滑动卡顿分析与解决方案(入门)

    Android 界面滑动卡顿分析与解决方案(入门) 导致Android界面滑动卡顿主要有两个原因: 1.UI线程(main)有耗时操作 2.视图渲染时间过长,导致卡顿 目前只讲第1点,第二点相对比较复 ...

  2. cmake window下 sh.exe was found in your PATH, here

    在window下 mingw环境下 用 camke 编译Cpp程序 CMake Error at D:/Program Files/CMake/share/cmake-3.8/Modules/CMak ...

  3. 初探runtime

    1 简介 runtime,也叫它运行时系统.它是用c写的一套API,oc代码底层实现全都依赖它.我们说它是运行时,是相比编译,在程序编译完成之后,一些对象可通过runtime来干一些在编译时看似不可能 ...

  4. 修改hosts文件不起作用

    今天遇到个很奇怪的问题,在hosts文件里添加了一些域名指向后,发现根本没起作用,后来还发现个细节,就是hosts文件左下角有个小锁的标志,开始以为是杀毒软件之类的把他锁了.可是没找到在哪里有相关操作 ...

  5. SQL与Access使用查询结果集更新表

    SQL语法 update 表1 set 字段1 = bb.字段1 from 表1 as aa, (select 字段1,字段2 from 表) bb where aa.字段2 = bb.字段2 Acc ...

  6. sp_who 查看数据库连接数

    create table #TempTable(spid int,ecid int,statusvarchar(32),loginname varchar(32),hostname varchar(3 ...

  7. 洛谷 P2073 送花

    这题其实可以用vector水掉! 定义: 记住要用结构体(c为价格,x为美丽值)! 以c排序. struct Node { int x,c; bool operator < (const &am ...

  8. spring整合问题分析之-Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.

    1.异常分析 Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into ...

  9. Nginx+Springboot+Vue 前后端分离 解决跨域问题

    1:前端vue 写完 打包 npm run build prod 2: 后端api 写完打包 springboot mvn package -Dmaven.test.skip=true 3: ngin ...

  10. python基础教程_学习笔记19:标准库:一些最爱——集合、堆和双端队列

    版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/signjing/article/details/36201499 标准库:一些最爱 集合.堆和双端队 ...