Flume 源码学习(二)Channel组件介绍
来源:互联网 发布:windows欢迎界面 编辑:程序博客网 时间:2024/05/01 05:37
Flume 源码学习(二)Channel组件介绍
Channel是Flume中第二个组件,是日志从source传输到sink的通道。根据Flume文档,channel有两个重要衡量指标:
- Reliability:可依赖性。即channel需要接收到的event被下个agent接收或被最终的sink接收。Flume使用事务来保证Reliability。支持可以持久化的基于文件系统的FileChannel和不能保证持久化的MemoryChannel
- Recoverability:可恢复性。如果发生Failure,是否能够恢复数据;Flume支持可恢复的FileChannel和不支持恢复但传输速度快得MemoryChannel
类图
首先还是来看Channel相关类的类图:
两个望文生义的类的说明:
MemoryChannel
我们首先来看MemoryChannel的实现,MemoryChannel有几个重要参数可以配置:
- capacity:Channel的最大容积
- transactionCapacity:一个事务最多可以包含多少个events
- byteCapacity:Channel的Queue的最大的byte 容积
- byteCapacityBufferPercent:定义了byteCapacity和评估的event size之间缓冲的百分比,概要的说就是如果MemoryChannel中等待写出的EventList的byte size最多只能达到(1-byteCapacityBufferPercent/100)*100%,剩下的是缓冲buffer(如果没有buffer,很可能出现内存溢出)
- keep-alive:定义了允许在队列中等待的最大秒数
根据上面的类图,我们知道MemoryChannel继承了BasicChannelSemantics抽象类,而后者
有一个抽象方法createTransaction()需要子类自己实现。所以,MemoryChannel中第一个重要的功能就是基于内存的Transaction的实现。MemoryChannel中是MemoryTransaction这一个内部类,代码如下:
private class MemoryTransaction extends BasicTransactionSemantics { private LinkedBlockingDeque<Event> takeList;//从channel中take,准备推送到sink private LinkedBlockingDeque<Event> putList;//从source put到channel的队列 private final ChannelCounter channelCounter;//counter private int putByteCounter = 0;//put的字节counter private int takeByteCounter = 0;//take的字节counter public MemoryTransaction(int transCapacity, ChannelCounter counter) { putList = new LinkedBlockingDeque<Event>(transCapacity); takeList = new LinkedBlockingDeque<Event>(transCapacity); channelCounter = counter; } //往putList增加Event,如果没有空间抛错 @Override protected void doPut(Event event) throws InterruptedException { channelCounter.incrementEventPutAttemptCount(); int eventByteSize = (int)Math.ceil(estimateEventSize(event)/byteCapacitySlotSize); 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; } //从外部类MemoryChannel的等待Take的Event List中take一个过来放到事务的takeList里面,作为本次事务需要提交的Event @Override protected Event doTake() throws InterruptedException { channelCounter.incrementEventTakeAttemptCount(); if(takeList.remainingCapacity() == 0) {//首先判断takeList是否还有空间 throw new ChannelException("Take list for MemoryTransaction, capacity " + takeList.size() + " full, consider committing more frequently, " + "increasing capacity, or increasing thread count"); } if(!queueStored.tryAcquire(keepAlive, TimeUnit.SECONDS)) {//通过queueStored这Semaphore信号来判断外部类MemoryChannel是否有queued Event等待被take,用信号量而不是直接判断queueStored(LinkedBlockingDeque<Event>)的poll()主要是后者会阻塞queueStored上的所有操作,尤其是包括为空得情况下put操作。可以提高throughput。 return null;//没有获取到,意味着可能queue当前为空。 } Event event; synchronized(queueLock) { event = queue.poll();//queueStored不为空。 } Preconditions.checkNotNull(event, "Queue.poll returned NULL despite semaphore " + "signalling existence of entry"); takeList.put(event); //计算taken的byte int eventByteSize = (int)Math.ceil(estimateEventSize(event)/byteCapacitySlotSize); takeByteCounter += eventByteSize; return event; } //实际事务的提交 @Override protected void doCommit() throws InterruptedException { int remainingChange = takeList.size() - putList.size(); if(remainingChange < 0) {//take size < putsize,sink的消费速度慢于source的产生速度 if(!bytesRemaining.tryAcquire(putByteCounter, keepAlive, TimeUnit.SECONDS)) {//判断是否有足够空间接收putList中events所占的空间 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"); } if(!queueRemaining.tryAcquire(-remainingChange, keepAlive, TimeUnit.SECONDS)) {//判断queue是否还有空间接收(因为生产速度快于消费速度) 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();//事务期间生产的event int takes = takeList.size();//事务期间等待消费的event synchronized(queueLock) { if(puts > 0 ) { while(!putList.isEmpty()) { if(!queue.offer(putList.removeFirst())) {//将putList中新生产的Events保存到queue throw new RuntimeException("Queue add failed, this shouldn't be able to happen"); } } } putList.clear();//重置事务的putList,下同 takeList.clear(); } bytesRemaining.release(takeByteCounter); takeByteCounter = 0; putByteCounter = 0; queueStored.release(puts);//从queueStored释放puts个信号量 if(remainingChange > 0) { queueRemaining.release(remainingChange);//queueRemaining释放remainingChange个信号量 } if (puts > 0) { channelCounter.addToEventPutSuccessCount(puts); } if (takes > 0) { channelCounter.addToEventTakeSuccessCount(takes); } channelCounter.setChannelSize(queue.size()); } @Override protected void doRollback() { int takes = takeList.size(); 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());//把takelist中的events原封不动的放回queue } putList.clear(); } bytesRemaining.release(putByteCounter); putByteCounter = 0; takeByteCounter = 0; queueStored.release(takes); channelCounter.setChannelSize(queue.size()); } }
通过上面的代码我们可以看到MemoryChanne的createTransaction内部使用的是基于内存的MemoryTransaction,没有实现持久化。在生产和消费的过程中,非常关注byteCapacity,防止内存溢出。
FileChannel
接下来来看FileChannel的实现TBD
0 0
- Flume 源码学习(二)Channel组件介绍
- flume二:flume Channel介绍
- Flume-ng源码解析之Channel组件
- Flume-ng源码解析之Channel组件
- Flume-ng源码解析之Channel组件
- Flume-ng源码解析之Channel组件
- Flume-ng源码解析之Channel组件
- Flume-ng源码解析之Channel组件
- Flume-ng源码解析之Channel组件
- Flume-ng源码解析之Channel组件
- Flume-ng源码解析之Channel组件
- Flume学习进阶(一):source、channel、sink、processor、interceptor等组件列表说明及包含的类型介绍
- Flume学习笔记 --- Flume内置source,channel, sink介绍
- 【Hadoop】Flume-ng源码解析之Channel组件
- Flume内置channel,source,sink三组件介绍
- Flume内置channel,source,sink三组件介绍
- Flume内置channel,source,sink三组件介绍
- Flume 源码学习(一)Source介绍
- 线程(五)--线程控制-让步
- 【kafka】win7-64位 kafka安装
- Java文本语音转换组件JTTS发布
- jepg
- select用法
- Flume 源码学习(二)Channel组件介绍
- HDU 2.1.6 找新朋友
- 欢迎使用CSDN-markdown编辑器
- HDU 2.1.7 整数对
- 第二周项目-小试循环
- HDU 2.1.8 The area
- iOS开发bundle对象使用详解
- 如何让处于文档流中间的tab标签页滚动到顶部时固定
- CF #651B. Beautiful Paintings