前边介绍了flume的基本概念和Source部分,接下来看看flume中的第二大组件Channel中的MemoryChannel。MemoryChannel是完全在内存中运行,速度很快,其优点同样也就成了缺点,不能持久化,若机器发生宕机或断电,数据就会丢失。在实际使用中需要根据具体的需求进行合理的选择。
先看下MemoryChannel的基本的类图,根据这个结构图可以很好的帮助理解。
MemoryChannel中最重要的部分主要是Channel、Transaction 和Configurable三个接口。
Channel接口中主要声明了Channel中的三个方法:
public void put(Event event) throws ChannelException; //刚方法从指定的Source中获得Event放入指定的Channel中
public Event take() throws ChannelException; //take方法主要是从Channel中取出event放入Sink中
public Transaction getTransaction(); //getTransaction方法是获得当前Channel的事务实例
Transaction接口主要声明了flume中事务机制的四个方法:
enum TransactionState { Started, Committed, RolledBack, Closed } //枚举类型,指定了事务的四种状态,事务开始、提交、失败回滚、关闭
void begin();
void commit();
void rollback();
void close();
Configurable接口主要是和flume配置组件相关的,需要从flume配置系统获取配置信息的任何组件,都必须实现该接口。该接口中只声明了一个context方法,用于获取配置信息。
以上方法的具体内容都是在具体的Channel中实现的,系统在启动时会根据配置文件信息调用相应的组件的方法实现,这种实现称为回调,类似于C语言中的钩子函数,先声明方法然后在具体的需要时调用相应的实现方法。
接下来看看具体的代码实现,代码开始是定义一些默认的配置信息,Channel、Transaction事务大小等信息:
public class MemoryChannel extends BasicChannelSemantics {
private static Logger LOGGER = LoggerFactory.getLogger(MemoryChannel.class);
private static final Integer defaultCapacity = 100;
private static final Integer defaultTransCapacity = 100;
private static final double byteCapacitySlotSize = 100;
private static final Long defaultByteCapacity = (long)(Runtime.getRuntime().maxMemory() * .80);
private static final Integer defaultByteCapacityBufferPercentage = 20;
private static final Integer defaultKeepAlive = 3;
接下来就是实现Channel的put、get方法和事务的commit、rollback方法,这几个方法都是在内部类 MemoryTransaction 实现的,看到下边的几个方法名字,大家可能会问怎么每个方法前边都有个do,实际上这是因为 MemoryTransaction 继承了BasicTransactionSemantics抽象类,而不是直接实现了 Channel 和 Transaction 接口,在 BasicTransactionSemantics抽象接口中 对上边提到的几种方法做了一些简单的封装,在内部调用就是调用类似doTake的方法:
protected Event take() {
Preconditions.checkState(Thread.currentThread().getId() == initialThreadId,
"take() called from different thread than getTransaction()!");
Preconditions.checkState(state.equals(State.OPEN),
"take() called when transaction is %s!", state);
try {
return doTake();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
}
}
具体的 MemoryTransaction 内部类实现的几个方法如下代码:
private class MemoryTransaction extends BasicTransactionSemantics {
private LinkedBlockingDeque<Event> takeList; //阻塞双端队列,从channel中取event先放入takeList,输送到sink,commit成功,从channel queue中删除
private LinkedBlockingDeque<Event> putList; //从source 会先放至putList,然后commit传送到channel queue队列
private final ChannelCounter channelCounter