如何通过系统衡量事件发生率

时间:2013-05-08 11:47:36

标签: math message-queue rate

我需要测量软件系统消耗来自消息队列的消息的速率,并定期报告。

具体地,消息从消息排队系统到达,并且我需要报告(每秒)关于在多个滚动窗口内接收的消息的数量 - 例如,最后一秒,最后5秒,最后30秒等等。

虽然我确信我可以建立这个,但我不确定我会以最有效的方式解决这个问题!我也确定有这样的库(我正在使用JVM,因此我想到了Apache Commons Math),但我甚至不知道Google的正确用语! : - )

3 个答案:

答案 0 :(得分:5)

这是我的基于指数平滑的解决方案。它不需要任何后台线程。您将为要跟踪的每个滚动窗口创建1个实例。对于每个相关事件,您将在每个实例上调用newEvent。

public class WindowedEventRate {

  private double normalizedRate; // event rate / window
  private long windowSizeTicks;
  private long lastEventTicks;


  public WindowedEventRate(int aWindowSizeSeconds) {
    windowSizeTicks = aWindowSizeSeconds * 1000L;
    lastEventTicks = System.currentTimeMillis();
  }

  public double newEvent() {

    long currentTicks = System.currentTimeMillis();
    long period = currentTicks - lastEventTicks;
    lastEventTicks = currentTicks;
    double normalizedFrequency = (double) windowSizeTicks / (double) period;

    double alpha = Math.min(1.0 / normalizedFrequency, 1.0);
    normalizedRate = (alpha * normalizedFrequency) + ((1.0 - alpha) * normalizedRate);
    return getRate();
  }

  public double getRate() {
    return normalizedRate * 1000L / windowSizeTicks;
  }
}

答案 1 :(得分:1)

这是我最后写的。

package com.example;

import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class BucketCounter {
    private final Lock rollLock = new ReentrantLock();
    private final int[] bucketSizes;
    private final int[] buckets;
    private final int[] intervals;
    private final AtomicInteger incoming = new AtomicInteger(0);

    public BucketCounter(int... bucketSizes) {
        if (bucketSizes.length < 1) {
            throw new IllegalArgumentException("Must specify at least one bucket size");
        }

        this.bucketSizes = bucketSizes;
        this.buckets = new int[bucketSizes.length];

        Arrays.sort(bucketSizes);

        if (bucketSizes[0] < 1) {
            throw new IllegalArgumentException("Cannot have a bucket of size < 1");
        }

        intervals = new int[bucketSizes[bucketSizes.length - 1]];
    }

    public int count(int n) {
        return incoming.addAndGet(n);
    }

    public int[] roll() {
        final int toAdd = incoming.getAndSet(0);

        rollLock.lock();
        try {
            final int[] results = new int[buckets.length];

            for (int i = 0, n = buckets.length; i < n; i++) {
                results[i] = buckets[i] = buckets[i] - intervals[bucketSizes[i] - 1] + toAdd;
            }

            System.arraycopy(intervals, 0, intervals, 1, intervals.length - 1);
            intervals[0] = toAdd;

            return results;
        } finally {
            rollLock.unlock();
        }
    }
}

通过传递不同的时间增量(例如1,5,30)来初始化它。然后安排后台线程在每个“时间段”调用roll()。如果你每秒呼叫一次,那么你的水桶分别为1,5和30秒。如果你每5秒调用一次,那么你的桶就会有5秒,25秒和150秒等等。基本上,桶的表示为“roll()被调用的次数”。

roll()还会返回每个存储桶的当前计数数组。请注意,这些数字是原始计数,并不是每个时间间隔的平均值。如果你想测量“费率”而不是“数量”,你需要自己做这个部门。

最后,每次事件发生时,请致电count()。我已经设置了一个包含其中一些系统的系统,我在每条消息上调用count(1)来计算传入消息,在每条消息上计算count(message.size())以计算传入的字节速率等。

希望有所帮助。

答案 2 :(得分:-1)

您可以将其实现为拦截器,因此搜索拦截器并结合消息队列产品名称和语言名称。