Apache Flume1.9.0源码走读之flume agent启动流程
一、入口
找FLume启动入口最简单的办法,当然就是查看启动脚本。可以随便下载一个flume的tar包,在bin目录下查看flume-ng脚本。
这些就是flume的启动类,其中FlUME_AGNET_CLASS变量代表的就是flume-ng启动时的启动类。
入口类找到了,就先来看看当启动flume的时候都启动了哪些组件,这些组件的作用都是什么。
二、主方法简述
2.1 参数初始化
这一行截止,上面的部分是相关启动参数的初始化部分,下面是运行环境的部署
2.1 配置文件初始化
if (isZkConfigured) { //如果配置文件的存储是使用zk // get options String zkConnectionStr = commandLine.getOptionValue('z'); String baseZkPath = commandLine.getOptionValue('p'); if (reload) { //如果需要重新加载配置文件 EventBus eventBus = new EventBus(agentName + "-event-bus"); List<LifecycleAware> components = Lists.newArrayList(); PollingZooKeeperConfigurationProvider zookeeperConfigurationProvider = new PollingZooKeeperConfigurationProvider( agentName, zkConnectionStr, baseZkPath, eventBus); components.add(zookeeperConfigurationProvider); application = new Application(components); eventBus.register(application); } else { //不需要重新加载配置文件 StaticZooKeeperConfigurationProvider zookeeperConfigurationProvider = new StaticZooKeeperConfigurationProvider( agentName, zkConnectionStr, baseZkPath); application = new Application(); application.handleConfigurationEvent(zookeeperConfigurationProvider.getConfiguration()); } } else { //使用本地文件来存储conf文件 File configurationFile = new File(commandLine.getOptionValue('f')); /* * The following is to ensure that by default the agent will fail on * startup if the file does not exist. */ if (!configurationFile.exists()) { // If command line invocation, then need to fail fast if (System.getProperty(Constants.SYSPROP_CALLED_FROM_SERVICE) == null) { String path = configurationFile.getPath(); try { path = configurationFile.getCanonicalPath(); } catch (IOException ex) { logger.error("Failed to read canonical path for file: " + path, ex); } throw new ParseException( "The specified configuration file does not exist: " + path); } } List<LifecycleAware> components = Lists.newArrayList(); if (reload) { EventBus eventBus = new EventBus(agentName + "-event-bus"); PollingPropertiesFileConfigurationProvider configurationProvider = new PollingPropertiesFileConfigurationProvider( agentName, configurationFile, eventBus, 30); components.add(configurationProvider); application = new Application(components); eventBus.register(application); } else { PropertiesFileConfigurationProvider configurationProvider = new PropertiesFileConfigurationProvider(agentName, configurationFile); application = new Application(); application.handleConfigurationEvent(configurationProvider.getConfiguration()); } } application.start();
三、配置文件加载
加载Source,Channel,Sink
新版本的flume 1.9.0可以使用zk来进行配置文件的管理,那么,当加载组件的时候就有那么几种方式
- 当配置文件存储在zk时
- 当配置文件需要reload时
- 当配置文件不需要reload时
- 当配置文件存储在本地时
- 当配置文件需要reload时
- 当配置文件不需要reload时
判断逻辑的主干还是在main方法中,这里不再重复引用。主要看一下当上面的情况发生时具体的加载逻辑是什么样的。
3.1 当配置文件存储在zk时并且配置文件需要reload
这里需要提一句的是,是否存储在zk需要看是否配置了相应的zk连接,是否需要重新加载,要看是否配置了一个参数no-reload-conf,如果配置了当前参数,则不需要重新加载。需要注意的时,配置和不配置no-reload-conf区别很大。当配置了no-reload-conf这个参数的时候,意味这flume将不会监听配置文件的动态变化,如果想变更配置,只能手动重启flume。而配置了no-reload-conf这个参数,flume会默认每隔1s去判断配置文件是否发生变更,以达到更新配置文件的目的。
boolean isZkConfigured = false; if (commandLine.hasOption('z') || commandLine.hasOption("zkConnString")) { isZkConfigured = true; }
boolean reload = !commandLine.hasOption("no-reload-conf");
以下是具体的调用逻辑
//如果需要重新加载配置文件 EventBus eventBus = new EventBus(agentName + "-event-bus"); List<LifecycleAware> components = Lists.newArrayList(); //注册当前配置的Provider PollingZooKeeperConfigurationProvider zookeeperConfigurationProvider = new PollingZooKeeperConfigurationProvider( agentName, zkConnectionStr, baseZkPath, eventBus); //将provider加入到一个数组中,components是一个arrayList集合 components.add(zookeeperConfigurationProvider); //将组件重新注册 application = new Application(components); eventBus.register(application);
在这里FLume引用了一个外部的组件EventBus,对于这种不知道的东西怎么办,看注释
一个轻量级的发布-订阅的库,那么flume到底是用他来干了什么呢,接着向下看,至于EventBus到底是怎样实现的,它有哪些优势呢,这个之后再说。
ps:其实在这一想,发布-订阅,难道flume的消息队列就是用这个来实现的?其实不是,flume只是用它来通知加载配置文件
看一下PollingZooKeeperConfigurationProvider这个对象
它实现了LifecycleAware接口,这是FLume内部控制组件生命周期的统一接口,里面就三个方法
start 开始
stop 结束
getLifecycleState 获取组件状态
看里面的方法实现是用来更新Flume配置文件的
@Override public void start() { LOGGER.debug("Starting..."); try { client.start(); try { agentNodeCache = new NodeCache(client, basePath + "/" + getAgentName()); agentNodeCache.start(); agentNodeCache.getListenable().addListener(new NodeCacheListener() { @Override public void nodeChanged() throws Exception { refreshConfiguration(); } }); } catch (Exception e) { client.close(); throw e; } } catch (Exception e) { lifecycleState = LifecycleState.ERROR; if (e instanceof RuntimeException) { throw (RuntimeException) e; } else { throw new FlumeException(e); } } lifecycleState = LifecycleState.START; } private void refreshConfiguration() throws IOException { LOGGER.info("Refreshing configuration from ZooKeeper"); byte[] data = null; ChildData childData = agentNodeCache.getCurrentData(); if (childData != null) { data = childData.getData(); } //从zk读取到的内容是字节流的方式,在这将其转化为Flume内部的配置类 flumeConfiguration = configFromBytes(data); eventBus.post(getConfiguration()); }
可以看到的是在start方法里面,他获取了相应agent在zk下的配置文件并注册了监听事件(当路径下内容发生变更时会触发调用)。作用就是当该路径下的内容发生变更时,会调用refreshConfiguration对agent节点的配置进行更新以达到热部署的目的。最终要把新的配置文件更新在eventBus中。
3.2 当配置文件存储在zk时并且配置文件不需要reload
StaticZooKeeperConfigurationProvider zookeeperConfigurationProvider =
new StaticZooKeeperConfigurationProvider(
agentName, zkConnectionStr, baseZkPath);
application = new Application();
application.handleConfigurationEvent(zookeeperConfigurationProvider.getConfiguration());
StaticZooKeeperConfigurationProvider就是还是读取配置文件,通过它内部的getFlumeConfiguration方法
之后就是创建一个Application,然后去处理配置文件。
@Subscribe public void handleConfigurationEvent(MaterializedConfiguration conf) { try { lifecycleLock.lockInterruptibly(); stopAllComponents(); startAllComponents(conf); } catch (InterruptedException e) { logger.info("Interrupted while trying to handle configuration event"); return; } finally { // If interrupted while trying to lock, we don't own the lock, so must not attempt to unlock if (lifecycleLock.isHeldByCurrentThread()) { lifecycleLock.unlock(); } } }
处理的过程,就是先将所有组件停掉,然后按照新的配置文件重新启动。
3.3 回头再看EventBus
它的作用就是用来定时的调度更新配置文件,所以,当不配置no-reload-conf参数时,就需要注册一个EventBus事件,当配置文件发生变更时,通知FLume进行重启等操作。
3.4 当配置文件存储在本地时并且配置文件需要reload
这部分就很好理解了,过程跟上面的一样,只不过Flume会从本地读取配置文件而不是zk
EventBus eventBus = new EventBus(agentName + "-event-bus"); PollingPropertiesFileConfigurationProvider configurationProvider = new PollingPropertiesFileConfigurationProvider( agentName, configurationFile, eventBus, 30); components.add(configurationProvider); application = new Application(components); eventBus.register(application);
3.5 当配置文件存储在本地时并且配置文件不需要reload
PropertiesFileConfigurationProvider configurationProvider =
new PropertiesFileConfigurationProvider(agentName, configurationFile);
application = new Application();
application.handleConfigurationEvent(configurationProvider.getConfiguration());
四、启动
接下来终于可以启动了,就简单的一句话
application.start();
具体的逻辑,下回分解。。。

浙公网安备 33010602011771号