我需要测量软件系统消耗来自消息队列的消息的速率,并定期报告。
具体地,消息从消息排队系统到达,并且我需要报告(每秒)关于在多个滚动窗口内接收的消息的数量 - 例如,最后一秒,最后5秒,最后30秒等等。
虽然我确信我可以建立这个,但我不确定我会以最有效的方式解决这个问题!我也确定有这样的库(我正在使用JVM,因此我想到了Apache Commons Math),但我甚至不知道Google的正确用语! : - )
答案 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)
您可以将其实现为拦截器,因此搜索拦截器并结合消息队列产品名称和语言名称。