对于flume的监控,只需要监控channel的性能数据即可,source和sink的性能一部分可以从channel中表现出来。
以MemoryChannel为例,在MemoryTransaction的构造函数中会实例化一个org.apache.flume.instrumentation.ChannelCounter对象

    public MemoryTransaction( int transCapacity, ChannelCounter counter) {
      putList = new LinkedBlockingDeque<Event>(transCapacity);
      takeList = new LinkedBlockingDeque<Event>(transCapacity);
      channelCounter = counter;
    }

org.apache.flume.instrumentation.ChannelCounter 定义了几个计数器用来记录channel的性能数据

  private static final String COUNTER_CHANNEL_SIZE = "channel.current.size"; //已经使用的容量大小
  private static final String COUNTER_EVENT_PUT_ATTEMPT = "channel.event.put.attempt"; //source到channel尝试插入的数据(不管是否成功)
  private static final String COUNTER_EVENT_TAKE_ATTEMPT = "channel.event.take.attempt"; //sink从channel尝试消费的数据(不管是否成功)
  private static final String COUNTER_EVENT_PUT_SUCCESS = "channel.event.put.success"; //source到channel成功插入的数据
  private static final String COUNTER_EVENT_TAKE_SUCCESS = "channel.event.take.success"; //sink从channel成功消费的数据
  private static final String COUNTER_CHANNEL_CAPACITY = "channel.capacity";  //总容量大小

并封装了相关的方法,来操作这些性能计数器:

wKiom1T1w3CynIp-AAFVrItasOA700.jpg

比如channel.event.put.attempt的由getEventPutAttemptCount和incrementEventPutAttemptCount操作:

  public long incrementEventPutAttemptCount() { //用于数量增加1
    return increment( COUNTER_EVENT_PUT_ATTEMPT);
  }
  public long getEventPutAttemptCount() { //用于获取值
    return get( COUNTER_EVENT_PUT_ATTEMPT);
  }

而在channel的相关操作中会使用到这些方法:

    protected void doPut(Event event) throws InterruptedException {
      channelCounter.incrementEventPutAttemptCount(); //比如在插入数据的操作开始时,增加channel.event.put.attempt的值
      int eventByteSize = (int)Math.ceil(estimateEventSize(event)/ byteCapacitySlotSize);
      if (! putList.offer(event)) {
        throw new ChannelException(
          "Put queue for MemoryTransaction of capacity " +
            putList.size() + " full, consider committing more frequently, " +
            "increasing capacity or increasing thread count" );
      }
      putByteCounter += eventByteSize;
    }


counter的注册使用,以memorychannel相关为例:
ChannelCounter扩展了MonitoredCounterGroup类并实现了ChannelCounterMBean接口
MonitoredCounterGroup是一个抽象类,其具体的实现类定义了具体的组件的性能计数器和对应的封装方法

wKiom1T1w5Oimh3vAAEQLzntWLo002.jpg

ChannelCounter中包含的所有的可用的counter:

private static final String[] ATTRIBUTES = {
    COUNTER_CHANNEL_SIZE, COUNTER_EVENT_PUT_ATTEMPT,
    COUNTER_EVENT_TAKE_ATTEMPT, COUNTER_EVENT_PUT_SUCCESS,
    COUNTER_EVENT_TAKE_SUCCESS, COUNTER_CHANNEL_CAPACITY
  };

ChannelCounter的构造方法调用MonitoredCounterGroup的构造方法:

  public ChannelCounter(String name) {
    super(MonitoredCounterGroup.Type. CHANNEL, name, ATTRIBUTES ); //调用MonitoredCounterGroup构造方法
  }
MonitoredCounterGroup构造方法:
private final Map<String, AtomicLong> counterMap;
....
  protected MonitoredCounterGroup(Type type, String name, String... attrs) {
    this. type = type;
    this. name = name;
    Map<String, AtomicLong> counterInitMap = new HashMap<String, AtomicLong>(); // 声明一个初始的hashmap,用来存放counter name到value的对应关系
    // Initialize the counters
    for (String attribute : attrs) {
      counterInitMap.put(attribute, new AtomicLong(0L)); //初始value都为0
    }
    counterMap = Collections.unmodifiableMap(counterInitMap); //返回hashmap不可更改的映射视图
    startTime = new AtomicLong(0L);
    stopTime = new AtomicLong(0L);
  }

这里Type是一个enum类型,可取值:

  public static enum Type {
    SOURCE,
    CHANNEL_PROCESSOR,
    CHANNEL,
    SINK_PROCESSOR,
    SINK,
    INTERCEPTOR,
    SERIALIZER,
    OTHER
  };

在MemoryChannel中的start方法中启动:

  public synchronized void start() {
    channelCounter.start(); //调用MonitoredCounterGroup的start方法
    channelCounter.setChannelSize( queue.size());
    channelCounter.setChannelCapacity(Long. valueOf(
            queue.size() + queue.remainingCapacity()));
    super.start();
  }

MonitoredCounterGroup.start:

  public void start() {
    register(); //调用register方法注册counter,主要是调用ManagementFactory. getPlatformMBeanServer().registerMBean( this, objName);进行注册mbean操作,把ChannelCounter对象作为mbean进行注册
    stopTime.set(0L);
    for (String counter : counterMap.keySet()) {
      counterMap.get(counter).set(0L); //设置值都为0
    }
    startTime.set(System. currentTimeMillis());
    logger.info( "Component type: " + type + ", name: " + name + " started" );
  }

这样就可以通过jmx获取的监控项