All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.netflix.eventbus.impl.AbstractEventBusStats Maven / Gradle / Ivy

package com.netflix.eventbus.impl;

import com.netflix.servo.monitor.Monitors;
import org.apache.commons.math.stat.StatUtils;
import org.apache.commons.math.stat.descriptive.moment.Mean;
import org.apache.commons.math.stat.descriptive.moment.StandardDeviation;
import org.apache.commons.math.stat.descriptive.rank.Percentile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Iterator;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author Nitesh Kant ([email protected])
 */
public abstract class AbstractEventBusStats {

    protected static final Logger LOGGER = LoggerFactory.getLogger(EventBusStats.class);

    protected long collectionDurationInMillis;

    // Static as the compute is CPU only task, so we can share these timers across consumers.
    protected static Timer statsSweeper = new Timer(true);

    public AbstractEventBusStats(long collectionDurationInMillis) {
        this.collectionDurationInMillis = collectionDurationInMillis;
        statsSweeper.schedule(new TimerTask() {
            @Override
            public void run() {
                computeTimeIntervalStats();
            }
        }, collectionDurationInMillis, collectionDurationInMillis);
    }

    protected void registerMonitors() {
        try {
            Monitors.registerObject(this);
        } catch (Throwable th) {
            LOGGER.error("Unable to register to event bus stats to servo.", th);
        }
    }

    protected abstract void computeTimeIntervalStats();

    protected class LatencyStats {

        // No reads happen on the below fields, it always happens via the computedData ref which is never written.
        private int sampleSize;
        private double mean;
        private double median;
        private double percentile_99_5;
        private double percentile_99;
        private double percentile_90;
        private double stddev;
        private double max;

        private ConcurrentLinkedQueue rawData;
        private AtomicReference computedData; // This is to avoid all members to be AtomicDoubles.

        protected LatencyStats() {
            rawData = new ConcurrentLinkedQueue();
            computedData = new AtomicReference(new LatencyStats(this));
        }

        private LatencyStats(LatencyStats copyFrom) {
            sampleSize = copyFrom.sampleSize;
            mean = copyFrom.mean;
            median = copyFrom.median;
            percentile_90 = copyFrom.percentile_90;
            percentile_99 = copyFrom.percentile_99;
            percentile_99_5 = copyFrom.percentile_99_5;
            stddev = copyFrom.stddev;
            max = copyFrom.max;
        }

        protected void addLatency(double latency) {
            rawData.add(latency);
        }

        protected void compute() {
            Percentile percentile = new Percentile();
            double[] rawDataAsArray = clearRawDataAndGetAsArray();
            if (null != rawDataAsArray && rawDataAsArray.length != 0) {
                sampleSize = rawDataAsArray.length;
                percentile.setData(rawDataAsArray);
                percentile_99_5 = percentile.evaluate(99.5);
                percentile_99 = percentile.evaluate(99);
                percentile_90 = percentile.evaluate(90);
                median = Math.max(1d, percentile.evaluate(50));
                max = StatUtils.max(rawDataAsArray);
                mean = new Mean().evaluate(rawDataAsArray);
                stddev = new StandardDeviation().evaluate(rawDataAsArray);
            }
            computedData.set(getCopyOfComputedData());
        }

        protected LatencyStats getComputedStats() {
            return computedData.get();
        }

        public int getSampleSize() {
            return getComputedStats().sampleSize;
        }

        public double getMean() {
            return getComputedStats().mean;
        }

        public double getMedian() {
            return getComputedStats().median;
        }

        public double getPercentile_99_5() {
            return getComputedStats().percentile_99_5;
        }

        public double getPercentile_99() {
            return getComputedStats().percentile_99;
        }

        public double getPercentile_90() {
            return getComputedStats().percentile_90;
        }

        public double getStddev() {
            return getComputedStats().stddev;
        }

        public double getMax() {
            return getComputedStats().max;
        }

        private LatencyStats getCopyOfComputedData() {
            return new LatencyStats(this);
        }

        private double[] clearRawDataAndGetAsArray() {
            double[] toReturn = new double[rawData.size()];
            int index = 0;
            for (Iterator iterator = rawData.iterator(); iterator.hasNext(); ) {
                Double aDataPoint = iterator.next();
                iterator.remove(); // Do not double count in the next cycle.
                toReturn[index++] = aDataPoint;
            }
            return toReturn;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy