如果你还没看过Flume-ng源码解析系列中的启动流程、Channel组件和Sink组件,可以点击下面链接:

Flume-ng源码解析之启动流程

Flume-ng源码解析之Channel组件

Flume-ng源码解析之Sink组件

在前面三篇文章中我们初步了解了Flume的启动流程、Channel组件和Sink组件,接下来我们一起来看看agent三大组件中Source组件。

1 Source

Source,作为agent中的消息来源组件,我们来看看它是如何将event传递给channel的和它的特性。

依然先看代码:

@InterfaceAudience.Public
@InterfaceStability.Stable
public interface Source extends LifecycleAware, NamedComponent {
public void setChannelProcessor(ChannelProcessor channelProcessor);
public ChannelProcessor getChannelProcessor();
}

我们可以看到它里面定义的两个需要实现方法是getChannelProcessor和setChannelProcessor,我们大概可以猜到,source就是通过ChannelProcessor将event传输给channel的。

这里先来了解一下Source的类型,Flume根据数据来源的特性将Source分成两类类,像Http、netcat和exec等就是属于事件驱动型(EventDrivenSource),而kafka和Jms等就是属于轮询拉取型(PollableSource)。

据我们在启动流程中了解到的,Application是先启动SourceRunner,再由SourceRunner来启动source,那么既然source有两种类型,那么Sourcerunner也分为EventDrivenSourceRunner和PollableSourceRunner,我们来看看它们的start():

EventDrivenSourceRunner

public class EventDrivenSourceRunner extends SourceRunner {

@Override
public void start() {
Source source = getSource();
ChannelProcessor cp = source.getChannelProcessor();
cp.initialize();
source.start();
lifecycleState = LifecycleState.START;
}

}

PollableSourceRunner

public class PollableSourceRunner extends SourceRunner {

