最近项目在用到flume,因此翻了下flume的代码,

启动脚本:

  nohup bin/flume-ng agent -n tsdbflume -c conf -f conf/配置文件.conf -Dflume.root.logger=DEBUG,console &

翻下flume-ng的脚本,  FLUME_AGENT_CLASS="org.apache.flume.node.Application"

从Application进入;

写了下flume-agent启动的时序图:

这是简单的启动时序图,时序图里画的都在flume-node这个项目里;

里边其实最核心的是创建配置文件里的对象,这个工作是在AbstractConfigurationProvider.getConfiguration()这个方法里做的。先上代码

  public MaterializedConfiguration getConfiguration() {
MaterializedConfiguration conf = new SimpleMaterializedConfiguration();
   // getFlumeConfiguration()方法,是关键核心,负责整个配置加载,下边代码说明
FlumeConfiguration fconfig = getFlumeConfiguration();
AgentConfiguration agentConf = fconfig.getConfigurationFor(getAgentName());
if (agentConf != null) {
Map<String, ChannelComponent> channelComponentMap = Maps.newHashMap();
Map<String, SourceRunner> sourceRunnerMap = Maps.newHashMap();
Map<String, SinkRunner> sinkRunnerMap = Maps.newHashMap();
try {
loadChannels(agentConf, channelComponentMap);
loadSources(agentConf, channelComponentMap, sourceRunnerMap);
loadSinks(agentConf, channelComponentMap, sinkRunnerMap);
Set<String> channelNames = new HashSet<String>(channelComponentMap.keySet());
for (String channelName : channelNames) {
ChannelComponent channelComponent = channelComponentMap.get(channelName);
if (channelComponent.components.isEmpty()) {
LOGGER.warn(String.format("Channel %s has no components connected" +
" and has been removed.", channelName));
channelComponentMap.remove(channelName);
Map<String, Channel> nameChannelMap =
channelCache.get(channelComponent.channel.getClass());
if (nameChannelMap != null) {
nameChannelMap.remove(channelName);
}
} else {
LOGGER.info(String.format("Channel %s connected to %s",
channelName, channelComponent.components.toString()));
conf.addChannel(channelName, channelComponent.channel);
}
}
for (Map.Entry<String, SourceRunner> entry : sourceRunnerMap.entrySet()) {
conf.addSourceRunner(entry.getKey(), entry.getValue());
}
for (Map.Entry<String, SinkRunner> entry : sinkRunnerMap.entrySet()) {
conf.addSinkRunner(entry.getKey(), entry.getValue());
}
} catch (InstantiationException ex) {
LOGGER.error("Failed to instantiate component", ex);
} finally {
channelComponentMap.clear();
sourceRunnerMap.clear();
sinkRunnerMap.clear();
}
} else {
LOGGER.warn("No configuration found for this host:{}", getAgentName());
}
return conf;
}

下面说下这个类的具体加载过程。

PropertiesFileConfigurationProvider.getFlumeConfiguration()

  @Override
public FlumeConfiguration getFlumeConfiguration() {
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(file));
Properties properties = new Properties();
properties.load(reader);
return new FlumeConfiguration(toMap(properties));
} catch (IOException ex) {
LOGGER.error("Unable to load file:" + file
+ " (I/O failure) - Exception follows.", ex);
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException ex) {
LOGGER.warn(
"Unable to close file reader for file: " + file, ex);
}
}
}
return new FlumeConfiguration(new HashMap<String, String>());
}

new FlumeConfiguration(toMap(properties)),代码在下边:

下边从代码入手写下怎么加载内容:

  /**
* 创建一个FlumeConfiguration对象,参数为:配置文件的key-value对
* Creates a populated Flume Configuration object.
*/
public FlumeConfiguration(Map<String, String> properties) {
agentConfigMap = new HashMap<String, AgentConfiguration>();
errors = new LinkedList<FlumeConfigurationError>();
// Construct the in-memory component hierarchy
for (String name : properties.keySet()) {
String value = properties.get(name); // addRawProperty里对agentConfigMap初始化,
// 1:这里插入的是agentConfiguration对象里的contextMap
if (!addRawProperty(name, value)) {
logger.warn("Configuration property ignored: " + name + " = " + value);
}
}
// Now iterate thru the agentContext and create agent configs and add them
// to agentConfigMap // validate and remove improperly configured components
// 2:这里插入的是agentConfiguration对象里的configMap
validateConfiguration();
}

