SmoothWarmingUp rate limiter not providing expected throughput

172 views
Skip to first unread message

Jeeno Lentin

unread,
Jul 22, 2020, 3:38:55 PM7/22/20
to guava-discuss
Hi,

I am facing the following issue with SmoothWarmingUp RateLimiter.

RateLimiter rateLimiter = RateLimiter.create(3000, 1, TimeUnit.SECONDS);

Stopwatch timer = Stopwatch.createStarted();
int count = 0;

while(!Thread.currentThread().isInterrupted()) {

    rateLimiter.acquire();
    count++;

    if(timer.elapsed(TimeUnit.SECONDS) >= 1) {
        // Prints 1500 ~ 2000 on average
        System.out.println(LocalDateTime.now() + " => " + count);
        count = 0;
        timer.reset().start();
    }
}


I tried on different machines, and get only 1500 to 2000 permits per second instead of the expected 3000.

(But I get 3000/second when using a SmoothBursty rate limiter)

I suspect that in case of SmoothWarmingUp rate limiter, it tries to do a TimeUnit.NANOSECONDS.sleep(..) for a very small time, and the thread doesn't wake up in time.

Not sure if this is the expected max throughput when using acquire() with SmoothWarmingUp rate limiter.

Appreciate any information on this. Thanks.






Reiner Saddey

unread,
Jul 23, 2020, 1:43:36 AM7/23/20
to guava-discuss
Hi Jeeno,

I suspect, problems like these should best be asked at stackoverflow. Anyway, and as IMHO, Javadocs should mention this behaviour...

Very few threads cannot warm up the RateLimiter as it is constantly cooling down at the same time as well.

See stackoverflow - Guava RateLimiter warmup clarification: "Note that in practice using a single thread you will not be able to saturate the demand on a RateLimiter so your actual QPS will be slightly lower than expected and will rarely (if ever) actually reach the stable (maximum) rate. Using multiple threads, however, will allow you to always have a pending permit request and saturate demand."

Experimenting with your code, I found 4 to 5 threads to be able to supply sufficient "heat":

  public static void main(final String[] args) throws InterruptedException {

    final RateLimiter rateLimiter =
        RateLimiter.create(3000, 1, TimeUnit.SECONDS);

    final AtomicInteger count = new AtomicInteger();

    for (int i = 1; i <= 5; ++i) {
      new Thread() {

        {
          setDaemon(true);
        }

        @Override
        public void run() {
          while (true) {
            rateLimiter.acquire();
            count.incrementAndGet();
          }
        }
      }.start();
    }

    final Stopwatch timer = Stopwatch.createStarted();
    for (int second = 0; second < 10; ++second) {
      Thread.sleep(1000);
      System.out
          .println(LocalDateTime.now() + " => " + count.getAndSet(0) * 1000
              / timer.elapsed(TimeUnit.MILLISECONDS));
      timer.reset().start();
    }

  }

Jeeno Lentin

unread,
Jul 23, 2020, 8:32:39 PM7/23/20
to guava-discuss
Hi Reiner,

Thank you for the response. That helps me understand this behavior.
I will use stack overflow for such questions in future.

Thanks,
Jeeno
Reply all
Reply to author
Forward
0 new messages