Flume NG源码分析(二)支持运行时动态修改配置的配置模块

本文介绍FlumeNG如何通过PollingPropertiesFileConfigurationProvider实现在运行时动态修改配置文件并实时生效的功能。主要包括:1) 使用FileWatcherRunnable监控配置文件变化;2) 利用Guava EventBus发布配置变更事件,并由Application监听这些事件来更新内部状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在上一篇中讲了Flume NG配置模块基本的接口的类,PropertiesConfigurationProvider提供了基于properties配置文件的静态配置的能力,这篇细说一下PollingPropertiesFileConfigurationProvider提供的运行时动态修改配置并生效的能力。


要实现动态修改配置文件并生效,主要有两个待实现的功能

1. 观察配置文件是否修改

2. 如果修改,将修改的内容通知给观察者


对于第一点,监控配置文件是否修改,Flume NG定义了一个FileWatcherRunnable对象来监控配置文件,启动了一个单独的线程采用定时轮询的方式来监控,轮询频率是30毫秒一次,比较file.lastModified属性与lastChange时间戳,当file.lastModified > lastChange时表示文件被修改

public class FileWatcherRunnable implements Runnable {

    private final File file;
    private final CounterGroup counterGroup;

    private long lastChange;

    public FileWatcherRunnable(File file, CounterGroup counterGroup) {
      super();
      this.file = file;
      this.counterGroup = counterGroup;
      this.lastChange = 0L;
    }

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

// PollingPropertiesFileConfigurationProvider.start()启动一个单独的线程来监控properties配置文件
 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");
  }

对于第二点,利用Guava EventBus提供的发布订阅模式机制,将配置修改封装成事件传递给Application,来重新加载配置

// FileWatcherRunnable.run方法 发布配置修改的事件
   eventBus.post(getConfiguration());

// Application.main方法来注册事件订阅
      Application application;
      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);
      }


// Application类采用@Subscribe标注来定义订阅方法,即配置修改后会执行handleConfigurationEvent方法,这个方法是线程安全的

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



SpoolDirectorySource 是 Flume 框架中的一个 Source 组件,用于监控指定目录下的文件,当有新文件出现,将文件内容读取并发送到 Flume 的 Channel 中供后续处理。 使用 SpoolDirectorySource 需要配置以下参数: - spoolDir:监控的目录路径。 - fileHeader:文件头信息。 - fileSuffix:文件后缀名。 - batchSize:每次读取文件的批量大小。 - ignorePattern:忽略的文件匹配模式。 - deserializer:文件内容的反序列化方式。 SpoolDirectorySource 的工作原理如下: - 不断轮询指定目录下的文件列表,如果有新文件出现,则将文件信息加入到待处理列表中。 - 从待处理列表中取出文件信息,读取文件内容并发送到 Channel 中。 - 处理完成后将文件信息从待处理列表中删除。 SpoolDirectorySource 的源码分析: SpoolDirectorySource 的源码位于 flume-ng-core 模块中的 org.apache.flume.source 目录下,主要类包括 SpoolDirectorySource 和 SpoolDirectoryRunnable。 SpoolDirectorySource 继承自 AbstractSource,重写了 doConfigure、doStart 和 doStop 方法,其中 doStart 方法启动了一个新的线程来监控指定目录下的文件。具体实现可参考以下代码: ```java @Override protected void doStart() throws FlumeException { logger.info("SpoolDirectorySource source starting with directory:{}", spoolDirectory); try { directory = new ReliableSpoolingFileEventReader.Builder() .spoolDirectory(spoolDirectory) .deserializer(deserializer) .checkpointDir(new File(spoolDirectory + ".checkpoint")) .ignorePattern(ignorePattern) .trackerDir(new File(spoolDirectory + ".tracker")) .annotateFileName(fileHeader) .fileNameHeader(fileHeader) .consumeOrder(consumeOrder) .bufferSize(bufferSize) .fileSuffix(fileSuffix) .build(); } catch (IOException ioe) { throw new FlumeException("Error instantiating spooling event parser", ioe); } executor = Executors.newSingleThreadExecutor(); runner = new SpoolDirectoryRunnable(directory, sourceCounter); executor.execute(runner); super.doStart(); logger.debug("SpoolDirectorySource source started"); } ``` SpoolDirectoryRunnable 实现了 Runnable 接口,实现了 SpoolDirectorySource 监控目录下文件的具体逻辑。具体实现可参考以下代码: ```java @Override public void run() { logger.debug("SpoolDirectoryRunnable starts"); while (!Thread.interrupted()) { try { List<Event> events = reader.readEvents(batchSize); if (events.isEmpty()) { continue; } sourceCounter.addToEventReceivedCount(events.size()); source.getChannelProcessor().processEventBatch(events); reader.commit(); sourceCounter.addToEventAcceptedCount(events.size()); } catch (Throwable t) { logger.error("Unable to read events from directory " + reader.getSpoolDirectory(), t); if (t instanceof Error) { throw (Error) t; } } } try { reader.close(); } catch (IOException e) { logger.error("Error while closing the directory reader", e); } } ``` 以上代码中,reader.readEvents(batchSize) 会读取 batchSize 个文件,并将文件内容转化成 Event 对象,存储在 events 列表中;source.getChannelProcessor().processEventBatch(events) 将 events 发送到 Channel 中;reader.commit() 会提交当前读取的文件,避免重复读取;sourceCounter.addToEventReceivedCount 和 sourceCounter.addToEventAcceptedCount 用于计数。 综上所述,SpoolDirectorySource 的工作原理是通过一个新的线程不断轮询指定目录下的文件,将新文件内容读取并转化成 Event 对象发送到 Channel 中,实现了 Flume 对文件的监控和实处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值