然后,进入FlumeConfiguration.addRawProperty(name,value):

  private boolean addRawProperty(String name, String value) {
// Null names and values not supported
if (name == null || value == null) {
errors
.add(new FlumeConfigurationError("", "",
FlumeConfigurationErrorType.AGENT_NAME_MISSING,
ErrorOrWarning.ERROR));
return false;
} // Empty values are not supported
if (value.trim().length() == 0) {
errors
.add(new FlumeConfigurationError(name, "",
FlumeConfigurationErrorType.PROPERTY_VALUE_NULL,
ErrorOrWarning.ERROR));
return false;
} // Remove leading and trailing spaces
name = name.trim();
value = value.trim(); int index = name.indexOf('.'); // All configuration keys must have a prefix defined as agent name
if (index == -1) {
errors
.add(new FlumeConfigurationError(name, "",
FlumeConfigurationErrorType.AGENT_NAME_MISSING,
ErrorOrWarning.ERROR));
return false;
} String agentName = name.substring(0, index); // Agent name must be specified for all properties
if (agentName.length() == 0) {
errors
.add(new FlumeConfigurationError(name, "",
FlumeConfigurationErrorType.AGENT_NAME_MISSING,
ErrorOrWarning.ERROR));
return false;
} String configKey = name.substring(index + 1); // Configuration key must be specified for every property
if (configKey.length() == 0) {
errors
.add(new FlumeConfigurationError(name, "",
FlumeConfigurationErrorType.PROPERTY_NAME_NULL,
ErrorOrWarning.ERROR));
return false;
} AgentConfiguration aconf = agentConfigMap.get(agentName); // 这里创建AgentConfiguration,并插入到FlumeConfiguration的Map<String, AgentConfiguration> agentConfigMap中
if (aconf == null) {
aconf = new AgentConfiguration(agentName, errors);
agentConfigMap.put(agentName, aconf);
} // Each configuration key must begin with one of the three prefixes:
// sources, sinks, or channels.
// 最终,键值对被加载到agentConfiguration中
return aconf.addProperty(configKey, value);
}

最终被加载到:agentConfiguration.addProperty(String key, String value)中

      ComponentNameAndConfigKey cnck = parseConfigKey(key,
BasicConfigurationConstants.CONFIG_SOURCES_PREFIX); if (cnck != null) {
// it is a source
String name = cnck.getComponentName();
Context srcConf = sourceContextMap.get(name); if (srcConf == null) {
srcConf = new Context();
sourceContextMap.put(name, srcConf);
}
// sourceContextMap中存放new Context().put(cnck.getConifyKey(),value)
srcConf.put(cnck.getConfigKey(), value);
return true;
}

