Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

I am hosting a website for a client on a dedicated VPS that has 512mb of RAM. Within the last 2 weeks, it has hosed up twice due to 0% free memory (or free swap). The site is pretty database intensive, as it's running Drupal with 60+ modules. It gets, on average (according to the website owner), about 6,000 visitors/month (~200/day). It will probably grow fairly quickly though - it was just launched less than a year ago.

So I'm sitting down to finally get a grasp on understanding Apache. I've hand configured httpd.conf before, but not fully understanding all of the intricacies.

I've learned that I should calculate my average Apache process size in Mb by MaxClients, and that this number shouldn't go above the memory available to the system. Each process size is a little under 7% (this would be about 1.4Mb, right?) according to Top. 512/1.5 = 341... this seems awfully big to me. Am I misunderstanding something? At first, I thought that I should calculate the process size by the percentage (in this case, ~7). Perhaps I was right the first time?

This gives a little room for other OS processes.

The database (MySQL) is on the same host.

My question is twofold. 1) I'm thinking about installing Varnish to help reduce the database load (almost all visitors are unauthenticated), to speed up initial response time, etc... For a system with this little amount of memory, am I insane? I'm thinking about giving it 256Mb if I do so. Thoughts? Obviously, things wouldn't stay in the cache for a long time. 256/7 = ~36 pages. My hope in this is, however, that the "main" pages would be cached. The homepage, and some of the main pages behind the homepage, are going to be pretty database intensive, and I'd like to reduce the amount of disk IO as much as possible.

2) If I did install Varnish, I'm wondering if I should tweak the Apache settings to half of what they're currently at, since I've given Varnish half the memory. What's the relationship between Varnish and Apache in this low-level configuration?

share|improve this question
    
While this doesn't directly relate to Varnish, another way to reduce the load on your server is to switch to using nginx. I switched from Apache to nginx (with PHP-FPM) on one of my 512MB VPS and it was drastic how much the memory footprint was reduced. –  Daniel Nov 10 '11 at 14:28

1 Answer 1

up vote 14 down vote accepted

You need to get a larger VM. You start your post out telling us that your VM has "hosed up" twice now due to memory exhaustion and swapping. How would adding yet another application that benefits from a large amount of memory help your situation? It won't.

Let's break down your little VM and its memory usage.

First, you have 512 MB of RAM. Take 100 to 125 MB (20-25%) of this and completely remove it from your calculations. This RAM is needed by your kernel, supporting processes, buffers and cache. This leaves you with 400 MB of RAM (split the difference).

MySQL

Let's say you want to use half of your 400 MB, giving MySQL 200MB. Let me make it clear that I'm not familiar with Drupal's requirements, or whether it uses MyISAM or InnoDB. If you were configuring InnoDB you'd use the innodb_buffer_pool_size variable and just set that to 200M. You can expect MySQL to use more than this however for things like query cache (if used), open tables, connection handling, thread tracking, sort buffers, join buffers, and countless other configuration options. If you're using MyISAM it's even more complicated because there are a lot more variables involved, key_buffer and myisam_sort_buffer are just two of several. So, assuming InnoDB with a 200M innodb_buffer_pool_size and the query cache disabled let's say MySQL consumes 216 MB of RAM.

Apache

You now have 184 MB of RAM left for Apache to use. First, lets take a moment to clear up some of the really confusing things in your question.

I've learned that I should calculate my average Apache process size in Mb by MaxClients, and that this number shouldn't go above the memory available to the system.

No. You observe your average httpd process size when your site is in use. Using the average size per httpd process (assuming prefork MPM, the default) you calculate what MaxClients can be so that you don't exceed the memory allotted to httpd or the machine, causing it to swap.

Each process size is a little under 7% (this would be about 1.4Mb, right?) according to Top. 512/1.5 = 341... this seems awfully big to me. Am I misunderstanding something?

Yes, you are. First, stop using percentage to "calculate" the size of the httpd processes.


Edit

Wait! What? 7% of 512 is 35.84. I'm not sure where you got 1.4 Mb from. My answer still stands, and I won't be adjusting my answer to compensate for your 35M httpd processes.

End Edit


The size of the httpd processes is listed plainly in top under the RES column. For example:

top - 21:48:44 up 168 days,  4:46,  1 user,  load average: 0.02, 0.09, 0.08
Tasks:  66 total,   2 running,  64 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Mem:   2072832k total,  1994784k used,    78048k free,   407976k buffers
Swap:   787176k total,      300k used,   786876k free,  1321988k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                                                                                       
 8725 mysql     20   0  729m  69m 3396 S  0.0  3.4  53:45.84 mysqld                                                                                                         
22217 apache    20   0  161m  17m 7960 S  0.0  0.9   0:08.42 apache2                                                                                                        
26193 apache    20   0  161m  16m 6944 S  0.0  0.8   0:00.26 apache2                                                                                                        
 4470 apache    20   0  161m  16m 6948 S  0.0  0.8   0:01.52 apache2                                                                                                        
 6193 apache    20   0  161m  15m 6608 S  0.0  0.8   0:01.35 apache2                                                                                                        
 4014 apache    20   0  161m  15m 6616 S  0.0  0.8   0:01.48 apache2                                                                                                        
 6939 apache    20   0  161m  15m 6608 S  0.0  0.8   0:01.48 apache2                                                                                                        
 6685 apache    20   0  161m  15m 6608 S  0.0  0.8   0:01.32 apache2                                                                                                        
