今天我们通过阅读Flume-NG的源码来看看Flume的整个启动流程,废话不多说,翠花,上源码!!

1 主类也是启动类

在这里我贴出Application中跟启动有关的方法,其他你们可以自己看源码,毕竟源码解析解的是思路。

org.apache.flume.node.Application

  1. /*主函数*/
  2. public static void main(String[] args) {
  3. try {
  4. boolean isZkConfigured = false;
  5. Options options = new Options();
  6. Option option = new Option("n", "name", true, "the name of this agent");
  7. option.setRequired(true);
  8. options.addOption(option);
  9. option = new Option("f", "conf-file", true,
  10. "specify a config file (required if -z missing)");
  11. option.setRequired(false);
  12. options.addOption(option);
  13. option = new Option(null, "no-reload-conf", false,
  14. "do not reload config file if changed");
  15. options.addOption(option);
  16. // Options for Zookeeper
  17. option = new Option("z", "zkConnString", true,
  18. "specify the ZooKeeper connection to use (required if -f missing)");
  19. option.setRequired(false);
  20. options.addOption(option);
  21. option = new Option("p", "zkBasePath", true,
  22. "specify the base path in ZooKeeper for agent configs");
  23. option.setRequired(false);
  24. options.addOption(option);
  25. option = new Option("h", "help", false, "display help text");
  26. options.addOption(option);
  27. CommandLineParser parser = new GnuParser();
  28. CommandLine commandLine = parser.parse(options, args);
  29. if (commandLine.hasOption('h')) {
  30. new HelpFormatter().printHelp("flume-ng agent", options, true);
  31. return;
  32. }
  33. String agentName = commandLine.getOptionValue('n');
  34. boolean reload = !commandLine.hasOption("no-reload-conf");
  35. if (commandLine.hasOption('z') || commandLine.hasOption("zkConnString")) {
  36. isZkConfigured = true;
  37. }
  38. Application application = null;
  39. if (isZkConfigured) {
  40. // get options
  41. String zkConnectionStr = commandLine.getOptionValue('z');
  42. String baseZkPath = commandLine.getOptionValue('p');
  43. if (reload) {
  44. EventBus eventBus = new EventBus(agentName + "-event-bus");
  45. List<LifecycleAware> components = Lists.newArrayList();
  46. PollingZooKeeperConfigurationProvider zookeeperConfigurationProvider =
  47. new PollingZooKeeperConfigurationProvider(
  48. agentName, zkConnectionStr, baseZkPath, eventBus);
  49. components.add(zookeeperConfigurationProvider);
  50. application = new Application(components);
  51. eventBus.register(application);
  52. } else {
  53. StaticZooKeeperConfigurationProvider zookeeperConfigurationProvider =
  54. new StaticZooKeeperConfigurationProvider(
  55. agentName, zkConnectionStr, baseZkPath);
  56. application = new Application();
  57. application.handleConfigurationEvent(zookeeperConfigurationProvider.getConfiguration());
  58. }
  59. } else {
  60. File configurationFile = new File(commandLine.getOptionValue('f'));
  61. /*
  62. * 确保当文件不存在时agent会启动失败
  63. */
  64. if (!configurationFile.exists()) {
  65. // If command line invocation, then need to fail fast
  66. if (System.getProperty(Constants.SYSPROP_CALLED_FROM_SERVICE) ==
  67. null) {
  68. String path = configurationFile.getPath();
  69. try {
  70. path = configurationFile.getCanonicalPath();
  71. } catch (IOException ex) {
  72. logger.error("Failed to read canonical path for file: " + path,
  73. ex);
  74. }
  75. throw new ParseException(
  76. "The specified configuration file does not exist: " + path);
  77. }
  78. }
  79. List<LifecycleAware> components = Lists.newArrayList();
  80. if (reload) {
  81. EventBus eventBus = new EventBus(agentName + "-event-bus");
  82. PollingPropertiesFileConfigurationProvider configurationProvider =
  83. new PollingPropertiesFileConfigurationProvider(
  84. agentName, configurationFile, eventBus, 30);
  85. components.add(configurationProvider);
  86. application = new Application(components);
  87. eventBus.register(application);
  88. } else {
  89. PropertiesFileConfigurationProvider configurationProvider =
  90. new PropertiesFileConfigurationProvider(agentName, configurationFile);
  91. application = new Application();
  92. application.handleConfigurationEvent(configurationProvider.getConfiguration());
  93. }
  94. }
  95. application.start();
  96. final Application appReference = application;
  97. Runtime.getRuntime().addShutdownHook(new Thread("agent-shutdown-hook") {
  98. @Override
  99. public void run() {
  100. appReference.stop();
  101. }
  102. });
  103. } catch (Exception e) {
  104. logger.error("A fatal error occurred while running. Exception follows.", e);
  105. }
  106. }
  107. /*启动方法*/
  108. public synchronized void start() {
  109. for (LifecycleAware component : components) {
  110. supervisor.supervise(component,
  111. new SupervisorPolicy.AlwaysRestartPolicy(), LifecycleState.START);
  112. }
  113. }
  114. /*响应EventBus的方法*/
  115. @Subscribe
  116. public synchronized void handleConfigurationEvent(MaterializedConfiguration conf) {
  117. stopAllComponents();
  118. startAllComponents(conf);
  119. }
  120. /*停止方法*/
  121. public synchronized void stop() {
  122. supervisor.stop();
  123. if (monitorServer != null) {
  124. monitorServer.stop();
  125. }
  126. }
  127. /*停止所有组件*/
  128. private void stopAllComponents() {
  129. if (this.materializedConfiguration != null) {
  130. logger.info("Shutting down configuration: {}", this.materializedConfiguration);
  131. for (Entry<String, SourceRunner> entry :
  132. this.materializedConfiguration.getSourceRunners().entrySet()) {
  133. try {
  134. logger.info("Stopping Source " + entry.getKey());
  135. supervisor.unsupervise(entry.getValue());
  136. } catch (Exception e) {
  137. logger.error("Error while stopping {}", entry.getValue(), e);
  138. }
  139. }
  140. for (Entry<String, SinkRunner> entry :
  141. this.materializedConfiguration.getSinkRunners().entrySet()) {
  142. try {
  143. logger.info("Stopping Sink " + entry.getKey());
  144. supervisor.unsupervise(entry.getValue());
  145. } catch (Exception e) {
  146. logger.error("Error while stopping {}", entry.getValue(), e);
  147. }
  148. }
  149. for (Entry<String, Channel> entry :
  150. this.materializedConfiguration.getChannels().entrySet()) {
  151. try {
  152. logger.info("Stopping Channel " + entry.getKey());
  153. supervisor.unsupervise(entry.getValue());
  154. } catch (Exception e) {
  155. logger.error("Error while stopping {}", entry.getValue(), e);
  156. }
  157. }
  158. }
  159. if (monitorServer != null) {
  160. monitorServer.stop();
  161. }
  162. }
  163. /*启动所有组件*/
  164. private void startAllComponents(MaterializedConfiguration materializedConfiguration) {
  165. logger.info("Starting new configuration:{}", materializedConfiguration);
  166. this.materializedConfiguration = materializedConfiguration;
  167. /*启动Channel*/
  168. for (Entry<String, Channel> entry :
  169. materializedConfiguration.getChannels().entrySet()) {
  170. try {
  171. logger.info("Starting Channel " + entry.getKey());
  172. supervisor.supervise(entry.getValue(),
  173. new SupervisorPolicy.AlwaysRestartPolicy(), LifecycleState.START);
  174. } catch (Exception e) {
  175. logger.error("Error while starting {}", entry.getValue(), e);
  176. }
  177. }
  178. /*
  179. * Wait for all channels to start.
  180. */
  181. for (Channel ch : materializedConfiguration.getChannels().values()) {
  182. while (ch.getLifecycleState() != LifecycleState.START
  183. && !supervisor.isComponentInErrorState(ch)) {
  184. try {
  185. logger.info("Waiting for channel: " + ch.getName() +
  186. " to start. Sleeping for 500 ms");
  187. Thread.sleep(500);
  188. } catch (InterruptedException e) {
  189. logger.error("Interrupted while waiting for channel to start.", e);
  190. Throwables.propagate(e);
  191. }
  192. }
  193. }
  194. /*启动SinkRunner*/
  195. for (Entry<String, SinkRunner> entry : materializedConfiguration.getSinkRunners().entrySet()) {
  196. try {
  197. logger.info("Starting Sink " + entry.getKey());
  198. supervisor.supervise(entry.getValue(),
  199. new SupervisorPolicy.AlwaysRestartPolicy(), LifecycleState.START);
  200. } catch (Exception e) {
  201. logger.error("Error while starting {}", entry.getValue(), e);
  202. }
  203. }
  204. /*启动SourceRunner*/
  205. for (Entry<String, SourceRunner> entry :
  206. materializedConfiguration.getSourceRunners().entrySet()) {
  207. try {
  208. logger.info("Starting Source " + entry.getKey());
  209. supervisor.supervise(entry.getValue(),
  210. new SupervisorPolicy.AlwaysRestartPolicy(), LifecycleState.START);
  211. } catch (Exception e) {
  212. logger.error("Error while starting {}", entry.getValue(), e);
  213. }
  214. }
  215. this.loadMonitoring();
  216. }

