We have a php based web application and are expecting a big spike in traffic in 2 days.

We are set up on a standard Rackspace LAMP stack and will throw as many servers at it as we can but the application is quite memory and db intensive so there will be some ceiling of max concurrent users that we will not be able to exceed given the small amount of time we have.

We have been working to implement memcached but due to the nature of the application it is proving difficult to do effectively.

The traffic is only expected to last for a couple of hours and our main concern is that the site doesn't crash which would bring sales to a halt.

Whats the easiest way to display an error message that says "Sorry we are experiencing heavy traffic, please try again soon." When the servers are experiencing too heavy load?

In this way we could serve our proper web application and then when the request queue starts to fill up then we can just serve the simple static friendly html traffic message.

I know that with a naive approach it will mean that some people who are just about to buy something will get the error message and then might have to go back to the beginning of the process, which isn't ideal, but given the short time-frame we just need the site not to crash and stop sales. How do we do this?

Any help would be hugely appreciated!

Accepted Answer

If by "heavy load" you mean CPU load this would be quite easy with sys_getloadavg(), an example:

$load = sys_getloadavg();
$cores = intval(trim(shell_exec('grep physical /proc/cpuinfo | sort -u | wc -l')));

if ($load[0] > $cores)
{
    // machine was under heavy load in the last minute
}

else if ($load[1] > $cores)
{
    // machine was under heavy load in the last 5 minutes
}

else if ($load[2] > $cores)
{
    // machine was under heavy load in the last 15 minutes
}

Depending on your available memory and the number of allowed PHP processes you might wanna just delay the response for a couple of milliseconds using usleep() instead of showing a "under heavy load" message. Be aware that while sleeping, the process is still eating your memory and web server threads so you need to be careful with this - you can delay the response depending on the load, i.e.:

if (($load[1] / $cores) >= 1)
{
   $delay = ($load[1] / $cores) / 10;

   if ($delay >= 0.5) // never delay for more than 0.5 seconds
   {
       exit('heavy load sorry');
   }

   usleep($delay * 1000000);
}

The higher the load, the higher the delay, this would give time for the CPU to catch up with all the work.

If you're running a distributed load balancer you might wanna keep these values in memcached, also storing the $cores variable in APC or similar will probably give you a performance boost.

If you meant other kind of load (like users or memory) the logic is similar, all you need to worry about is to get the relevant metric and store it, either on APC or memcached if you need distributed logic.

PS: ServerFault might be a better place to ask this kind of questions.

Written by Alix Axel
This page was build to provide you fast access to the question and the direct accepted answer.
The content is written by members of the stackoverflow.com community.
It is licensed under cc-wiki