flume源码分析1--启动

Flume的程序入口是org.apache.flume.node.Application#main

进入后会先进行命令行参数的解析及核对,使用的组件是org.apache.commons.cli。还是很好用的。

会从参数中获取isZkConfigured及reload两个参数,isZkConfigured是指是否使用zookeeper来存储flume任务的配置,reload是指当flume作业的配置改变了以后是否重新启动程序来加载最新的参数。默认我们不使用zookeeper,而是采用文件来存储:

然后根据reload的不同,启动方式有所不同,为false的时候就直接启动,为true的时候就监听文件的改变,一旦有改变就重新启动加载最新的配置。这里使用了google的一个组件EventBus :

        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());
        }

假如是reload模式,

会构造一个configurationProvider ,注意这个configurationProvider 实现了LifecycleAware接口,那么什么是LifecycleAware?flume中把任意有生命周期(有空闲、启动、停止等状态)的组件都看作LifecycleAware,比如sink、source、channel等。

然后据此会构造一个application,并注册监听eventBus。

然后调用application.start(),

  public synchronized void start() {
    for (LifecycleAware component : components) {
      supervisor.supervise(component,
          new SupervisorPolicy.AlwaysRestartPolicy(), LifecycleState.START);
    }
  }

这里就是把每个组件交给监护人去监护。下面分析下这个监护人LifecycleSupervisor supervisor

需要注意的是这个监护人自身也是有生命周期的,也实现了LifecycleAware。

LifecycleSupervisor 有个静态内部类Supervisoree记录监护策略、期望状态。

LifecycleSupervisor 还有个静态内部类MonitorRunnable实现Runnable接口,用于根据组件的期望状态去调用组件的相应的方法。

所以org.apache.flume.lifecycle.LifecycleSupervisor#supervise方法主要就是做一些必要的检查,然后将监护信息封装进MonitorRunnable对象,然后启动一个线程去运行它。至于具体怎么运行逻辑都封装在MonitorRunnable里面。

这里为什么使用静态内部类?如果一段逻辑必须要封装独立出去,否则违反类的单一原则,但这个类又只被当前类使用,那么可以考虑内部类,如果这个内部类不访问原类的任何成员变量,那么可以考虑使用静态内部类。

使用内部类目的主要是封装更好,更好维护。

在MonitorRunnable使用这种方法保证组件在多线程环境下状态切换的安全进行。这样我们就不用在LifecycleAware类里面使用synchronized 修饰每个方法了。

synchronized (lifecycleAware) {
.....
case START:lifecycleAware.start
.....
case STOP:lifecycleAware.stop
.....
}

MonitorRunnable使用ScheduledThreadPoolExecutor定时调度运行,来确保每隔几秒钟就对组件来进行一次温暖的监护,确保其位于期望的状态。

到目前为止,我们的组件只有一个,就是上面的configurationProvider ,通过上面的流程我们把它启动了,那他的start方法都做了什么呢?

  @Override
  public void start() {
    LOGGER.info("Configuration provider starting");

    Preconditions.checkState(file != null,
        "The parameter file must not be null");

    executorService = Executors.newSingleThreadScheduledExecutor(
            new ThreadFactoryBuilder().setNameFormat("conf-file-poller-%d")
                .build());

    FileWatcherRunnable fileWatcherRunnable =
        new FileWatcherRunnable(file, counterGroup);

    executorService.scheduleWithFixedDelay(fileWatcherRunnable, 0, interval,
        TimeUnit.SECONDS);

    lifecycleState = LifecycleState.START;

    LOGGER.debug("Configuration provider started");
  }

可以看到,在start时候,它起了一个周期调用线程executorService,这个周期调用线程又回每隔30s调用fileWatcherRunnable这个配置文件监控线程,在FileWatcherRunnable这里面,会去监听flume配置文件的变化,如果修改时间发生变化,eventBus会说我感兴趣的事件发生了!即eventBus.post(getConfiguration())

    @Override
    public void run() {
      LOGGER.debug("Checking file:{} for changes", file);

      counterGroup.incrementAndGet("file.checks");

      long lastModified = file.lastModified();

      if (lastModified > lastChange) {
        LOGGER.info("Reloading configuration file:{}", file);

        counterGroup.incrementAndGet("file.loads");

        lastChange = lastModified;

        try {
          eventBus.post(getConfiguration());
        } catch (Exception e) {
          LOGGER.error("Failed to load configuration data. Exception follows.",
              e);
        } catch (NoClassDefFoundError e) {
          LOGGER.error("Failed to start agent because dependencies were not " +
              "found in classpath. Error follows.", e);
        } catch (Throwable t) {
          // caught because the caller does not handle or log Throwables
          LOGGER.error("Unhandled error", t);
        }
      }
    }

在application中,用注解@Subscribe标明的方法就告诉了我们,事件发生后,如何处理

  @Subscribe
  public synchronized void handleConfigurationEvent(MaterializedConfiguration conf) {
    stopAllComponents();
    startAllComponents(conf);
  }

到这里为止,讲清楚了如果启动flume时候配置了no-reload-con参数,flume就会动态加载配置文件,默认每30秒检查一次配置文件,如果有修改,会重启所有的components;如果没有配置该参数,则只会启动一次。

猜你喜欢

转载自blog.csdn.net/qq_24365213/article/details/79817118
今日推荐