1)40行:检查Shell命令,如果含有'h'字符则返回帮助命令

2)52行:判断命令行中是否有ZooKeeper相关信息,如果有则获取zookeeper相关信息,通过PollingZooKeeperConfigurationProvider或者StaticZooKeeperConfigurationProvider 去调用存储在zookeeper中的配置信息,如果没有的话则调用PollingPropertiesFileConfigurationProvider或者PropertiesFileConfigurationProvider去指定路径读取配置文件进行加载。

3)57行和96行:无论从zookeeper中还是file中获取配置文件,都需要判断命令行中是否有“no-reload-conf”,根据reload = !commandLine.hasOption("no-reload-conf")获得结果,如果reload为真,那么程序会每隔30秒检查一次配置文件,如果检查到配置文件发生变化则关闭原有组件,重新启动,这部分细节在XXProvider中体现。

4)如果是动态轮询的方式,那么会将application注册到EventBus中,然后调用Application类中的start()来启动components,如果是只加载一次的话,则使用handleConfigurationEvent()来启动。handleConfigurationEvent()同时也是EventBus的回调函数,当eventbus执行post时,该方法就会被调用。

5)所有Application的start()实际上调用了XXProvider中的start(),来执行真正组件的启动。

6)无论是reload还是一次加载,我们可以看到的是都是调用handleConfigurationEvent()来执行,该方法最终是调用stopAllComponents()和startAllComponent来完成的

