Flume - MemoryChannel源码解析

flume中的FileChannel的优化 经过对Flume FileChannel相关源码的分析,导致FileChannel吞吐率下降的主要原因集中于事务的提交过程——commit 立即下载

MemoryChannel的简易类结构:

 

内部类MemoryTransaction的简易类结构:

一,configure(Context context)

    1,capacity:MemroyChannel的容量,默认是100。

    2,transCapacity:每个事务最大的容量,也就是每个事务能够获取的最大Event数量。默认也是100。

    3,byteCapacityBufferPercentage:定义Channle中Event所占的百分比,需要考虑在Header中的数据。

    4,byteCapacity:byteCapacity等于设置的byteCapacity值或堆的80%乘以1减去byteCapacityBufferPercentage的百分比,然后除以100。源码如下:

 

    try {
      byteCapacity = (int)((context.getLong("byteCapacity", defaultByteCapacity).longValue() * (1 - byteCapacityBufferPercentage * .01 )) /byteCapacitySlotSize);
      if (byteCapacity < 1) {
        byteCapacity = Integer.MAX_VALUE;
      }
    } catch(NumberFormatException e) {
      byteCapacity = (int)((defaultByteCapacity * (1 - byteCapacityBufferPercentage * .01 )) /byteCapacitySlotSize);
    }

 

    5,keep-alive:增加和删除一个Event的超时时间(单位:秒)

    6,初始化LinkedBlockingDeque对象,大小为capacity。以及各种信号量对象。

    7,最后初始化计数器。

 

二,信号量

MemoryChannel有三个信号量用来控制事务,防止容量越界。这三个信号量分别是:

queueRemaining : 表示空闲的容量大小。

queueStored : 表示已经存储的容量大小。

bytesRemaining : 表示可以使用的内存大小。该大小就是计算后的byteCapacity值。

 

三,MemoryTransaction

MemoryTransaction用来接收数据和事务控制。该类继承BasicTransactionSemantics类,BasicTransactionSemantics类有三个主要的方法:

         1, put(Event event) 往Channel放入数据。
         2, take() 从Channel获取数据。
         3, begin() 开始事务
         3,commit() 提交事务
         4,rollback() 回滚事务

无论是Sink,还是Source都会调用getTransaction()方法,获取该事务实例。下面我们看看MemoryTransaction的初始化过程:

 

    public MemoryTransaction(int transCapacity, ChannelCounter counter) {
      putList = new LinkedBlockingDeque<Event>(transCapacity);
      takeList = new LinkedBlockingDeque<Event>(transCapacity);

      channelCounter = counter;
    }


由上可见,MemoryTransaction维护了两个队列,一个用于Source的put,一个用于Sink的take,容量大小为事务的容量(即:transCapacity)。

 

 

 

最后让我们了解一下MemoryTransaction类中,几个比较重要方法:

1,doPut(Event event)方法是往Channel插入数据

    protected void doPut(Event event) throws InterruptedException {
      channelCounter.incrementEventPutAttemptCount();<pre name="code" class="java">      //estimateEventSize方法返回Event的大小(只是Body的大小,header没有计算在内),并且除以byteCapacitySlotSize后向上取整计算
      int eventByteSize = (int)Math.ceil(estimateEventSize(event)/byteCapacitySlotSize);
      //添加到队列的尾部,如果超过了容量的限制,则添加失败,抛出ChannelException异常。
      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");
      }
      //记录Event的byte值
      putByteCounter += eventByteSize;
    }

 


 

 

2,doTake() 方法是从Channel中获取数据。

 

 

protected Event doTake() throws InterruptedException {
      channelCounter.incrementEventTakeAttemptCount();
      //takeList队列的剩余容量,如果为0,则抛异常
      if(takeList.remainingCapacity() == 0) {
        throw new ChannelException("Take list for MemoryTransaction, capacity " +
            takeList.size() + " full, consider committing more frequently, " +
            "increasing capacity, or increasing thread count");
      }
      //尝试获取许可,如果可以获取到许可的话,证明queue队列有空间,否则返回null
      if(!queueStored.tryAcquire(keepAlive, TimeUnit.SECONDS)) {
        return null;
      }
      Event event;
      synchronized(queueLock) {
        //从queue取出一个Event
        event = queue.poll();
      }
      Preconditions.checkNotNull(event, "Queue.poll returned NULL despite semaphore " +
          "signalling existence of entry");
      //加入到takeList队列中
      takeList.put(event);
      //更新takeByteCounter大小
      int eventByteSize = (int)Math.ceil(estimateEventSize(event)/byteCapacitySlotSize);
      takeByteCounter += eventByteSize;

      return event;
    }

 

