理解FlumeNG的batchSize和transactionCapacity参数和传输事务的原理 【转】
基于ThriftSource,MemoryChannel,HdfsSink三个组件,对Flume数据传输的事务进行分析,如果使用的是其他组件,Flume事务具体的处理方式将会不同。
Flume的事务处理原理:
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事物进行分析。
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.
那么,事务到底做了什么?
实际上,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();
- ...
- }
很简单,其实就是清空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());
- }
- ...
- }
- ...
- }
读完代码可见
batchSize是针对Source和Sink提出的一个概念,它用来限制source和sink对event批量处理的。
即一次性你可以处理batchSize个event,这个一次性就是指在一个事务中。
这个参数值越大,每个事务提交的范围就越大,taskList的清空等操作次数会减少,因此性能肯定会提升,但是可能在出错时,回滚的返回也会变大。
接下来看一下
内存通道中的内部类MemoryTransaction:
private class MemoryTransaction extends BasicTransactionSemantics {
private LinkedBlockingDeque takeList;
private LinkedBlockingDeque putList;
private final ChannelCounter channelCounter;
private int putByteCounter = 0;
private int takeByteCounter = 0;
public MemoryTransaction(int transCapacity, ChannelCounter counter) {
putList = new LinkedBlockingDeque(transCapacity);
takeList = new LinkedBlockingDeque(transCapacity);
channelCounter = counter;
}
可见transactionCapacity参数其实
就是putList和takeList的容量大小。在flume1.5版本中SpillableMemoryChannel的putList和takeList的长度为largestTakeTxSize和largestPutTxSize参数,该参数值为5000
理解FlumeNG的batchSize和transactionCapacity参数和传输事务的原理 【转】的更多相关文章
- (转)理解YOLOv2训练过程中输出参数含义
最近有人问起在YOLOv2训练过程中输出在终端的不同的参数分别代表什么含义,如何去理解这些参数?本篇文章中我将尝试着去回答这个有趣的问题. 刚好现在我正在训练一个YOLOv2模型,拿这个真实的例子来讨 ...
- 理解YOLOv2训练过程中输出参数含义
原英文地址: https://timebutt.github.io/static/understanding-yolov2-training-output/ 最近有人问起在YOLOv2训练过程中输出在 ...
- 通俗的讲法理解spring的事务实现原理
拿房屋买卖举例,流程:销售房屋 -- 接待员 -- 销售员 -- 财务 售楼处 存放着所有待售和已售的房屋数据(数据源 datasource) 总经理 带领一套自己的班底,下属员工都听自己的,服务于售 ...
- ibatis源码学习4_参数和结果的映射原理
问题在详细介绍ibatis参数和结果映射原理之前,让我们先来思考几个问题.1. 为什么需要参数和结果的映射?相对于全自动的orm,ibatis一个重要目标是,通过维护POJO与SQL之间的映射关系,让 ...
- 曹工说Redis源码(4)-- 通过redis server源码来理解 listen 函数中的 backlog 参数
文章导航 Redis源码系列的初衷,是帮助我们更好地理解Redis,更懂Redis,而怎么才能懂,光看是不够的,建议跟着下面的这一篇,把环境搭建起来,后续可以自己阅读源码,或者跟着我这边一起阅读.由于 ...
- 深入理解JVM(三)——配置参数
JVM配置参数分为三类参数: 1.跟踪参数 2.堆分配参数 3.栈分配参数 这三类参数分别用于跟踪监控JVM状态,分配堆内存以及分配栈内存. 跟踪参数 跟踪参数用于跟踪监控JVM,往往被开发人员用于J ...
- 如何理解CUDA中的cudaMalloc()的参数
首先看下此运行时函数的原型: cudaError_t cudaMalloc (void **devPtr, size_t size ); 主要的第一个参数.为什么是两个星星呢?用个例子来说明下. fl ...
- 深入理解Java虚拟机,gc输出参数
https://blog.csdn.net/qq_21383435/article/details/80702205
- 理解Linux系统负荷(WDCP系统后台参数之一)
一.查看系统负荷 如果你的网站很卡,可能是因为服务器很慢,,你或许想查看一下,它的工作量是否太大了. 在Linux系统中,我们一般使用uptime命令查看(w命令和top命令也行).(另外,它们在苹果 ...
随机推荐
- ios中图片旋转
@interface ViewController () { UIImageView *_imageview; BOOL flag; } @end @implementation ViewContro ...
- Maven实战——常用Maven插件介绍
maven nexus 库已上传了第三方jar,但就是用mvn compile下不到本地 回答于 2013-06-04 14:40 你是通过何种方式上传到nexus的? 有给pom文件吗? 如果是单纯 ...
- maven中跳过单元测试
Maven 提供了跳过单元测试的能力,只需要使用 Surefire 插件的 skip 参数. 在命令行,只要简单的给任何目标添加 maven.test.skip 属性就能跳过测试: $ mvn ins ...
- realloc 使用详解(分析realloc invalid pointer、指针无效等错误)【转】
来源:http://www.cnblogs.com/ladd/archive/2012/06/30/2571420.htmlrealloc函数用来为ptr重新分配大小为size的一块内存,看似很简单, ...
- Spring使用内存数据库二
在上篇<Spring 使用内存数据库>中我们使用Hibernate作为ORM的框架,直接调用Hibernate的API进行相关的持久化操作,但在实际项目中,可能会由于公司规定等原因要求统一 ...
- C语言学习笔记 (008) - C语言字符串操作总结大全(超详细)(转)
1)字符串操作 strcpy(p, p1) 复制字符串 strncpy(p, p1, n) 复制指定长度字符串 strcat(p, p1) 附加字符串 strncat(p, p1, n) 附加指定长度 ...
- 【MySQL】mysql在Windows下使用mysqldump命令备份数据库
在cmd窗口中使用mysqldump命令首先需要配置环境变量 1,在计算机中找到MySQL的安装位置,找到MySQL Workbench,比如我的是C:\Program Files\MySQL\MyS ...
- iOS 图标
iOS icon是一件很头疼的事情 大致多少张呢,忘记了,下面开发者中心给的一个文档,自己捋捋有多少张 180934.jpg 幸亏不是自己画的,不然要骂姥姥,但是多数的UI是妹子啊,让人家做人家会说: ...
- 免费的UI素材准备
UI素材准备 UI也是一个专业性比较强的一个活啊,不过还好我有强大的百度,强大的百度有各种强大的网站,下面介绍一些UI常用的网站1.阿里巴巴矢量图标库 http://www.iconfont.cn/p ...
- Docker : endpoint with name xxx already exists.
停止不了容器,在尝试过: docker stop [container_id] docker kill [container_id] 都不行之后,强制删除容器: docker rm -f [cont ...