7)stopAllComponent我们就不说了,重点来看看startAllComponents,它的启动顺序是有讲究的,先启动channels,再启动SinkRunner,最后启动SourceRunner。

这里面有两个问题:

1)启动顺序的问题:为什么要先启动channel,因为sink和source的连接纽带就是channel,而且sink和source的启动都要判断是否存在连接channel,所以channel要先启动,至于sink比source先启动,我认为应该是sink作为最后消费者,而source作为数据来源,那么防止数据堆积在channel中,所以先启动消费者,再启动生产者,需求促进供给嘛,瞎扯的。

2)SourceRunner和SinkRunner是什么玩意,source和sink哪里去了,这里就简单说下,SourceRunner和SinkRunner是用于启动source和sink的驱动类,我们在下一篇source、sink和channel的分析中再来细说

2 XXProvider

该类是启动组件时主要的类,这里就以PollingPropertiesFileConfigurationProvider举例说明,上代码

  1. public class PollingPropertiesFileConfigurationProvider
  2. extends PropertiesFileConfigurationProvider
  3. implements LifecycleAware {
  4. private static final Logger LOGGER =
  5. LoggerFactory.getLogger(PollingPropertiesFileConfigurationProvider.class);
  6. private final EventBus eventBus;
  7. private final File file;
  8. private final int interval;
  9. private final CounterGroup counterGroup;
  10. private LifecycleState lifecycleState;
  11. private ScheduledExecutorService executorService;
  12. public PollingPropertiesFileConfigurationProvider(String agentName,
  13. File file, EventBus eventBus, int interval) {
  14. super(agentName, file);
  15. this.eventBus = eventBus;
  16. this.file = file;
  17. this.interval = interval;
  18. counterGroup = new CounterGroup();
  19. lifecycleState = LifecycleState.IDLE;
  20. }
  21. @Override
  22. public void start() {
  23. LOGGER.info("Configuration provider starting");
  24. Preconditions.checkState(file != null,
  25. "The parameter file must not be null");
  26. executorService = Executors.newSingleThreadScheduledExecutor(
  27. new ThreadFactoryBuilder().setNameFormat("conf-file-poller-%d")
  28. .build());
  29. FileWatcherRunnable fileWatcherRunnable =
  30. new FileWatcherRunnable(file, counterGroup);
  31. executorService.scheduleWithFixedDelay(fileWatcherRunnable, 0, interval,
  32. TimeUnit.SECONDS);
  33. lifecycleState = LifecycleState.START;
  34. LOGGER.debug("Configuration provider started");
  35. }
  36. @Override
  37. public void stop() {
  38. LOGGER.info("Configuration provider stopping");
  39. executorService.shutdown();
  40. try {
  41. while (!executorService.awaitTermination(500, TimeUnit.MILLISECONDS)) {
  42. LOGGER.debug("Waiting for file watcher to terminate");
  43. }
  44. } catch (InterruptedException e) {
  45. LOGGER.debug("Interrupted while waiting for file watcher to terminate");
  46. Thread.currentThread().interrupt();
  47. }
  48. lifecycleState = LifecycleState.STOP;
  49. LOGGER.debug("Configuration provider stopped");
  50. }
  51. @Override
  52. public synchronized LifecycleState getLifecycleState() {
  53. return lifecycleState;
  54. }
  55. @Override
  56. public String toString() {
  57. return "{ file:" + file + " counterGroup:" + counterGroup + " provider:"
  58. + getClass().getCanonicalName() + " agentName:" + getAgentName() + " }";
  59. }
  60. public class FileWatcherRunnable implements Runnable {
  61. private final File file;
  62. private final CounterGroup counterGroup;
  63. private long lastChange;
  64. public FileWatcherRunnable(File file, CounterGroup counterGroup) {
  65. super();
  66. this.file = file;
  67. this.counterGroup = counterGroup;
  68. this.lastChange = 0L;
  69. }
  70. @Override
  71. public void run() {
  72. LOGGER.debug("Checking file:{} for changes", file);
  73. counterGroup.incrementAndGet("file.checks");
  74. long lastModified = file.lastModified();
  75. if (lastModified > lastChange) {
  76. LOGGER.info("Reloading configuration file:{}", file);
  77. counterGroup.incrementAndGet("file.loads");
  78. lastChange = lastModified;
  79. try {
  80. eventBus.post(getConfiguration());
  81. } catch (Exception e) {
  82. LOGGER.error("Failed to load configuration data. Exception follows.",
  83. e);
  84. } catch (NoClassDefFoundError e) {
  85. LOGGER.error("Failed to start agent because dependencies were not " +
  86. "found in classpath. Error follows.", e);
  87. } catch (Throwable t) {
  88. // caught because the caller does not handle or log Throwables
  89. LOGGER.error("Unhandled error", t);
  90. }
  91. }
  92. }
  93. }
  94. }

