flume监控分析

来源:互联网 发布:sql注入站点 编辑:程序博客网 时间:2024/05/01 12:15

flume 监控分析

由启动flume时可以发现,flume 入口函数位于flume-ng-node目录中的Application.java文件中:

  1. Info: Sourcing environment configuration script /home/bjtianye1/apache-flume-1.7.0-bin/conf/flume-env.sh
  2. Info: Including Hadoop libraries found via (/home/hadoop/hadoop//bin/hadoop) for HDFS access
  3. Info: Including HBASE libraries found via (/home/hbase/hbase/bin/hbase) for HBASE access
  4. Info: Including Hive libraries found via () for Hive access
  5. + exec /home/jdk//bin/java -Xmx20m -Dflume.root.logger=DEBUG,console,LOGFILE -Xms100m -Xmx2000m -Dflume.monitoring.type=ganglia -Dflume.monitoring.hosts=10.172.152.66:8666 -DisGanglia3=true -cp '/home/bjtianye1/apache-flume-1.7.0-bin/conf:/home/hadoop/hadoop-2.5.2/lib/native org.apache.flume.node.Application -f conf/flume.conf -n agent1

根据命令中含有no-reload-conf(默认为动态加载)参数,决定采用那种加载配置文件方式:一、没有此参数,会动态加载配置文件,默认每30秒加载一次配置文件,因此可以动态修改配置文件;二、有此参数,则只在启动时加载一次配置文件。实现动态加载功能采用了发布订阅模式,使用guava中的EventBus实现。

main方法首先解析各个传入的参数,然后调用handleConfigurationEvent方法,在该方法中调用startAllComponents方法,在该方法中调用loadMonitoring方法加载监控的一些信息,并开始监控服务monitorServer.start()(monitorServer实现了接口MonitorService,该接口中只有两个方法start和stop)

  1. private void loadMonitoring() {
  2. ...
  3. monitorServer.configure(context);来加载监控服务的配置信息;
  4. monitorServer.start();启动监控服务
  5. ...
  6. }

查看该start 方法的具体实现: 

monitorServer有两种,GangliaServer和HTTPMetricsServer,都实现了MonitorService接口。

  1. /**
  2. * Start this server, causing it to poll JMX at the configured frequency.
  3. */
  4. @Override
  5. public void start() {
  6. try {
  7. socket = new DatagramSocket();
  8. hostname = InetAddress.getLocalHost().getHostName();
  9. } catch (SocketException ex) {
  10. logger.error("Could not create socket for metrics collection.");
  11. throw new FlumeException(
  12. "Could not create socket for metrics collection.", ex);
  13. } catch (Exception ex2) {
  14. logger.warn("Unknown error occured", ex2);
  15. }
  16. for (HostInfo host : hosts) {
  17. addresses.add(new InetSocketAddress(
  18. host.getHostName(), host.getPortNumber()));
  19. }
  20. collectorRunnable.server = this;
  21. if (service.isShutdown() || service.isTerminated()) {
  22. /*
  23. * 创建一个单线程执行程序,它可安排在给定延迟后运行命令或者定期地执行。
  24. * (注意,如果因为在关闭前的执行期间出现失败而终止了此单个线程,那么如果需要,
  25. * 一个新线程会代替它执行后续的任务)。可保证顺序地执行各个任务,并且在任意给定
  26. * 的时间不会有多个线程是活动的。与其他等效的 newScheduledThreadPool(1) 不同,
  27. * 可保证无需重新配置此方法所返回的执行程序即可使用其他的线程
  28. *
  29. */
  30. service = Executors.newSingleThreadScheduledExecutor();
  31. }
  32. /* scheduleWithFixedDelay(Runnable command, 要执行的任务
  33. * long initialDelay, 首次执行的延迟时间
  34. * long delay, 一次执行终止和下一次执行开始之间的延迟
  35. * TimeUnit unit) initialDelay 和 delay 参数的时间单位
  36. * 创建并执行一个在给定初始延迟后首次启用的定期操作,随后,在每一次执行终止和下一次
  37. * 执行开始之间都存在给定的延迟。如果任务的任一执行遇到异常,就会取消后续执行。否则,
  38. * 只能通过执行程序的取消或终止方法来终止该任务。
  39. */
  40. service.scheduleWithFixedDelay(collectorRunnable, 0,
  41. pollFrequency, TimeUnit.SECONDS);
  42. }

start()方法中会调用collectorRunnable(一个实现了Runnable的类GangliaCollector )

  1. /**GangliaServer.java
  2. * Worker which polls JMX for all mbeans with
  3. * {@link javax.management.ObjectName} within the flume namespace:
  4. * org.apache.flume. All attributes of such beans are sent to the all hosts
  5. * specified by the server that owns it's instance.
  6. * 这些bean的所有属性都发送到拥有它的实例的服务器指定的所有主机
  7. */
  8. protected class GangliaCollector implements Runnable {
  9. private GangliaServer server;
  10. @Override
  11. public void run() {
  12. try {
  13. Map<String, Map<String, String>> metricsMap =
  14. JMXPollUtil.getAllMBeans(); //具体的监控数据从这获得,通过JMX方式得到
  15. for (String component : metricsMap.keySet()) {
  16. Map<String, String> attributeMap = metricsMap.get(component);
  17. for (String attribute : attributeMap.keySet()) {
  18. if (isGanglia3) {
  19. server.createGangliaMessage(GANGLIA_CONTEXT + component + "."
  20. + attribute,
  21. attributeMap.get(attribute));
  22. } else {
  23. server.createGangliaMessage31(GANGLIA_CONTEXT + component + "."
  24. + attribute,
  25. attributeMap.get(attribute));
  26. }
  27. server.sendToGangliaNodes(); //发送metrics数据到ganglia节点
  28. }
  29. }
  30. } catch (Throwable t) {
  31. logger.error("Unexpected error", t);
  32. }
  33. }
  34. }

监控数据主要是通过类JMXPollUtil的getAllMBean方法中获取的,这个类是flume监控的核心代码,通过Java JMX(java管理扩展,是Java平台上为应用程序、设备、系统等植入管理功能的框架)实现。首先会从MBeanServer服务器获取已注册的 MBean 对象名及其类名,然后将对应的component和属性信息放入Map对象中返回:

  1. public class JMXPollUtil {
  2. private static Logger LOG = LoggerFactory.getLogger(JMXPollUtil.class);
  3. private static MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
  4. /*
  5. * getAllMBeans()获取所有组件注册的MBean构成的Map<String,Map<String,String>> mbeanMap
  6. * 将组件信息和对应的监控项信息put至集合mbeanMap中并返回
  7. */
  8. public static Map<String, Map<String, String>> getAllMBeans() {
  9. //newHashMap方法内部只是创建了一个空的HashMap<K,V>实例
  10. Map<String, Map<String, String>> mbeanMap = Maps.newHashMap();
  11. Set<ObjectInstance> queryMBeans = null;
  12. try {
  13. /* queryMBeans获取该MBean服务器所控制的MBean
  14. * name - 对象名模式,标识要检索的 MBean。如果为 null 或未指定域和键属性,则检索所有已注册的 MBean。
  15. * query - 应用到所选 MBean 的查询表达式。如果为 null,则不对所选的 MBean 应用查询表达式
  16. */
  17. queryMBeans = mbeanServer.queryMBeans(null, null);
  18. } catch (Exception ex) {
  19. LOG.error("Could not get Mbeans for monitoring", ex);
  20. Throwables.propagate(ex);
  21. }
  22. /* 类ObjectInstance用于表示 MBean 对象名及其类名
  23. * getObjectName()方法用于返回对象名部分,类型为ObjectName
  24. */
  25. for (ObjectInstance obj : queryMBeans) {
  26. try { //ObjectName类中有重写toString方法
  27. if (!obj.getObjectName().toString().startsWith("org.apache.flume")) {
  28. continue;
  29. }
  30. //getMBeanInfo方法发现了 MBean 为管理而公开的属性和操作
  31. //getAttributes返回为了便于管理而公开的属性的列表。
  32. MBeanAttributeInfo[] attrs = mbeanServer.getMBeanInfo(obj.getObjectName()).getAttributes();
  33. String[] strAtts = new String[attrs.length];
  34. for (int i = 0; i < strAtts.length; i++) {
  35. strAtts[i] = attrs[i].getName();
  36. }
  37. //mbeanServer.getAttributes获得指定 MBean 的多个属性值
  38. AttributeList attrList = mbeanServer.getAttributes(obj.getObjectName(), strAtts);
  39. //获取组件名
  40. String component = obj.getObjectName().toString().substring(
  41. obj.getObjectName().toString().indexOf('=') + 1);
  42. //创建存储属性键值对的HashMap集合
  43. Map<String, String> attrMap = Maps.newHashMap();
  44. for (Object attr : attrList) {
  45. Attribute localAttr = (Attribute) attr;
  46. if (localAttr.getName().equalsIgnoreCase("type")) {
  47. component = localAttr.getValue() + "." + component;
  48. }
  49. attrMap.put(localAttr.getName(), localAttr.getValue().toString());
  50. }
  51. mbeanMap.put(component, attrMap);
  52. } catch (Exception e) {
  53. LOG.error("Unable to poll JMX for metrics.", e);
  54. }
  55. }
  56. return mbeanMap;
  57. }
  58. }

Sink组件

各个具体监控组件的私有指标信息都是在各个组件自己实现定义,这些源码都是在flume-ng-core中的org.apache.flume.instrumentation包下面,所有的监控组件都会继承MonitoredCounterGroup实现xxxCounterMBean接口,MonitoredCounterGroup中定义了一些基本公有的监控属性(启动时间、停止时间等),提供了注册至MBeanServer的方法registerMBean,在具体的组件调用时会进行注册,xxxCounterMBean 则定义了获取监控元素的方法接口,具体实现还是在监控组件中实现。这里就拿 Sink组件来大致看下。 
SinkCounter 类继承 MonitoredCounterGroup抽象类,并实现了 SinkCounterMBean 接口:

  1. public class SinkCounter extends MonitoredCounterGroup implements
  2. SinkCounterMBean {
  3. private static final String COUNTER_EVENT_DRAIN_ATTEMPT =
  4. "sink.event.drain.attempt";
  5. private static final String COUNTER_EVENT_DRAIN_SUCCESS =
  6. "sink.event.drain.sucess";
  7. private static final String[] ATTRIBUTES = { //组件的监控指标属性信息
  8. COUNTER_CONNECTION_CREATED, COUNTER_CONNECTION_CLOSED,
  9. COUNTER_CONNECTION_FAILED, COUNTER_BATCH_EMPTY,
  10. COUNTER_BATCH_UNDERFLOW, COUNTER_BATCH_COMPLETE,
  11. COUNTER_EVENT_DRAIN_ATTEMPT, COUNTER_EVENT_DRAIN_SUCCESS
  12. };
  13. @Override
  14. public long getConnectionCreatedCount() { //具体指标的获取方法
  15. return get(COUNTER_CONNECTION_CREATED);
  16. }
  17. ......

SinkCounterMBean接口主要就是声明了一个属性的获取方法:

  1. public interface SinkCounterMBean {
  2. long getConnectionCreatedCount();
  3. ......
  4. long getEventDrainSuccessCount();
  5. long getStartTime();
  6. long getStopTime();
  7. }

上边这就是flume监控的一个大致框架,你可能会发现上边的类或者接口的名字都有点相似,其实这不是偶然的,它是 JMX 中的统一规范。

0 0
原创粉丝点击