從bin/flume 這個shell指令碼可以看到Flume的起始於org.apache.flume.node.Application類,這是flume的main函數所在。
main方法首先會先解析shell命令,如果指定的設定檔不存在就甩出異常。
根據命令中含有"no-reload-conf"參數,決定採用那種載入設定檔方式:一、沒有此參數,會動態載入設定檔,預設每30秒載入一次設定檔,因此可以動態修改設定檔;二、有此參數,則只在啟動時載入一次設定檔。實現動態載入功能採用了發布訂閱模式,使用guava中的EventBus實現。
EventBus eventBus = new EventBus(agentName + "-event-bus"); PollingPropertiesFileConfigurationProvider configurationProvider = new PollingPropertiesFileConfigurationProvider(agentName, configurationFile, eventBus, 30); //這裡是發布事件的類,這裡的30則是動態載入設定檔時間間隔,單位是s components.add(configurationProvider); application = new Application(components); eventBus.register(application); //將訂閱類註冊到Bus中
訂閱類是application = new Application(components);發布代碼在PollingPropertiesFileConfigurationProvider中的FileWatcherRunnable.run方法中。在這隻是先構建一個PollingPropertiesFileConfigurationProvider對象,PollingPropertiesFileConfigurationProvider extends PropertiesFileConfigurationProvider implements LifecycleAware,繼續跟蹤PropertiesFileConfigurationProvider extends AbstractConfigurationProvider,再跟蹤AbstractConfigurationProvider implements ConfigurationProvider可以看到這些類的構造方法都是初始化,AbstractConfigurationProvid的構造方法初始化了sink、channel、source的工廠類。
Application.handleConfigurationEvent(MaterializedConfiguration conf)有@Subscribe註解,是訂閱者法,當eventBus.post(MaterializedConfiguration conf)執行時,會觸發執行handleConfigurationEvent方法。
new Application(components)時,會構建一個對象supervisor = new LifecycleSupervisor()會啟動10個線程用來執行設定檔中的各個組件,並監控組件的整個運行過程。
application.start()方法會啟動設定檔的載入過程supervisor.supervise(component, new SupervisorPolicy.AlwaysRestartPolicy(), LifecycleState.START); //LifecycleState.START開始運行,在這的component就是上面的PollingPropertiesFileConfigurationProvider對象。supervise方法會對component建立一個MonitorRunnable進程,並放入預設有10個線程的monitorService去執行
Supervisoree process = new Supervisoree(); process.status = new Status(); process.policy = policy; process.status.desiredState = desiredState; process.status.error = false; MonitorRunnable monitorRunnable = new MonitorRunnable(); monitorRunnable.lifecycleAware = lifecycleAware;//組件 monitorRunnable.supervisoree = process; monitorRunnable.monitorService = monitorService; supervisedProcesses.put(lifecycleAware, process); //建立並執行一個在給定初始延遲後首次啟用的定期操作,隨後,在每一次執行終止和下一次執行開始之間都存在給定的延遲。如果任務的任一執行遇到異常,就會取消後續執行。 ScheduledFuture<?> future = monitorService.scheduleWithFixedDelay( monitorRunnable, 0, 3, TimeUnit.SECONDS); //啟動MonitorRunnable,結束之後3秒再重新啟動,可以用於重試 monitorFutures.put(lifecycleAware, future);
看MonitorRunnable類,其run方法主要是根據supervisoree.status.desiredState的值執行對應的操作。這裡的lifecycleAware就是上面supervise方法中的component,lifecycleAware在構造之初將lifecycleState=IDLE,application.start()方法通過supervisor.supervise方法將supervisoree.status.desiredState=START。所以在run方法中會執行lifecycleAware.start(),也就是PollingPropertiesFileConfigurationProvider.start()方法。
PollingPropertiesFileConfigurationProvider.start()方法會啟動一個單線程FileWatcherRunnable每隔30s去載入一次設定檔(如果設定檔有修改):eventBus.post(getConfiguration())。getConfiguration()是AbstractConfigurationProvider.getConfiguration()這個方法解析了設定檔擷取了所有組件及其配置屬性。這個方法較為複雜,放在後續再講解。
待eventBus.post(getConfiguration())之後會觸發Application.handleConfigurationEvent方法:
@Subscribe public synchronized void handleConfigurationEvent(MaterializedConfiguration conf) { stopAllComponents(); startAllComponents(conf); }
stopAllComponents()方法會依次stop各個組件的運行,順序是:source、sink、channel。之所以有順序是因為:一、source是不停的讀資料放入channel的;二、sink是不停的從channel拿資料的,channel兩頭都在使用應該最後停止,停止向channel發送資料後sink停止才不會丟資料。stop是通過supervisor.unsupervise方法來完成的。
startAllComponents(conf)是啟動各個組件的,順序正好和stopAllComponents()停止順序相反,相信大夥很容易理解。是通過supervisor.supervise啟動組件的。另外需要注意的是啟動channel組件後需要等待一定時間,是為了讓所有channel全部啟動。
另外為什麼要先stop再start呢。因為考慮到要動態載入設定檔啊,載入設定檔後就需要重新啟動所有組件,所以先停止所有的,再重新啟動所有的。
main方法的最後還有一個鉤子函數Runtime.getRuntime().addShutdownHook,主要是用來進行記憶體清理、對象銷毀等操作。