3,doCommit() 提交

 

    protected void doCommit() throws InterruptedException {
      int remainingChange = takeList.size() - putList.size();
      //如果takeList更小,说明该MemoryChannel放的数据比取的数据要多,所以需要判断该MemoryChannel是否有空间来放
      if(remainingChange < 0) {
        //利用该信号量判断是否有剩余空间
        if(!bytesRemaining.tryAcquire(putByteCounter, keepAlive,
          TimeUnit.SECONDS)) {
          throw new ChannelException("Cannot commit transaction. Byte capacity " +
            "allocated to store event body " + byteCapacity * byteCapacitySlotSize +
            "reached. Please increase heap space/byte capacity allocated to " +
            "the channel as the sinks may not be keeping up with the sources");
        }
        //检查queue队列是否有足够的空间。
        if(!queueRemaining.tryAcquire(-remainingChange, keepAlive, TimeUnit.SECONDS)) {
          bytesRemaining.release(putByteCounter);
          throw new ChannelFullException("Space for commit to queue couldn't be acquired." +
              " Sinks are likely not keeping up with sources, or the buffer size is too tight");
        }
      }
      int puts = putList.size();
      int takes = takeList.size();
      //如果上述两个信号量都有空间的话,那么把putList中的Event放到该MemoryChannel中的queue中。
      synchronized(queueLock) {
        if(puts > 0 ) {
          while(!putList.isEmpty()) {
            if(!queue.offer(putList.removeFirst())) {
              throw new RuntimeException("Queue add failed, this shouldn't be able to happen");
            }
          }
        }
        //最后情况putList和takeList
        putList.clear();
        takeList.clear();
      }
      //更新queue大小控制的信号量bytesRemaining
      bytesRemaining.release(takeByteCounter);
      takeByteCounter = 0;
      putByteCounter = 0;

      queueStored.release(puts);
      //takeList比putList大,说明该MemoryChannel中queue的数量应该是减少了,所以把(takeList-putList)的差值加到信号量queueRemaining
      if(remainingChange > 0) {
        queueRemaining.release(remainingChange);
      }
      //更新计数器
      if (puts > 0) {
        channelCounter.addToEventPutSuccessCount(puts);
      }
      if (takes > 0) {
        channelCounter.addToEventTakeSuccessCount(takes);
      }

      channelCounter.setChannelSize(queue.size());
    }


4,doRollback() 回滚

 

 

    protected void doRollback() {
      //获取takeList的大小,然后bytesRemaining中释放
      int takes = takeList.size();
      //将takeList中的Event重新放回到queue队列中。
      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());
        }
        //最后清空putList
        putList.clear();
      }
      //清空了putList,所以需要把putList占用的空间添加到bytesRemaining中
      bytesRemaining.release(putByteCounter);
      putByteCounter = 0;
      takeByteCounter = 0;

      queueStored.release(takes);
      channelCounter.setChannelSize(queue.size());
    }

 

MemoryChannel的数据流向:

source -> putList -> queue -> takeList -> sink

 

MemoryChannel还是比较简单的,主要是通过MemoryTransaction中的putList、takeList与MemoryChannel中的queue进行数据流转和事务控制,MemoryChannel受内存空间的影响,如果数据产生的过快,同时获取信号量超时容易造成数据的丢失。而且Flume进程挂掉,数据也会丢失。

Java8动态生成SFunction:基于字段名的Lambda表达式实践 本文深入探讨了在Java8中如何基于字段名动态生成SFunction,以解决MyBatis Plus的LambdaQueryWrapper在动态查询场景下的局限性。通过核心原理LambdaMetafactory的解析和手把手的代码实现,展示了如何将字符串字段名转换为类型安全的Lambda表达式,从而实现真正动态、类型安全的查询条件构建与通用数据处理,显著提升代码的灵活性与安全性。 阅读详情

相关推荐

从CAD到Web:高效转换STEP/IGES模型为GLB格式的实践指南

