Search code examples
javaraterate-limiting

java measure method invocation rate


I want to calculate and print method invocation rate, let's say I have the following method that is called on every consumed message (from Kafka):

public class Consumer {
  public void run() {
   while (true) {
     ConsumerRecords<String> recs = consumer.poll();
     for(ConsumerRecord record: recs) {
       parseMessageToDB(record.getValue());
     }
   }
 }

  public void parseMessageToDB(String message) {
    // message parsing logic..
  }
}

My goal here is to calculate #parseMessageToDB method invocations per second to know the speed with that my application can consume events from Kafka.

I tried to use RateLimiter from Guava but it doesn't return the current invocation rate.

Right now I ended up with the following solution where I simply calculate the number of consumed messages in 15sec and simply reset it to zero after logging.

This calculation is not very accurate since I rely on the timer intervals and also there is a possibility to take(or reset) values from another 15sec window, but this gives me at least some picture:

public class Consumer {

    private final Timer timer = new Timer();
    private final AtomicLong parsedEvents = new AtomicLong();
    private static final int CONSUMER_TIMER_RATE_SEC = 15;

    public Consumer () {
      timer.schedule(new TimerTask() {
        @Override
        public void run() {
        logEventsParsingRate();
        }
      }, 0, CONSUMER_TIMER_RATE_SEC*1000);

    }

    public void run() {
       while (true) {
         ConsumerRecords<String> recs = consumer.poll();
         for(ConsumerRecord record: recs) {
            parseMessageToDB(record.getValue());
         }
        parsedEvents.addAndGet(recs.count());
       }
     }

   private void logEventsParsingRate() {
     logger.info("Consumer events consuming rate per sec: " + 
       handledEvents.getAndSet(0)/CONSUMER_TIMER_RATE_SEC);
   }

}

So I'm still looking for any other more accurate solutions.


Solution

  • There are metering libraries that can provide the rate measurement capabilities.

    Here are two of them:

    Dropwizard metrics

    Micrometer

    Both work in a similar way to some descent - keep in memory an object that has all the required information.

    Usually, these frameworks are used in conjunction with metrics persistence servers like Prometheus, Influx DB, Graphite, etc + some UI tool that allows easy view and analysis of the values (like Grafana).

    But even in a "stadalone" mode they can report the gathered information to Log files or JMX for instance

    For example, in Dropwizard, there is a "Meter" primitive that can be used like this:

    // somewhere globally defined
    private final MetricRegistry metrics = new MetricRegistry();
    private final Meter requests = metrics.meter("requests");
    
    // the method to be metered
    public void run() {
        requests.mark();
        // do stuff
    }