1
\$\begingroup\$

I have a background thread which runs every 5 minutes. I am using ScheduledExecutorService for this. Every five minutes, I am making a call to one of my service and parsing the response coming back from that service.

public class ThreadScheduler {

private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

    public void startScheduleTask() {

        scheduler.scheduleAtFixedRate(new Runnable() {
            public void run() {
                try {
                    callService();
                } catch (Exception ex) {
                    // log error
                }
            }
        }, 0, 5L, TimeUnit.MINUTES);
    }

    public void callService() throws Exception {
        // execute the service and parse the response
    }   
}

Now the above code is running in 1000 machines and they all are started at the same time, so that means it will make all the 1000 calls every 5 minutes simultaneously to my service. I'm trying to spread the load more evenly over a 5 minute window. Is this possible to do by any chance with the above code?

I am just trying to spread the load more evenly on my service over the 5 minute window so that it doesn't hit my service at the same time which will put more load once all the systems are started up simultaneously.

I came up with the below code trying to spread the load more evenly over the five minute window:

public class ThreadScheduler {

private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

    public void startScheduleTask() {

        scheduler.scheduleAtFixedRate(new Runnable() {
            public void run() {
                try {
                    callService();
                } catch (Exception ex) {
                    // log error
                }
            }
        }, (int)(Math.random()*5*60), 5*60L, TimeUnit.SECONDS);
    }

    public void callService() throws Exception {
        // execute the service and parse the response
    }   
}

I am opting for code review to see whether this way load will get evenly spread out over the 5 minute window or not.

\$\endgroup\$
  • \$\begingroup\$ Your approach seems to make sense. \$\endgroup\$ – Stop ongoing harm to Monica Aug 30 '14 at 21:23
  • \$\begingroup\$ @janos sure. How can I test this out? Also whether this approach is better or using "schedule with fixed delay" and put a short, random pause in every execution? \$\endgroup\$ – arsenal Aug 30 '14 at 21:25
  • \$\begingroup\$ On the other hand - what are 1000 simultaneous calls to one box? The problem is elsewhere. \$\endgroup\$ – Thomas Junk Aug 30 '14 at 21:55
  • \$\begingroup\$ @ThomasJunk What I meant is - Above code is in some library and that library is being used in each machine so if number of machine is 1000 and all 1000 machines are getting started at same time, meaning background thread starts at same time, so there will be high load at same time. \$\endgroup\$ – arsenal Aug 30 '14 at 21:57
  • \$\begingroup\$ Yes. We are talking about those 1k calling 1 single box, right? \$\endgroup\$ – Thomas Junk Aug 30 '14 at 22:00
1
\$\begingroup\$

If you use a random delay and fixed period, all machines will make roughly the same number of calls during their lifetime. With this approach you can be sure that every machine makes a call within the period.

If you use a fixed delay and random period, then some machines may end up making more calls than average, and others less than average.

If you want more balanced calls, the first approach makes more sense.

To measure the actual load, add some logging on the server. To give you an example, given this simplified sample from an apache log:

66.249.67.190 - - [30/Aug/2014:04:28:23 -0700] "GET
66.249.67.203 - - [30/Aug/2014:04:28:34 -0700] "GET
66.249.65.126 - - [30/Aug/2014:05:32:54 -0700] "GET
66.249.65.126 - - [30/Aug/2014:05:32:54 -0700] "GET
66.249.65.118 - - [30/Aug/2014:08:11:20 -0700] "GET
66.249.65.118 - - [30/Aug/2014:08:11:20 -0700] "GET
66.249.65.126 - - [30/Aug/2014:08:11:21 -0700] "GET
180.76.5.168 - - [30/Aug/2014:14:30:57 -0700] "GET

I would extract the timestamp part using cut or awk commands, for example:

# extract the timestamp part, until minutes, without seconds
cat access.log | cut -d' ' -f4 | cut -d: -f-2
[30/Aug/2014:04
[30/Aug/2014:04
[30/Aug/2014:05
[30/Aug/2014:05
[30/Aug/2014:08
[30/Aug/2014:08
[30/Aug/2014:08
[30/Aug/2014:14

And pipe this to uniq -c to get a count per-minute:

cat access.log | cut -d' ' -f4 | cut -d: -f-2 | uniq -c
  2 [30/Aug/2014:04
  2 [30/Aug/2014:05
  3 [30/Aug/2014:08
  1 [30/Aug/2014:14

Hopefully you should see a balanced count, and a repeating pattern every 5 minutes.

This is just an example (and not the best way, quick and dirty way) of measuring the load, use whatever method that suits you best.

\$\endgroup\$
  • \$\begingroup\$ Thanks for your suggestion. It makes sense now. I will most probably go with my suggestion which I have in my question. Thanks for the help. I also have one more question for CR here. See if you can help me out if possible? \$\endgroup\$ – arsenal Aug 30 '14 at 21:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.