所以最后是加载到AgentConfiguration中对应的*ContextMap中了;

  public static class AgentConfiguration {

    private final String agentName;
private String sources;
private String sinks;
private String channels;
private String sinkgroups; private final Map<String, ComponentConfiguration> sourceConfigMap;
private final Map<String, ComponentConfiguration> sinkConfigMap;
private final Map<String, ComponentConfiguration> channelConfigMap;
private final Map<String, ComponentConfiguration> sinkgroupConfigMap; private Map<String, Context> sourceContextMap;
private Map<String, Context> sinkContextMap;
private Map<String, Context> channelContextMap;
private Map<String, Context> sinkGroupContextMap; private Set<String> sinkSet;
private Set<String> sourceSet;
private Set<String> channelSet;
private Set<String> sinkgroupSet; private final List<FlumeConfigurationError> errorList; // ** 省略其他代码 }

这里比较崩溃,跑来跑去的我们来梳理下:

先是FlumeConfiguration的addRawProperty方法执行put动作:

  FlumeConfiguration.agentConfigMap.put(agentName, AgentConfiguration conf);

在这里创建AgentCponfiguration对象

  aconf = new AgentCponfiguration(agentName, errors);

然后执行

  aconf.addProperty(configKey, value), 将key,value插入到AgentConfiguration对象的*ContextMap中,至此完成键值对的保存工作;

最终所有的键值对都被保存在AgentConfiguration对象中;

对于AgentConfiguration的插入操作,也分为两个部分,在FlumeConifiguration构造方法中,

1:addRawProperty(name,value);将kv键值对,插入到AgentConfiguration对象的contextMap中;

2:validateConfiguration;下边跟进下validateConfiguration代码;

validateConfiguration -> aconf.isValid() -> validateChannels(channelSet)

代码注释中,其实已经写得比较详细了

    /**
* If it is a known component it will do the full validation required for
* that component, else it will do the validation required for that class.
*/
private Set<String> validateChannels(Set<String> channelSet) {
Iterator<String> iter = channelSet.iterator();
Map<String, Context> newContextMap = new HashMap<String, Context>();
ChannelConfiguration conf = null;
/*
* The logic for the following code:
*
* Is it a known component?
* -Yes: Get the ChannelType and set the string name of that to
* config and set configSpecified to true.
* -No.Look for config type for the given component:
* -Config Found:
* Set config to the type mentioned, set configSpecified to true
* -No Config found:
* Set config to OTHER, configSpecified to false,
* do basic validation. Leave the context in the
* contextMap to process later. Setting it to other returns
* a vanilla configuration(Source/Sink/Channel Configuration),
* which does basic syntactic validation. This object is not
* put into the map, so the context is retained which can be
* picked up - this is meant for older classes which don't
* implement ConfigurableComponent.
*/
while (iter.hasNext()) {
String channelName = iter.next();
Context channelContext = channelContextMap.get(channelName);
// Context exists in map.
if (channelContext != null) {
// Get the configuration object for the channel:
ChannelType chType = getKnownChannel(channelContext.getString(
BasicConfigurationConstants.CONFIG_TYPE));
boolean configSpecified = false;
String config = null;
// Not a known channel - cannot do specific validation to this channel
if (chType == null) {
config = channelContext.getString(BasicConfigurationConstants.CONFIG_CONFIG);
if (config == null || config.isEmpty()) {
config = "OTHER";
} else {
configSpecified = true;
}
} else {
config = chType.toString().toUpperCase(Locale.ENGLISH);
configSpecified = true;
} try {
conf =
(ChannelConfiguration) ComponentConfigurationFactory.create(
channelName, config, ComponentType.CHANNEL);
logger.debug("Created channel " + channelName);
if (conf != null) {
conf.configure(channelContext);
}
if ((configSpecified && conf.isNotFoundConfigClass()) ||
!configSpecified) {
newContextMap.put(channelName, channelContext);
} else if (configSpecified) {
channelConfigMap.put(channelName, conf);
}
if (conf != null) {
errorList.addAll(conf.getErrors());
}
} catch (ConfigurationException e) {
// Could not configure channel - skip it.
// No need to add to error list - already added before exception is
// thrown
if (conf != null) errorList.addAll(conf.getErrors());
iter.remove();
logger.warn("Could not configure channel " + channelName
+ " due to: " + e.getMessage(), e); }
} else {
iter.remove();
errorList.add(new FlumeConfigurationError(agentName, channelName,
FlumeConfigurationErrorType.CONFIG_ERROR, ErrorOrWarning.ERROR));
}
}
channelContextMap = newContextMap;
Set<String> tempchannelSet = new HashSet<String>();
tempchannelSet.addAll(channelConfigMap.keySet());
tempchannelSet.addAll(channelContextMap.keySet());
channelSet.retainAll(tempchannelSet);
return channelSet;
}

在validChannels中,根据配置文件中的channel的类型,创建ChannelConfiguration对象,然后插入到AgentConfiguration的configMap中;

到这里,一个完整的FlumeConfiguration对象已经完全加载好了;下面继续;












关于flume配置加载的更多相关文章

  1. 关于flume配置加载(二)

    为什么翻flume的代码,一方面是确实遇到了问题,另一方面是想翻一下flume的源码,看看有什么收获,现在收获还谈不上,因为要继续总结.不够已经够解决问题了,而且确实有好的代码,后续会继续慢慢分享,这 ...

  2. Java实现配置加载机制

    前言 现如今几乎大多数Java应用,例如我们耳熟能详的tomcat, struts2, netty…等等数都数不过来的软件,要满足通用性,都会提供配置文件供使用者定制功能. 甚至有一些例如Netty这 ...

  3. 异常处理之IIS配置加载出错

    问题详情:  一台部署在海外服务器,在管理IIS过程中,出现问题 There was an error when trying to connect. Do you want > to rety ...

  4. 深入理解 Laravel 中 config 配置加载原理

    Laravel的配置加载其实就是加载config目录下所有文件配置.如何过使用php artisan config:cache则会把加载的配置合并到一个配置文件中,下次请求就不会再去加载config目 ...

  5. Springboot学习01- 配置文件加载优先顺序和本地配置加载

    Springboot学习01-配置文件加载优先顺序和本地配置加载 1-项目内部配置文件加载优先顺序 spring boot 启动会扫描以下位置的application.properties或者appl ...

  6. Unity3d通用工具类之数据配置加载类-ini配置文件加载

    Unity3d通用工具类之数据配置加载类-ini配置文件加载 上次我们讲过xml文件的加载配置管理,今天我们换个配置文件,也是比较常见的配置文件.ini格式的数据. 按照国际管理先贴一张啥是.ini文 ...

  7. Unity3d通用工具类之数据配置加载类

    今天,我们来讲讲游戏中的数据配置加载. 什么是游戏数据加载呢?一般来说游戏中会有场景地图. 按照国际惯例,先贴一张游戏场景的地图: 在这张地图上,我们可以看到有很多正六边形,正六边形上有树木.岩石等. ...

  8. 3springboot:springboot配置文件(外部配置加载顺序、自动配置原理,@Conditional)

    1.外部配置加载顺序 SpringBoot也可以从以下位置加载配置: 优先级从高到低 高优先级的配置覆盖低优先级的配置,所有的配置会形成互补配置  1.命令行参数 所有的配置都可以在命令行上进行指定 ...

  9. Expressjs配置加载器

    有些东西就是操刀开干,没什么好解释的.... 问题引入 解决问题 直接上码 env.js index.js 使用方法 初始化 使用方法 写在最后 问题引入 大家都知道在日常的研发过程中,我们的程序会有 ...

随机推荐

  1. iOS中AutoLayer自动布局流程及相关方法

    关于UIView的Layer,IOS提供了三个方法: 1.layoutSubviews 在iOS5.1和之前的版本,此方法的缺省实现不会做任何事情(实现为空),iOS5.1之后(iOS6开始)的版本, ...

  2. 没有为扩展名.htm注册的生成提供程序,没有为扩展名.html注册的生成提供程序

    在web.config中添加下面这段 代码如下 <buildProviders> <add extension=".html" type="System ...

  3. [解决方案] pythonchallenge level 0

    http://www.pythonchallenge.com/pc/def/0.html 问题: 2^38 >>> 2**38 >>>274877906944L 输 ...

  4. 微软How old do I Look——初体验

    前段时间微软发布了一个可爱的网站how old.net,着实火了一把,全民体验魔镜魅力. 上传自己的靓照到http://www.how-old.net/,它就可以告诉你性别和年龄,大家还习惯称之为“颜 ...

  5. HTML&CSS学习心德

    学了html&css一周的时间,每天上课9小时,有空就看一下HTML+div+CSS视频,感觉还不错. 基本思路:从大的方面(整体结构)着手,将HTML的基本知识"解构"然 ...

  6. IntelliJ IDEA注册码

    1.打开IJ,help选项下的register 2. 选择Activation code 将注册码粘到内容框里,点击ok即可 43B4A73YYJ-eyJsaWNlbnNlSWQiOiI0M0I0QT ...

  7. Java(六)——抽奖系统

     总体思路: 将编号加入ArrayList动态数组中,利用集合的静态方法Collections.shuffle() 乱序集合中的元素从而获得随机数,remove删除已抽编号  代码如下: import ...

  8. Unity3D-坐标转换笔记

    Transform.TransformPoint 作用 : 将一个点从以自身为坐标系的本地坐标转换成世界坐标 Transform.InverseTransformPoint 作用 : 将一个点从世界坐 ...

  9. java工厂-积木系列

    这里记录一个例子,工厂模式的理论就不扯淡了. 遇到的问题:支付方式有很多种,比如微信支付 支付宝支付 银联支付 等等.我们在在实现的时候发现他么的流程上是相似的,以及每个方式都有大量的个性配置,在实例 ...

  10. grafana+graphit安装笔记

    OS:MAC 10.11查看测试线运行demo请访问http://10.103.13.101:3000/dashboard/db/graphite-carbon-metrics?editorTab=O ...