imperialWicket

am i the only croquet-playing computer nerd?

« Increase PHP memory_limit on GoDaddy shared Linux hosting How about some open source days? »

Tuning Apache for a low memory server (like AWS Micro EC2 instances)

2012-01-9

One of my goals for 2012 is moving away from shared hosting and toward cloud and/or small VPS servers. For now, I am targeting AWS Micro instances for a lot of my efforts. Ultimately, I will probably move to Lighttpd or Nginx, but in the mean time I thought I would relay a configuration that is working well for me on low traffic sites.

For anyone seeing performance or stability issues on a micro instances (using LAMP) that get reasonable traffic, you are probably encountering something like:

  • WSOD (White screen of death) - most often this is actually a out of memory error in PHP
  • MySQL failing to start or getting killed - this is usually apache using all the memory and the kernel shutting down the MySQL server
  • Actual output of Out Of Memory errors in PHP - really the same as above
  • MySQL failing to start due to pthread create returned 11 - MySQL can't create a new thread, probably because apache is using too many.

The root cause of these problems is lack of memory. Before you shut down your micro instance in favor of a small instance, or go back to shared hosting, consider tuning apache down a few notches. The default apache configuration is actually quite inappropriate to a server with 1GB or less memory. The default changes a little from one Linux distribution to the next, but for reference I'll describe the Amazon Linux defaults.

Amazon Linux default apache config

This is all stored in the /etc/httpd/conf/httpd.conf file. There is a lot in this file, but most of what we want to discuss is near the beginning. Our biggest concerns have to do with KeepAlives and the prefork module. If you are using workers, you will also want to review the worker module configuration -- which is very analogous to the prefork module configuration.

Timeout

The default timeout is 60 (seconds). This is ridiculous. Have you ever waited 60 seconds for a site to load? I turn this down to the 20-30 second range.

KeepAlive

KeepAlive defaults to Off in Amazon Linux. Enabling KeepAlive can avoid generating/killing so many apache child threads, but if your users tend to only view a page or two, this makes no difference, because apache only persists the thread for a given connection. If you have high user engagement, you probably want KeepAlive on, but you should tune it down to keep your total apache thread count low. I have it enabled in my example config below, but for many of my sites, visitor engagement is relatively low, and I simply leave it disabled.

MaxKeepAliveRequests and KeepAliveTimeout

If you enabled KeepAlive on your low memory server, you should reduce the MaxKeepAliveRequests and KeepAliveTimeout. MaxKeepAliveRequests defaults to 100, which seems relatively low, but how many users do you actually have making 100 requests to your server per session? Related to this is the KeepAliveTimeout value, which defaults to 15 (seconds). In my mind, 15 seconds is longer than a short page view requires, and shorter than a long page view requires. That is, if someone hits my site and realizes the page is not what they want, they look at tags/categories/menu/whatever and decide to look at something else. The time required for this is usually more like 5-10 seconds. There is no reason to keep the thread alive for 15 seconds. The opposite end of this spectrum is a user who reviews an entire page, and then elects to review a previous or alternate article, in this scenario more than 15 seconds often elapses, and the user generates a new thread anyway. If you enabled KeepAlive, I recommend reducing KeepAliveTimeout to 5 or 10 seconds. MaxKeepAliveRequests probably won't be an issue, but 25 or 50 is likely to behave in the same way as 100, and under the low chance that something awkward is happening, the lower maximum will curtail the issue sooner.

Prefork Module

Prefork is where the real magic happens. This is where we can tell apache to only generate so many processes. The defaults here are high, limiting you to a max of 256 servers. Just to put this in perspective, let's say you get 10 concurrent requests for a php page, and that page happens to require around 64MB of RAM when requested (well within the default php memory_limit of 128MB on Amazon Linux). That's around 640MB of RAM usage on your 613MB micro instance. And that's with only 10 connections - apache is configured to allow 256! I scale these down a lot, usually sticking with 10-12 MaxClients. As we mentioned in our example, this is still a dangerous number because 10-12 concurrent connections would use all our memory. If you want to be really cautious, make sure that your max memory usage is less than 613MB (on an AWS micro instance - 512MB is common on VPS from other providers). Something like 64M php memory limit and 8 max clients keeps you under your limit with space to spare - this helps ensure that the kernel won't do something crazy like killing the MySQL process when your server is under load.

You can play with the MinSpareServers, MaxSpareServers, StartServers, and MaxRequestsPerChild; but within the context of less than 20 MaxClients, making changes like 3 StartServers vs 5 StartServers will have almost no visible impact.

