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

Math 如何通过系统测量事件发生率,math,message-queue,rate,Math,Message Queue,Rate,我需要测量软件系统消耗消息队列中消息的速率,并定期报告该速率 具体而言,消息来自消息队列系统,我需要(每秒)报告在多个滚动窗口内收到的消息数量,例如,最后一秒、最后5秒、最后30秒等 虽然我相信我可以建立这个,但我不确定我会以最有效的方式进行!我也确信有库可以做到这一点(我使用的是JVM,所以我想到了ApacheCommonsMath),但我甚至不知道谷歌应该用什么词来表达!:-) 您可能可以将其实现为拦截器,因此搜索拦截器,并结合消息队列产品名称和语言名称。这就是我最后写的内容 package

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

具体而言,消息来自消息队列系统,我需要(每秒)报告在多个滚动窗口内收到的消息数量,例如,最后一秒、最后5秒、最后30秒等


虽然我相信我可以建立这个,但我不确定我会以最有效的方式进行!我也确信有库可以做到这一点(我使用的是JVM,所以我想到了ApacheCommonsMath),但我甚至不知道谷歌应该用什么词来表达!:-)

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

这就是我最后写的内容

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();
        }
    }
}
package.com.example;
导入java.util.array;
导入java.util.concurrent.AtomicInteger;
导入java.util.concurrent.locks.Lock;
导入java.util.concurrent.locks.ReentrantLock;
公营柜台{
private final Lock rollLock=新的ReentrantLock();
私人最终整数[]美元大小;
私人最终整数[]桶;
私有最终int[]间隔;
私有最终AtomicInteger传入=新的AtomicInteger(0);
公共BucketCounter(内部…bucketSizes){
如果(bucketSizes.length<1){
抛出新的IllegalArgumentException(“必须指定至少一个桶大小”);
}
此参数。bucketSizes=bucketSizes;
this.bucket=新整数[bucketSizes.length];
数组。排序(bucketSizes);
如果(bucketSizes[0]<1){
抛出新的IllegalArgumentException(“不能有大小小于1的桶”);
}
间隔=新整数[bucketSizes[bucketSizes.length-1];
}
公共整数计数(整数n){
返回传入的.addAndGet(n);
}
公共int[]roll(){
final int toAdd=传入的.getAndSet(0);
rollLock.lock();
试一试{
最终int[]结果=新int[bucket.length];
for(int i=0,n=bucket.length;i
通过传递不同的时间增量(例如1、5、30)对其进行初始化。然后安排后台线程在每个“时间段”调用
roll()
。如果你每秒钟叫一次,那么你的桶是1、5和30秒。如果你每5秒调用一次,那么你的存储桶是5、25和150秒,以此类推。基本上,存储桶用“调用次数
roll()
is called”)表示

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

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


希望有帮助。

这是我基于指数平滑的解决方案。它不需要任何后台线程。您将为要跟踪的每个滚动窗口创建一个实例。对于每个相关事件,您将在每个实例上调用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;
  }
}

谢谢你的回复,但我不知道这是什么意思!我不知道什么是“拦截器”,除非你说的是AOP之类的东西。而且特定的消息队列产品和语言基本上是不相关的。@dty您也可以尝试“回调”。这方面有什么进展吗?我基本上也有相同的要求,最后我自己写了。我会在回复中发布。谢谢发布。我想避免背景线程的复杂性。我正在研究一种基于指数平滑的解决方案。等我写完了我会把它贴出来的。你能解释一下它是怎么工作的吗?特别是,你能解释一下历史事件是如何从结果中去除的吗?我可以试试。我们希望对成员变量normalizedRate执行指数平滑。每次我们得到一个新事件时,我们更新为:normalizedRate(t)=(normalizedFrequency*alpha)+(normalizedRate*(1-alpha))。请注意,我的实现不能很好地处理长时间缺席的事件,也就是说,它只在观察到新事件时更新normalizedRate,因此,当预期的事件速率至少为每个窗口周期1时,它将工作得最好。我在考虑如何处理这件事。今天我将尝试更好地记录事情并更新我的答案。更直接地回答您的问题。因此,在每次更新时,我们计算一个新值,它是新“度量”的一部分,也是旧值的一部分。查找“指数平滑”或“卡尔曼滤波”。对此,我没有强有力的数学基础,但在我的实现中,我将新度量的权重分配给它所代表的窗口的比例。这可能有助于通过手工操作和示例来了解历史值是如何“指数衰减”的。您可以查看启动,例如normalizedRate=0,事件以恒定的2/s或类似速度开始发生。谢谢我会详细阅读你的回复,稍后再查阅参考资料。