1)我们在Application类中看看它的start()

  1. public synchronized void start() {
  2. for (LifecycleAware component : components) {
  3. supervisor.supervise(component,
  4. new SupervisorPolicy.AlwaysRestartPolicy(), LifecycleState.START);
  5. }
  6. }

这里使用supervisor.supervise()来启动component,那么我就不带大家去看LifecycleSupervisor这个类,在这里就告诉大家,这个方法内部还是调用了LifecycleAware的start()来进行启动。既然讲到了LifecycleAware接口,怎么说都得看看代码

  1. @InterfaceAudience.Public
  2. @InterfaceStability.Stable
  3. public interface LifecycleAware {
  4. public void start();
  5. public void stop();
  6. public LifecycleState getLifecycleState();
  7. }

非常简单,就是三个方法,start()、stop()和getLifecycleState,但是flume大多数涉及启动关闭的类都实现了它。

2)我们可以看到PollingPropertiesFileConfigurationProvider也是实现了LifecycleAware接口,那么appliaction的start()实际上就是调用PollingPropertiesFileConfigurationProvider的start()

3)48行:启动了一个30秒执行一次的线程,也就是30秒检查一次配置文件。这个线程是一个内部类FileWatcherRunnable(77行)

4)99行:判断文件是否有改动,如果有则调用eventBus.post(getConfiguration()).那么订阅了事件的Application类则会调用handleConfigurationEvent()执行组件的全部关闭和重启。

5)同时我们注意到该类中是没有getConfiguration()的,该方法是它的父类AbstractConfigurationProvider中定义的,用于获取配置文件信息,这里就不带大家看了,有兴趣可以看一下。

启动流程的分析就到此为止,这里显示不了行号,尴尬