Without further ado, here are some values to get you started. Tweak away, and have fun - welcome to httpd.conf (use apache2.conf if you're on debian).

/etc/httpd/conf/httpd.conf

Timeout 30
KeepAlive On
MaxKeepAliveRequests 50
KeepAliveTimeout 10


    StartServers          3
    MinSpareServers       2
    MaxSpareServers       5
    MaxClients            10
    MaxRequestsPerChild   1000


# if you are using workers, update the IfModule worker.c section similarly.

/etc/php.ini

memory_limit = 100M

14 Responses to Tuning Apache for a low memory server (like AWS Micro EC2 instances)

Feed for this Entry

9 Comments

  • Is there an instance that you recommend for me to get started? I want to have a basic apache server (I am familiar with Ubuntu) all I need is the FancyIndex feature. I want to use fancyindex to distribute pdf files to my sales team and branch offices. Should have around 5 GB of PDF's and think I should store them on S3. This is all quite overwhelming. I am doing this currently on a hosted ($8/month) plan with bluehost but am violating their terms so am worried they will shut me down. Having said that it's been a year and they have not said anything.

    Thanks for any help or direction you can give me with this aws setup.

    Pierre

    #7481 | Comment by Pierre on Jan 17, 2012 09:04am
  • I usually use Amazon Linux (a barebones RedHat derivative), but if you prefer ubuntu, you can use canonical's own amis: 10.04 LTS. Newer releases are available at the 'releases/' directory, but I'd recommend sticking with LTS releases. It sounds like a Micro or Small instance would suffice (note that small instances are only available in 32 bit).

    That said, a service like MediaTemple's grid hosting might be a better option for you. It sounds like the administrative overhead and cost might work out to be a lot more overall effort using AWS for these purposes, as opposed to a shared hosting solution.

  • I've signed up with Media Temple.
    Thanks!

    #7569 | Comment by Pierre on Jan 17, 2012 06:28pm
  • Why worry about getting apache's memory footprint down when you can run Nginx or lighttpd? They both offer extreme speed, scale-ability, and their memory footprint is minute. I just set up Habari on my home server and it worked fantastically. I also run most of my Wordpress installs on the same server.

    #8153 | Comment by ClashTheBunny on Feb 19, 2012 01:06am
  • @ClashTheBunny - Apache still has the most popularity. I agree that a web server that avoids spawning unique processes per request (like Nginx or lighttpd) would be a much better choice on a low memory server. Nonetheless, I get a lot of requests for such Apache configs, and they generally aren't interested in the recommendation to use an alternate web server.

  • Thank you for this post. I am starting out with AWS and plan on using an EC2 micro instance for my personal blog site. This information helps greatly. Thank you.

    Can you be more specific about the recommending settings for workers.c section of httpd.conf?

    #15056 | Comment by Johnny on May 1, 2013 06:55am
  • @Johnny - Default Apache has a worker config available, but for most standard scripting languages you won't use workers. If you were linking Apache to a backend java servlet container, workers would likely be in the mix. If this were the case, you would want to add the exact same config for servers/clients max/mins within the worker.c config section to delimit those connections as well.

  • Please let me know any formula to how to calculate max client and MaxKeepAliveRequests and MaxRequestsPerChild to any servers.

    Please share

    #16084 | Comment by Ashok on May 16, 2013 06:26am
  • @Ashok - Keepalives are tricky. Depending on exactly whats happening, having keepalives enabled sometimes uses more memory than just disabling it entirely. It's worth flipping it on or off and investigating server behavior. A place where keepalive helps is when SSL is used, where the SSL handshake only needs to occur again after the keepalive expires. This saves a lot of bandwidth overhead and latency for the user. In non-SSL scenarios, it's a much more nebulous benefit.

    Under general use MaxRequestsPerChild just serves to protect any DOS/robot hits, and keeps a single process from wrecking everything. The limit here needs to consider how many individual requests to a server a user is going to require. For example, if your page retrieves 17 resources from the server when someone loads it, setting MaxRequestsPerChild to 15 will cause issues, because each page load will need to spawn multiple processes. If you're concerned about robots/DOS, I'd recommend setting MaxRequestsPerChild based on the number of server requests you expect a human user to require.

    MaxClients is a RAM equation. You likely have a large number of cacheable requests (images, static files, etc.), these play a small role in the consideration. Mostly your scripting efforts matter. If you are running PHP, and each apache-PHP process can use 100MB of RAM, then you want to make sure that MaxClients * 100MB corresponds appropriate to the available RAM on the machine. You can usually cheat here to a degree, based on the fact that it's almost never the case that a site receives a multitude of exactly concurrent requests for the same page; but if you do, kernel level errors where memory and swap run out are a possibility.


About You

Email address is not published

Add to the Discussion

Search