Wow, it's taking an awful lot of work trying to keep this site running right now. The server we're currently running on is a virtual CentOS machine with 256MB RAM, and the constant traffic from both users and robots (crawlers) causes Apache to lock up from time to time. Right now I'm tweaking all the LAMP (Linux, Apache, MySQL, and PHP) knobs I know how to tweak to keep the site more or less running most of the day.
Here's a quick review of the hacks, er, performance optimizations, I've been working on.
Really, I'm doing very little with Linux, other than using tools like top, uptime, ps, and vmstat to see what's happening on the server, i.e., what changes with each tweak I make elsewhere. Other than that most of the tweaks are Apache tweaks, including variables like MaxClients, MaxRequestsPerChild, and KeepAliveTimeout.
I've tried to convince MySQL to use less RAM by turning off everything I don't need. For instance, I have a number of settings like this in my /etc/my.cnf file:
skip-bdb skip-ndbcluster skip-networking
I'm also looking for slow queries, but that hasn't really been much of a problem. I also reduced the maximum number of connections, but again, I don't think that had much effect.
I'm also trying to tweak the knobs on PHP and Drupal, and this has been the biggest learning experience. In Drupal I've turned off and removed every non-essential module (including my favorite admin_menu module), and I've been running the following PHP commands inside my theme from time to time:
<?php echo memory_get_usage(); echo memory_get_peak_usage(); ?>
This has helped to show me that from within a page served up by Drupal, my max memory use reported here is less than 12MB. By default PHP was installed to use a max of 128MB RAM, so I've cranked that way down, and I haven't had an "out of memory" errors recently.
After all of this work, Apache seems to be the largest culprit. Did you know that Apache processes can swell to 20-30MB each when serving up dynamic content? Did you also know that the same 30MB process that served up a dynamic page might later be used to serve up static content -- like little, bitty images? I really had no idea the processes themselves could get that large; I've always been a Java guy, and just used Apache as a proxy to a Java web server.
After many, many changes to both Drupal and Apache, my Apache httpd processes now show up as 16m when looking at them with the top command. I've looked and looked, and I don't see what else to remove, so that's probably as low as I can go there. When you think about it, if you have 256MB RAM available, and each Apache process takes as much as 16MB RAM, you can't have many Apache processes running at one time, can you?
(As mentioned earlier, most of my Apache tweaks have been around the MaxClients, MaxRequestsPerChild, and KeepAliveTimeout variables. There have been others, including turning off some internationalization features, but most of what I'm doing now centers around these three variables, and other closely related variables.)
Really, the only other Apache optimization that I've read about has to do with .htaccess files, specifically disabling their use. Did you know that if you have a directory structure that goes five levels deep, and if you have AllowOverride set to all, and someone requests a document in that lowest directory, Apache has to look in that directory, and all four directories above it to see if there is a .htaccess file in any directory? I knew this, but I never really thought about all the work that was required to serve many of the documents on this site, so I'll be setting AllowOverride None as soon as I can clean up some related things around here.
All in all, it's been a heck of a learning experience, and I suppose it's good to learn about all these things now. My hope is to grow this site at least 10x, so I might as well learn all these things now, so I can be smarter about my needs in the future.
MySQL memory management recipes
If you need help with MySQL memory management, the MySQL Admin Guide (2nd edition) has nice recipes on p. 475, specifically for dealing with "little memory and lots of connections".
Don't use Apache worker mpm with php
FYI - Make sure you use Apache's prefork mpm, and not worker mpm. This is from the php 5.2.x INSTALL file:
"We do not recommend using a threaded MPM in production with Apache2.
Use the prefork MPM instead, or use Apache1. For information on why,
read the related FAQ entry on using Apache2 with a threaded MPM."
Apache memory usage
You're looking at it naively -- the memory usage for each httpd process includes any shared libraries and other memory that shared (copy-on-write) with other httpd processes. Marginal overhead is much lower in most cases.
Using top command output
I agree, I am probably looking at it naively, as I've never been a Unix systems programmer, and I don't fully understand memory usage. The only thing I can go by is what I see with the
topcommand, and my understanding of those results.For instance, here's a subset of the current
topcommand output related tohttpdprocesses:The first two lines of this output are a little misleading, because this site was on a shared, virtual server, and there was really only 256 MB RAM available to me. I was supposed to be allowed "bursts" up to 1 GB, but I never saw RAM usage anywhere near that high; the system would always bog down before getting near that peak. I don't know if that was because of the throttling mechanism in place, or something else. As a practical matter, whenever RAM usage exceeded 300-350 MB, the system became non-responsive, and the best thing to do was restart Apache.
After the first two lines of output, all the remaining lines are related to httpd processes. The three columns I looked at were RES, SHR, and %MEM. I don't know how else to interpret these other than the output from the
topman page, which looks like this:RES Resident size (kb) The non-swapped physical memory a task has used. RES = CODE + DATA. SHR Shared Mem size (kb) The amount of shared memory used by a task. It simply reflects memory that could be potentially shared with other processes. %MEM Memory usage (RES) A task’s currently used share of available physical memory.In summary, when I first started down this road, I would typically see many Apache
httpdprocesses showing 16 or 17 MB in theREScolumn, with other smaller entries like the last one shown above, with 8648 in theREScolumn. And the "memory used" data above the columnar top output exceeded 256 MB RAM.By tweaking Apache's settings as described in this series, I was able to get more of these smaller RAM processes, and fewer of the 17 MB entries. As far as I could tell, these tweaks kept memory use down, and kept the server alive longer than the initial Apache settings.
The part I don't fully understand is the 14-15 MB difference between RES and SHR for most of those httpd processes. For instance, I think the first row is saying that 17 MB RAM is used by this process, and 2,684 KB of this may be shared with other processes. If this output is saying that 2,684 KB is shared, that's nice to know, but as a sysadmin whose server appears to be running out of memory, my only real concern is whether this process -- and the processes below it -- are all taking 16-17 MB RAM.
Sorry for this lengthy reply, but thanks for your feedback.
apache serving images
With your memory so constrained, it makes sense to minimize the amount of memory apache and php are using for any request. But another, parallel approach is to minimize the actual number of hits per page request, by off-loading static image and/or file requests to a static file server.
Put another way - why waste all that memory on requests that don't need it - you may find that up to 75% of your traffic is this kind of static file request.
Start with http://drupal.org/project/cdn and then google for drupal and static file servers. Amazon S3 is ridiculously cheap, and even if you just move your static theme images onto it, you'll save yourself a bunch of hits on your drupal server.
Thank you, those are good
Thank you, those are good suggestions. As you mention, they won't bring the memory use down, but they will help take the load off the server. In my case I have a couple of almost-free domains I can use to serve images from instead of something like S3, but we did use S3 at my former company. Thanks again.
Post new comment