本文详细介绍了如何将工业设计中的STEP/IGES模型高效转换为Web友好的GLB格式。通过PythonOCC和gltf-pipeline等工具链,实现从CAD到Web的无缝转换,大幅提升模型加载速度和展示效果。文章包含实战案例、优化技巧和常见问题解决方案,帮助开发者快速掌握3D模型转换技术。

weixin_29072299的博客 507

Flume监控【转】

转自https://kiswo.com/article/1023,感谢原作者 异常排查 当 QPS 压到3w时,Flume出现一下错误信息。 09 Jun 2017 12:06:30,703 ERROR [pool-3-thread-1] (org.apache.flume.source.ExecSource$ExecRunnable.run:352) - Failed while ru...

fuckaholic的博客 5816

MSPM0G3507电赛控制板设计:电机驱动与多传感器融合

微控制器是嵌入式控制系统的核心处理单元,其性能与外设集成度直接决定实时控制能力。基于Arm Cortex-M0+内核的MCU凭借低功耗、高性价比和丰富模拟资源,成为大学生电子设计竞赛等工程实践场景的主流选择。本文围绕MSPM0G3507展开,深入解析双路电机驱动(TB6612FNG)、多源传感采集(MPU6050+ADC电压监测)及抗干扰硬件架构等关键技术,强调电源隔离、信号完整性与鲁棒性设计对72小时封闭竞赛环境的关键支撑作用。典型应用涵盖巡线小车运动控制、姿态解算与蓝牙/Zigbee协同通信,为控制类赛

weixin_42588672的博客 541

源码趣事-flume-队列动态扩容及容量使用

1. 前言 最近在做数据平台 整个接入系统的重构,重点看了flume的高可高机制,在看memoryChannel源码的时候发现几个有意思的实现,刚好最近得空,写出来,...

jayjwes190的专栏 677

SAP ABAP BADI_FINS_ACDOC_POSTING_EVENTS 深度应用:KO88工单结算的凭证字段定制与财务数据增强

本文深入探讨了SAP ABAP中BADI_FINS_ACDOC_POSTING_EVENTS在KO88工单结算中的应用,详细解析了如何通过BADI实现财务凭证字段的定制与数据增强。文章提供了从结构扩展到BADI方法实现的完整步骤,包括性能优化建议和实际应用中的测试验证流程,帮助开发人员高效解决企业个性化财务需求。

weixin_26869081的博客 389

matlab电子科技大学数学实验期末模拟35道(1)

【代码】matlab电子科技大学数学实验期末模拟35道。

c_wrj_的博客 2044

flume MemoryChannel分析

前边介绍了flume的基本概念和Source部分,接下来看看flume中的第二大组件Channel中的MemoryChannel。MemoryChannel是完全在内存中运行,速度很快,其优点同样也就成了缺点,不能持久化,若机器发生宕机或断电,数据就会丢失。在实际使用中需要根据具体的需求进行合理的选择。  先看下MemoryChannel的基本的类图,根据这个结构图可以很好的帮助理解。

ty_laurel的博客 6622

软考中级-软件设计师 知识点整理(一篇就过了 建议收藏)

软考中级-软件设计师上午题知识点总结

片言可决讼,半纸能缚龙 17万+

flume采集kafka数据到hdfs,不会产生大量小文件的配置

Name the components on this agent a1.sources=r1 a1.channels=c1 a1.sinks=k1 source a1.sources.r1.type = org.apache.flume.source.kafka.KafkaSource a1.sources.r1.channels = c1 a1.sources.r1.batchSize = 5...

weixin_45194258的博客 1528

Arduino ESP8266通过 RF433数据收发实验

Arduino ESP8266通过 RF433射频模块实现数据收发实验 写这篇文章,折腾了2天,在没有成功之前,一直在摸索和采坑当中,不要问我黑暗和黎明之间有多长。开发很多时候只问结果,不问过程的,在这里分享来之不易的结果,希望后面的人不要采坑,有成功的案例先河,后面与之相关的应用开发只需要套用模板修改即可实现。 实物搭建 RF433模块 我使用的是这个:nodemcu 本案例开发所使用到的库:RadioHead:http://www.airspayce.com/mikem/

perseverance51博客 3808

大模型自我认知微调的实战教程