26146 apache    20   0  161m  15m 6604 S  0.0  0.8   0:00.38 apache2                                                                                                        
 6443 apache    20   0  161m  14m 5712 S  0.0  0.7   0:01.38 apache2                                                                                                        
26450 apache    20   0  161m  14m 5704 S  0.0  0.7   0:00.19 apache2                                                                                                        
 2524 root      20   0  159m  13m 5524 S  0.0  0.6   0:03.34 apache2   

Technically the memory used per process the difference of RES and SHR (shared). This is because SHR is memory shared by other processes. You can see on the example I showed you this is roughly 9 MB on average, for my unique use case. This is simply a machine running Cacti with virtually no traffic -- maybe 5-10 hits per day if I happen to look at it. I am skeptical that Drupal utilizes so little memory, but you'll be able to easily tell. It definitely uses much more than 1.4 MB.

Now, lets take a very unrealistic assumption that your httpd processes will utilize an even 10 MB of RAM every time. With 184 MB of RAM "allocated" for Apache, this leaves you with a MaxClients of 18 (10 MB * 18 = 180 MB). Much much much less than 341.

Varnish

First, lets evaluate the current state of your server. Assuming you properly configured MySQL and httpd to not swap under load, you're running with what is a pretty anemic MySQL configuration and an httpd configuration that will start to refuse requests if you ever get more than 18 concurrent requests. By any standards this machine is in no shape to handle traffic that will "grow very quickly".

Now you want to add a third application in and allocate 256MB of RAM to it?! That RAM will have to come from either MySQL or Apache, and maybe you could get away with stealing some from the OS itself. Either way you're further gimping one of the core services on your machine.

It's technically possible that you could find the sweet spot of configuration settings for Varnish, Apache, and MySQL on the same host that allowed all to operate at ideal efficiency with just the right amount of RAM, but I'm skeptical.

The Solution

Use what I've taught you about configuring MySQL and Apache correctly to do exactly that: configure them correctly. Your MaxClients should be nowhere near 300, very likely under 20, and quite possibly under 10. Another thing I haven't mentioned is that httpd processes can be a little reluctant to relinquish RAM when they've "peaked" much higher than the average. e.g. If a httpd worker hit 20MB for a single request, that worker will continue to use 20MB indefinitely (afaik) until it is reaped. You can address this by lowering your MaxRequestsPerChild setting. Lowering this means child processes are reaped more frequently. This will slow down your performance under load (forking new processes is relatively expensive), but it will help keep your memory usage manageable.

Configured properly your server should never swap. If you configure your server properly and you see issues such as refused connections under load, then I would suggest either expanding your VM, or look into adding Varnish on a separate dedicated VM.

You're off to the right start by reading the docs and seeking help online. If you get stuck or need in-depth help please feel free to ask in another question, but don't forget to search first! It's quite possible that you can find your answer in another.

share|improve this answer
    
As an added note, the Drupal documentation states that a PHP memory limit of 16 MB is the minimum required, and that 32 MB or 64 MB are not uncommon. This means that if PHP is using the full 16M of RAM per request then each httpd worker will be at least 16M in size, not the 10M I used as an unrealistic example. –  hobodave Feb 23 '11 at 4:25
    
It's also not unreasonable to be even more stingy with the RAM you give to MySQL depending on what it's using in practice. If you can get away with 64 or 100M for MySQL then do it, and leave that RAM for httpd. –  hobodave Feb 23 '11 at 4:37
    
I just added a blurb to my answer (see Edit). I wrongly assumed the OP didn't fail at math. :) 7% of 512 is ~36MB, nowhere near "1.4 Mb". With 184 MB of memory allocated for httpd and an average process size of 30M (assuming 6M shared) you would have no more than 6 MaxClients. –  hobodave Feb 23 '11 at 7:43
1  
This is very helpful. Thanks for the thoughtful, comprehensive response. A) I did almost fail highschool and college math. :) I'm not sure where I got the 1.4Mb either. I thought that sounded off too. B) I'm an idiot - of course I can see the MB in the RES column. Thanks for pointing that out. C) The info you gave on MySQL config is especially helpful. Looking at my.cnf, the server is horribly configured. I'll do more reading on that. D) I had already suggested to the client that we may need to get more RAM. We probably will, as well as fix the current configs. E) Thanks again. –  David W Feb 23 '11 at 12:20
    
As a follow-up to this, your general innodb_buffer_pool_size recommendation is helpful. I've read on a couple of places now that this should be set to ~10% higher than the size of the database. The database is currently ~33mb, so assuming that it's going to grow, I'm going to assume for a 100mb db within the next year. Thus, I was thinking about setting innodb_buffer_pool_size to 110mb. Your thoughts? –  David W Feb 23 '11 at 12:44

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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