定时器替代测量服务器端的请求率

时间:2016-01-03 05:24:41

标签: java multithreading timer timertask

我有客户端 - 服务器应用程序,我需要测量每秒请求到达率(请求率)。为此,我有一个计时器对象,每秒后激活,读取同步计数器,然后将其设置为零。计数器在每个请求到达时递增。我使用以下代码来检测请求率。在我的应用程序中运行有很多其他线程和计时器。问题是"由于计时器的不准确性,我没有得到完美的请求率"。除了使用计时器之外,还有其他测量请求率的方法。

public class FrequencyDetector extends TimerTask {
RequestCounter requestCounter;
FrequencyHolder frequencyHolder;

    public FrequencyDetector(RequestCounter requestCounter,FrequencyHolder frequencyHolder){
    this.frequencyHolder=new FrequencyHolder();
    this.frequencyHolder=frequencyHolder;
    }

    @Override
    public void run() {
           int newFrequency=requestCounter.getCounter();
           frequencyHolder.setFrequency(newFrequency);
           requestCounter.setCounterToZero();
          //calls to other fuctions    
    }       

}

1 个答案:

答案 0 :(得分:0)

您可以检查每单位计时器的时间,而不是每单位时间检查计数器。这可能会给你更准确的结果。算法如下。

  1. 每个请求都会增加计数器。
  2. 当计数器按FIXED_LIMIT
  3. 达到某个frequency=FIXED_LIMIT/duration since last record计算频率时
  4. 重置计数器并从步骤1开始
  5. 然而,这将以不可预测的间隔记录频率,如果请求频率减少,则连续记录之间的持续时间将增加。

    为了处理它我们可以实现自适应算法,下面给出算法。

    1. 根据每个请求递增计数器。
    2. 当计数器达到[{1}}
    3. 的某个ADAPTIVE_LIMIT记录频率时
    4. 将ADAPTIVE_LIMIT更改为frequency=ADAPTIVE_LIMIT/duration since last record
    5. 重置计数器并从步骤1开始。
    6. 以上算法将根据上次记录的频率重置限制。它被认为不会以最佳间隔录制,但它会非常接近。

      此外,它还可以为您提供高度准确的频率,因为它不依赖于任何预定的线程。

      以下是这种自适应计数器的实现。

      ADAPTIVE_LIMIT=frequency * DESIRED RECORD INTERVAL

      <强>输出

      import java.util.Random;
      import java.util.concurrent.atomic.AtomicLong;
      
      public class TestCounter {
          //Keep initial counterInterval to a small value otherwise first record may take long time
          final AtomicLong counterInterval = new AtomicLong(10);
          AtomicLong requestCounter = new AtomicLong();
          volatile long lastTime;
          /**OPTIMAL_DURATION is the duration after which frequency is expected to be recorded
           * Program adaptively tries to reach this duration
           */
          static final double OPTIMAL_DURATION = 1.0; // 1 second
          static final Random random = new Random();
      
          public static void main(String[] args) {
              System.out.println("Started ");
      
              TestCounter main = new TestCounter();
              for(int i = 0; i < 1000; i++) {
                  main.requestArrived();
              }
          }
      
          /*
           * Simulating requests
           */
          public void requestArrived() {
              printCounter();
      
              try {
                  Thread.sleep(random.nextInt(100));
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
          }
      
          //This will be in some Utility class
          private void printCounter() {
              requestCounter.incrementAndGet();
              long currentTime = System.nanoTime();
              long currentInterval = counterInterval.get();
      
              if(requestCounter.get() > currentInterval) {
                  if(lastTime != 0) {
                      long timeDelta = currentTime - lastTime;
                      long frequency = (long)(currentInterval / (timeDelta / 1e9));
                      System.out.printf("time=%.2f, frequency=%d\n", (timeDelta / 1e9), frequency);
      
                      //updating the currentInterval for the miss
                      long newCounterInterval = (long)(frequency * OPTIMAL_DURATION);
                      counterInterval.set(newCounterInterval);
                  }
                  requestCounter.set(0);
                  lastTime = currentTime;
              }
          }
      }