本文主要介绍了大模型自我认知微调的实战教程,希望对学习大语言模型的同学们有所帮助。微调成功并保留原有能力的截图如下所示: 文章目录 1. 前言 2. 配置环境 2.1 安装虚拟环境 2.2 安装依赖库 3. 实战代码 3.1 配置数据集 3.2 lora微调

herosunly的博客 4万+

flume MemoryChannel 源码解析

1.先分析三个LinkedBlockingDeque类型的takeList,putList,queue putList:  存放的是来自source生产的数据,通过调用doPut(Event event)方法,它是如何到queue的,在每次执行doCommit的时候,会循环放到queue,其实doCommit()放法只做了putlist交给queue, synchronized(q

1088

【数据集】中国区域地面气象要素驱动数据集(CMFD)2.0

中国区域地面气象要素驱动数据集(CMFD)2.0

WW、forever的博客 2979

Flume源码分析—数据流转框架分析(五)

Flume-NG中主要由source、channel及sink三个组件完成目标数据的收集、传递及整理过程,本文主要通过其源码来分析flume是如何将这些组件有机的整合在一起,完成数据的流转过程,从而为我们开发相似的框架提供借鉴。源码的版本还是使用的apache-flume-1.6.0-src 。一、组件参数准备与启动1、首先在根据配置文件启动Flume时,在org.apache.flume.node

muriyi的博客 678

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

flume MemoryChannel 源代码解析

1.先分析三个LinkedBlockingDeque<Event>类型的takeList,putList,queue putList: 存放的是来自source生产的数据,通过调用doPut(Event event)方法,它是怎样到queue的,在每次运行doCommit的时候,会循环放到qu...

weixin_30414305的博客 185

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Flume之MemoryChannel源码解读

一、MemoryChannel属性: 1.基本属性 //定义队列中一次允许的事件总数: private static final Integer defaultCapacity = 100; //定义一个事务中允许的事件总数: private static final Integer defaultTransCapacity = 100; //将物理内存转换成槽(slot)数,默认是100,看后边...

ChengYanan的博客 1042

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Flume-ng源码解析之Channel组件

如果还没看过Flume-ng源码解析之启动流程,可以点击Flume-ng源码解析之启动流程 查看 1 接口介绍 组件的分析顺序是按照上一篇中启动顺序来分析的,首先是Channel,然后是Sink,最后是Source,在开始看组件源码之前我们先来看一下两个重要的接口,一个是LifecycleAware ,另一个是NamedComponent 1.1 LifecycleAware @Inter

隔壁家的老黄 343

Flume 源码学习(二)Channel组件介绍

Flume 源码学习(二)Channel组件介绍Channel是Flume中第二个组件,也是我们今天学习的对象。

workwithwebis3w的专栏 1537

Flume 源码解读之解析HDFS路径

项目升级需求: 需要通过flume采集过去时间段的日志,并存储到HDFS中,保证路径以 xxx/ymd=%Y-%m-%d/h=%H 来存储 实践很简单: 1)我们通过flume的RPCClient发送Event事件,给flume服务端,Event header中放入timeStamp      headers.put("timestamp", data.getTime().toStrin...

只看代码 1950

02. flume-ng 核心源码解析【小明同学】

文章目录flume-ng 核心代码解析org.apache.flume.node.Application#main 解析PollingPropertiesFileConfigurationProvider 构造函数Application 构造函数eventBus.register(application)然后我们继续看下 application.start() 方法,不用想,我们的核心入口就在这个 start 方法里了。接下来我们就看下 org.apache.flume.lifecycle.Lifecycl

u011046509的博客 724

【Hadoop】Flume-ng源码解析之Channel组件

通过源码来解读flume三大组件的channel组件

_朝和 1343

flume基础(三)

flume启动 进入flume客户端的bin目录,执行命令: ./flume-ng agent --conf ../conf/ -f ../conf/flumeToKafka.conf -Dflume.root.logger=DEBUG,console -n agentDemo 配置文件名:flumeToKafka,配置文件中agent的名称:agentDemo ##关闭...

LexKaing 学习天地 270
上一篇: Flume + HDFS Sink采集数据及如何添加第三方JAR
下一篇: Flume - FileChannel源码详解
qianshanding0708
博客等级 码龄11年 425粉丝 96原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值