  …
@Override
public void start() {
PollableSource source = (PollableSource) getSource();
ChannelProcessor cp = source.getChannelProcessor();
cp.initialize();
source.start(); runner = new PollingRunner(); runner.source = source;
runner.counterGroup = counterGroup;
runner.shouldStop = shouldStop; runnerThread = new Thread(runner);
runnerThread.setName(getClass().getSimpleName() + "-" +
source.getClass().getSimpleName() + "-" + source.getName());
runnerThread.start(); lifecycleState = LifecycleState.START;
} …
public static class PollingRunner implements Runnable { private PollableSource source;
private AtomicBoolean shouldStop;
private CounterGroup counterGroup; @Override
public void run() {
logger.debug("Polling runner starting. Source:{}", source); while (!shouldStop.get()) {
counterGroup.incrementAndGet("runner.polls"); try {
if (source.process().equals(PollableSource.Status.BACKOFF)) {
counterGroup.incrementAndGet("runner.backoffs"); Thread.sleep(Math.min(
counterGroup.incrementAndGet("runner.backoffs.consecutive")
* source.getBackOffSleepIncrement(), source.getMaxBackOffSleepInterval()));
} else {
counterGroup.set("runner.backoffs.consecutive", 0L);
}
} catch (InterruptedException e) {
logger.info("Source runner interrupted. Exiting");
counterGroup.incrementAndGet("runner.interruptions");
} catch (EventDeliveryException e) {
logger.error("Unable to deliver event. Exception follows.", e);
counterGroup.incrementAndGet("runner.deliveryErrors");
} catch (Exception e) {
counterGroup.incrementAndGet("runner.errors");
logger.error("Unhandled exception, logging and sleeping for " +
source.getMaxBackOffSleepInterval() + "ms", e);
try {
Thread.sleep(source.getMaxBackOffSleepInterval());
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
} logger.debug("Polling runner exiting. Metrics:{}", counterGroup);
} } }

无论是PollableSourceRunner还是EventDrivenSourceRunner,都是调用它里面的source的start()。这个时候我们看到ChannelProcessor的存在,那么就会有疑惑,这ChannelProcessor哪来的?我们还是得看回AbstarctConfigurationProvider,查看里面的loadSources(),我们就会发现下面这段代码:

ChannelSelectorConfiguration selectorConfig = config.getSelectorConfiguration();
ChannelSelector selector = ChannelSelectorFactory.create(sourceChannels, selectorConfig);
ChannelProcessor channelProcessor = new ChannelProcessor(selector);
Configurables.configure(channelProcessor, config);
source.setChannelProcessor(channelProcessor);

到这里我们基本已经了解了Source的启动流程,下面以AvroSource为例看看,source是在哪里调用ChannelProcessor的插入方法。

2 AvroSource

public class AvroSource extends AbstractSource implements EventDrivenSource,
Configurable, AvroSourceProtocol {

@Override
public Status append(AvroFlumeEvent avroEvent) {
if (logger.isDebugEnabled()) {
if (LogPrivacyUtil.allowLogRawData()) {
logger.debug("Avro source {}: Received avro event: {}", getName(), avroEvent);
} else {
logger.debug("Avro source {}: Received avro event", getName());
}
} sourceCounter.incrementAppendReceivedCount();
sourceCounter.incrementEventReceivedCount(); Event event = EventBuilder.withBody(avroEvent.getBody().array(),
toStringMap(avroEvent.getHeaders())); try {
getChannelProcessor().processEvent(event);
} catch (ChannelException ex) {
logger.warn("Avro source " + getName() + ": Unable to process event. " +
"Exception follows.", ex);
return Status.FAILED;
} sourceCounter.incrementAppendAcceptedCount();
sourceCounter.incrementEventAcceptedCount(); return Status.OK;
} @Override
public Status appendBatch(List<AvroFlumeEvent> events) {
logger.debug("Avro source {}: Received avro event batch of {} events.",
getName(), events.size());
sourceCounter.incrementAppendBatchReceivedCount();
sourceCounter.addToEventReceivedCount(events.size()); List<Event> batch = new ArrayList<Event>(); for (AvroFlumeEvent avroEvent : events) {
Event event = EventBuilder.withBody(avroEvent.getBody().array(),
toStringMap(avroEvent.getHeaders())); batch.add(event);
} try {
getChannelProcessor().processEventBatch(batch);
} catch (Throwable t) {
logger.error("Avro source " + getName() + ": Unable to process event " +
"batch. Exception follows.", t);
if (t instanceof Error) {
throw (Error) t;
}
return Status.FAILED;
} sourceCounter.incrementAppendBatchAcceptedCount();
sourceCounter.addToEventAcceptedCount(events.size()); return Status.OK;
}

}

在append方法中我们可以看到getChannelProcessor().processEvent(event);,所以不同的Source根据它的不同触发机制和拉取机制,在特定的时候调用ChannelProcessor来执行event的插入。 ·

到此为止,我们就完成了对Flume启动流程和三大组件的研究,鉴于能力,其中有些细节没办法深入研究,希望以后有时间能够继续深入分析下去。

Flume-ng源码解析之Source组件的更多相关文章

  1. Flume-ng源码解析之Sink组件

    作为启动流程中第二个启动的组件,我们今天来看看Sink的细节 1 Sink Sink在agent中扮演的角色是消费者,将event输送到特定的位置 首先依然是看代码,由代码我们可以看出Sink是一个接 ...

  2. rest-framework源码解析和自定义组件----版本

    版本 url中通过GET传参自定义的版本 12345678910111213141516171819202122 from django.http import HttpResponsefrom dj ...

  3. Flume-ng源码解析之Channel组件

    如果还没看过Flume-ng源码解析之启动流程,可以点击Flume-ng源码解析之启动流程 查看 1 接口介绍 组件的分析顺序是按照上一篇中启动顺序来分析的,首先是Channel,然后是Sink,最后 ...

  4. Spring源码解析系列汇总

    相信我,你会收藏这篇文章的 本篇文章是这段时间撸出来的Spring源码解析系列文章的汇总,总共包含以下专题.喜欢的同学可以收藏起来以备不时之需 SpringIOC源码解析(上) 本篇文章搭建了IOC源 ...