Flume-ng源码解析之启动流程的更多相关文章

  1. SpringMVC源码解析-DispatcherServlet启动流程和初始化

    在使用springmvc框架,会在web.xml文件配置一个DispatcherServlet,这正是web容器开始初始化,同时会在建立自己的上下文来持有SpringMVC的bean对象. 先从Dis ...

  2. Netty源码解析—客户端启动

    Netty源码解析-客户端启动 Bootstrap示例 public final class EchoClient { static final boolean SSL = System.getPro ...

  3. Sentinel源码解析一(流程总览)

    引言 Sentinel作为ali开源的一款轻量级流控框架,主要以流量为切入点,从流量控制.熔断降级.系统负载保护等多个维度来帮助用户保护服务的稳定性.相比于Hystrix,Sentinel的设计更加简 ...

  4. Thinkphp6源码分析之解析,Thinkphp6路由,Thinkphp6路由源码解析,Thinkphp6请求流程解析,Thinkphp6源码

    Thinkphp6源码解析之分析 路由篇-请求流程 0x00 前言: 第一次写这么长的博客,所以可能排版啊,分析啊,什么的可能会比较乱.但是我大致的流程已经觉得是说的够清楚了.几乎是每行源码上都有注释 ...

  5. 【原创】angularjs1.3.0源码解析之执行流程

    Angular执行流程 前言 发现最近angularjs在我厂的应用变得很广泛,下周刚好也有个angular项目要着手开始做,所以先做了下功课,从源代码开始入手会更深刻点,可能讲的没那么细,侧重点在于 ...

  6. Ceph源码解析:读写流程

    转载注明出处,整理也是需要功夫的,http://www.cnblogs.com/chenxianpao/p/5572859.html 一.OSD模块简介 1.1 消息封装:在OSD上发送和接收信息. ...

  7. Python Web Flask源码解读(一)——启动流程

    关于我 一个有思想的程序猿,终身学习实践者,目前在一个创业团队任team lead,技术栈涉及Android.Python.Java和Go,这个也是我们团队的主要技术栈. Github:https:/ ...

  8. Spring5源码解析1-从启动容器开始

    从启动容器开始 最简单的启动spring的代码如下: @Configuration @ComponentScan public class AppConfig { } public class Mai ...

  9. Vue.js源码解析-Vue初始化流程

    目录 前言 1. 初始化流程概述图.代码流程图 1.1 初始化流程概述 1.2 初始化代码执行流程图 2. 初始化相关代码分析 2.1 initGlobalAPI(Vue) 初始化Vue的全局静态AP ...

随机推荐

  1. 勘误《iOS网络高级编程:iPhone和iPad的企业应用开发》

    VII页 , 倒数第二行, “其他” 应为 “其它” X页, 源代码有错误,说是有19章,实际一共13章 XI页,勘误表的链接也是错误的  .是该书的<Beginning ASP.NET 4.5 ...

  2. JS 继承(类式 与 原型式)

    1. /* -- 类式继承 -- *///先声明一个超类 function Person(name) { this.name = name;}//给这个超类的原型对象上添加方法 getName Per ...

  3. 数据库基础-INDEX

    http://m.oschina.net/blog/10314 一.引言 对数据库索引的关注从未淡出我的们的讨论,那么数据库索引是什么样的?聚集索引与非聚集索引有什么不同?希望本文对各位同仁有一定的帮 ...

  4. FineUI表格模板列Undefined问题

    一般是配置文件未添加ClientID="AutoID"引起

  5. Recurrent Neural Network系列2--利用Python,Theano实现RNN

    作者:zhbzz2007 出处:http://www.cnblogs.com/zhbzz2007 欢迎转载,也请保留这段声明.谢谢! 本文翻译自 RECURRENT NEURAL NETWORKS T ...

  6. Apriori算法原理总结

    Apriori算法是常用的用于挖掘出数据关联规则的算法,它用来找出数据值中频繁出现的数据集合,找出这些集合的模式有助于我们做一些决策.比如在常见的超市购物数据集,或者电商的网购数据集中,如果我们找到了 ...

  7. js动画(四)

    终于到了最后了,这里要告一段落了,整了个js运动框架,咳咳咳,好冷 啊啊啊啊啊啊,这天气.妈的,工资怎么也不发,啊,说好的 人与人之间的信任呢?哎,气诶,不到150字啊,又是这个梗..怎么办?说些什么 ...

  8. puppet来管理文件和软件包

    puppet来管理文件和软件包 1 exec的使用,可以运行shell命令 为配置文件添加配置,指示写了关键部分,其他配置省略没写 代码示例如下: [root@pup manifests]# cat ...

  9. [随笔]利用云虚拟机和学校VPN实现校外访问校内站点(反向代理)

    探究背景简介: 大学校内站点一般不对外开放,个人认为原因有二: 一是站点内容受众就是大学师生: 二是站点基本无防御措施,在公网环境下容易发生意外情况. 至于为何不对外开放,不是这篇随笔探讨的重点,利用 ...

  10. 使用Typescript来写javascript

    使用Typescript来写javascript 前几天尝试使用haxejs来写javascript,以获得静态类型带来的益处.虽然成功了,但很快发现将它与angularjs一起使用,有一些不太顺畅的 ...