  5. .Net Core缓存组件(Redis)源码解析

    上一篇文章已经介绍了MemoryCache,MemoryCache存储的数据类型是Object,也说了Redis支持五中数据类型的存储,但是微软的Redis缓存组件只实现了Hash类型的存储.在分析源 ...

  6. .Net Core缓存组件(MemoryCache)源码解析

    一.介绍 由于CPU从内存中读取数据的速度比从磁盘读取快几个数量级,并且存在内存中,减小了数据库访问的压力,所以缓存几乎每个项目都会用到.一般常用的有MemoryCache.Redis.MemoryC ...

  7. admin源码解析以及仿照admin设计stark组件

    ---恢复内容开始--- admin源码解析 一 启动:每个APP下的apps.py文件中. 首先执行每个APP下的admin.py 文件. def autodiscover(): autodisco ...

  8. admin源码解析及自定义stark组件

    admin源码解析 单例模式 单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实例存在.当你希望在整个系统中,某个类只能出现一个实例时,单 ...

  9. Django 之 admin组件使用&源码解析

    admin组件使用 Django 提供了基于 web 的管理工具. Django 自动管理工具是 django.contrib 的一部分.可以在项目的 settings.py 中的 INSTALLED ...

随机推荐

  1. Struts2 属性驱动、模型驱动、异常机制

    模型驱动使用单独的VO(值对象)来封装请求参数和处理结果,属性驱动则使用Action实例来封装请求参数和处理结果. 一.使用模型驱动 1.login.action采用模型驱动模式实现,采用模型驱动时必 ...

  2. C#与Java互通AES算法加密解密

    /// <summary>AES加密</summary> /// <param name="text">明文</param> /// ...

  3. oracle存储过程中文乱码问题

    设置环境变量,新建变量,设置变量名:NLS_LANG,变量值:SIMPLIFIED CHINESE_CHINA.ZHS16GBK word哥,还是不行呀: 参考:http://idata.blog.5 ...

  4. Windows 7 下 PHP 开发环境搭建(手动)

    Windows 7 下 PHP 开发环境搭建 1.说明 做开发的都知道一句话,就是“站在巨人的肩膀上”.确实现在打开浏览器随便一搜很多一键安装PHP环境的软件,比如wamp.xampp.AppServ ...

  5. EF6多线程与分库架构设计之Repository

    1.项目背景 这里简单介绍一下项目需求背景,之前公司的项目基于EF++Repository+UnitOfWork的框架设计的,其中涉及到的技术有RabbitMq消息队列,Autofac依赖注入等常用的 ...

  6. 龙珠超的新OP【限界突破×サバイバー】

    这首歌真的很燃 下载>>   限界突破×サバイバー 中文歌词 演唱:冰川清志 兴奋了!就去宇宙吧 最先端的“着迷”怎么样! 握在手中 突然想要大笑 糊里糊涂也习惯了吗! I can't g ...

  7. maven 配置安装

    1.下载maven http://maven.apache.org/   2.windows安装maven 解压包后配置环境变量 PATH:%M2_HOME%\bin M2_HOME:D:\soft\ ...

  8. Bootstrap框架的要点--栅格系统

    不同的公司要求使用框架有所不同,而Bootstrap框架在工作中使用频次较高,其中栅格系统在这一框架中的地位不容小觑,下面我们开始聊聊它吧. 简单介绍: Bootstrap提供了一套响应式.移动设备优 ...

  9. 一个web应用的诞生(6)--用户账户

    之前登录注册的功能都已经完成,但是登录成功回到首页发现还是白茫茫的一片,对的,title一直都写得博客,那么最终目的也是写出一个轻博客来,但是,在发表文章之前是不是要先记录一下登录状态呢? 用户登录 ...

  10. 【转】解决UpdatePanel 与 jQuery的冲突

    现在越来越多的朋友喜欢将jQuery和ASP.NET AJAX 一起来用,最近,许多印度人在forum里抱怨说UpdatePanel和jQuery不兼容,许多jQuery效果在UpdatePanel更 ...