Memory usage of php-cgi processes is growing steadily

I'm trying to set up a web server on a linode 360. My problem is that memory usage of php-cgi processes increases over time even though the website is not receiving any traffic at all. (it is behind a firewall for the time being)

I'm using Debian Lenny 32bit and its lighttpd and php5-cgi packages. Apart from some config changes (listed below), I'm using the stock setup by Debian.

The website is based on Drupal. Using Drupal's debugging module (called devel), I can tell that memory usage of PHP scripts is less than 20KB on average, and it never exceeds 8MB.

Here are the relevant parts from the output of ps aux:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
www-data 29871  0.0  1.7  54552  6368 ?        Ss   Aug12   0:00 /usr/bin/php-cgi
www-data 29873  0.0  7.4  65808 27468 ?        S    Aug12   0:00 /usr/bin/php-cgi
www-data 29874  0.0  3.7  55808 13736 ?        S    Aug12   0:00 /usr/bin/php-cgi
www-data 29875  0.0  4.3  58040 16204 ?        S    Aug12   0:00 /usr/bin/php-cgi
www-data 29876  0.0  4.4  57444 16288 ?        S    Aug12   0:00 /usr/bin/php-cgi
www-data 29877  0.0  1.7  54552  6368 ?        Ss   Aug12   0:00 /usr/bin/php-cgi
www-data 29879  0.0  9.6  67140 35684 ?        S    Aug12   0:26 /usr/bin/php-cgi
www-data 29880  0.0  6.6  59172 24492 ?        S    Aug12   0:23 /usr/bin/php-cgi
www-data 29881  0.0  7.1  59784 26388 ?        S    Aug12   0:22 /usr/bin/php-cgi
www-data 29882  0.0  7.4  60880 27440 ?        S    Aug12   0:23 /usr/bin/php-cgi

* Is it normal to have php-cgi this large?

  • Is it possible to estimate php-cgi memory usage based on settings?

  • Any tips for reducing memory consumption of php-cgi processes?

Searching for known memory leaking bugs didn't yield anything relevant. And I'd be surprised if the default Debian packages/config had such an obvious memory leak. Other users on the same host do not have this problem.

What I've done so far is set PHPFCGIMAX_REQUESTS to a low value so that php-cgi processes are recycled quickly. When I use ab to simulate high load, this works very well. Processes die quickly before they grow higher than 10MB. However, under low-to-medium load, all processes grow steadily (because of load balancing) and most of them consume 28MB+ simultaneously, putting my VPS at risk of swapping. Please note than even without any sort of traffic, the processes grow steadily.

I can reduce the number of php-cgi processes, but this feels like a workaround more than a fix. I'd be surprised if php-cgi normally grew like this.

Also, summing the total RSS numbers for php-cgi processes gives:

$ ps -C php-cgi -o rss= | awk '{s+=$1}END{print s/1024}'
195.738

Yet, free -m gives the following output:

             total       used       free     shared    buffers     cached
Mem:           360        351          8          0         33        190
-/+ buffers/cache:        127        232
Swap:          255          0        255

* Am I missing something? How come the used memory (without buffers) is lower than the total resident memory of php-cgi processes on the host?

I have the following PHP extensions:

php5-cgi php5-common php5-curl php5-gd php5-mysql php5-xcache

xcache.size is set to 24M. It used to be 32M but reducing it didn't help. xcache.var_size is set to 0. The remaining plugins are using the stock configuration. The xcache admin pages shows that xcache is using less than 1MB.

PHP's memory_limit is set to 32M.

Here is my FastCGI config:

fastcgi.server    = ( ".php" =>
  ((
    "bin-path" => "/usr/bin/php-cgi",
    "socket" => "/tmp/php.socket",
    "max-procs" => 2,
    "idle-timeout" => 20,
    "bin-environment" => (
      "PHP_FCGI_CHILDREN" => "4",
      "PHP_FCGI_MAX_REQUESTS" => "1000"
    ),
    "bin-copy-environment" => (
      "PATH", "SHELL", "USER"
    ),  
    "broken-scriptfilename" => "enable" 
  ))
)

I'm using more-or-less the stock lighttpd.conf that ships with Debian.

Please let me know if there is any other data that I can provide.

Any help is appreciated. I've been trying to troubleshoot this for days. I've run out of ideas.

8 Replies

I'm also on a 360, and I've noticed that php5-cgi is really eating way too much memory than it should.

htop tells me I'm using nearly 120MB. This has only just become a problem, I'm still running pretty much the same thing on my server since I first turned it on (as well as dnscache and irssi now) and memory has just shot up over time. I simply don't understand it.

Edit: Well waddaya know… Simply restarting lighty took memory usage to just 80MB. php5-cgi is still gobbling up a bit too much but at least one thing's solved…

Restarting reduces memory usage only temporarily. A few hours after the restart, memory usage would be back to where it was.

Yeah I already noticed… Visiting my site once ate 9MB.

Memory usage displayed on ps isn't exactly intuitive. I suspect a lot of it has to do with memory the instances are sharing. In any case, at least from the ps and free you pasted, you're probably in reasonable shape. I wouldn't be worried.

My recommendations:

  • Right now, lighttpd is set to spawn two processes, which will each spawn four children (for a total of 8 children). This isn't a good idea if you're using an opcode cacher (e.g. xcache); set your max-procs to 1. You can then twiddle PHPFCGICHILDREN if you need more actual children, although four should be fine for most purposes.

  • Removing the idle-timeout may help performance, although it won't impact memory consumption. (The goal is to use memory wisely, not to avoid using it.)

Here's what I'm seeing on an Ubuntu 8.04 (32-bit) system… note that I use spawn-fcgi, run each application as its own username, and use different child limits for each. So, basically, I'm violating my first recommendation above in the name of better isolation :-)

             total       used       free     shared    buffers     cached
Mem:           348        332         16          0         74        112
-/+ buffers/cache:        145        203
Swap:          255         56        199

asterisk  2744  0.0  0.8  37532  2900 ?        Ss   Aug12   0:00 /usr/bin/php-cgi
asterisk  2745  0.0  0.5  37532  2024 ?        S    Aug12   0:00 /usr/bin/php-cgi
asterisk  2746  0.0  0.5  37532  2024 ?        S    Aug12   0:00 /usr/bin/php-cgi
blogs     2748  0.0  0.8  37532  2912 ?        Ss   Aug12   0:00 /usr/bin/php-cgi
blogs     4632  0.0  4.2  39224 15236 ?        S    Aug13   0:28 /usr/bin/php-cgi
blogs     5371  0.0  4.4  40520 16012 ?        S    Aug13   0:27 /usr/bin/php-cgi
blogs     5375  0.0  5.0  40828 17904 ?        S    Aug13   0:27 /usr/bin/php-cgi
blogs     5378  0.0  4.9  41912 17800 ?        S    Aug13   0:27 /usr/bin/php-cgi
gallery2 15103  0.0  4.4  41624 15892 ?        S    Aug13   0:00 /usr/bin/php-cgi
gallery2  2756  0.0  0.8  37532  2908 ?        Ss   Aug12   0:00 /usr/bin/php-cgi
gallery2  6536  0.0  4.1  40024 14788 ?        S    Aug13   0:00 /usr/bin/php-cgi
gallery2  6550  0.0  4.0  40012 14344 ?        S    Aug13   0:00 /usr/bin/php-cgi

The first batch gets nearly zero traffic (n'fact, I don't think it's had any since I started it…); the second and third batches get a lot of traffic. I thought I was using xcache, but I don't have anything mentioning it in php.ini, so perhaps I'm not.

Thanks for your reply.

@hoopycat:

Memory usage displayed on ps isn't exactly intuitive. I suspect a lot of it has to do with memory the instances are sharing. In any case, at least from the ps and free you pasted, you're probably in reasonable shape. I wouldn't be worried.

Indeed, I don't fully understand the numbers. Perhaps the RSS values include cache/buffers? Because the sum of the RSS values adds up to more than the total system memory. Yet, the free command reports plenty of free memory.

> My recommendations:

  • Right now, lighttpd is set to spawn two processes, which will each spawn four children (for a total of 8 children). This isn't a good idea if you're using an opcode cacher (e.g. xcache); set your max-procs to 1. You can then twiddle PHPFCGICHILDREN if you need more actual children, although four should be fine for most purposes.

Good point, I will make this change and see how it goes. My initial idea was to have 2 process trees so that if one dies, the other would be immediately available. Also, I thought that this would utilize the multi-core system better. Keep in mind that I don't fully understand how requests are handled by FastCGI so it is likely that my ideas are inaccurate or wrong.

Interestingly, the 2 parent processes never grow above 7MB. It is the children who consume most of the memory. Furthermore, the admin interface of xcache reports that all of my PHP pages are cached in 2MB.

> - Removing the idle-timeout may help performance, although it won't impact memory consumption. (The goal is to use memory wisely, not to avoid using it.)

Already done this.

> Here's what I'm seeing on an Ubuntu 8.04 (32-bit) system… note that I use spawn-fcgi, run each application as its own username, and use different child limits for each. So, basically, I'm violating my first recommendation above in the name of better isolation :-)

             total       used       free     shared    buffers     cached
Mem:           348        332         16          0         74        112
-/+ buffers/cache:        145        203
Swap:          255         56        199

asterisk  2744  0.0  0.8  37532  2900 ?        Ss   Aug12   0:00 /usr/bin/php-cgi
asterisk  2745  0.0  0.5  37532  2024 ?        S    Aug12   0:00 /usr/bin/php-cgi
asterisk  2746  0.0  0.5  37532  2024 ?        S    Aug12   0:00 /usr/bin/php-cgi
blogs     2748  0.0  0.8  37532  2912 ?        Ss   Aug12   0:00 /usr/bin/php-cgi
blogs     4632  0.0  4.2  39224 15236 ?        S    Aug13   0:28 /usr/bin/php-cgi
blogs     5371  0.0  4.4  40520 16012 ?        S    Aug13   0:27 /usr/bin/php-cgi
blogs     5375  0.0  5.0  40828 17904 ?        S    Aug13   0:27 /usr/bin/php-cgi
blogs     5378  0.0  4.9  41912 17800 ?        S    Aug13   0:27 /usr/bin/php-cgi
gallery2 15103  0.0  4.4  41624 15892 ?        S    Aug13   0:00 /usr/bin/php-cgi
gallery2  2756  0.0  0.8  37532  2908 ?        Ss   Aug12   0:00 /usr/bin/php-cgi
gallery2  6536  0.0  4.1  40024 14788 ?        S    Aug13   0:00 /usr/bin/php-cgi
gallery2  6550  0.0  4.0  40012 14344 ?        S    Aug13   0:00 /usr/bin/php-cgi

The first batch gets nearly zero traffic (n'fact, I don't think it's had any since I started it…); the second and third batches get a lot of traffic. I thought I was using xcache, but I don't have anything mentioning it in php.ini, so perhaps I'm not.

Thanks for sharing. Your numbers are a bit lower than mine.

By the way, you can grab the xcache admin interface here and install it to see if xcache actually works.

I don't think it's abnormal for PHP FastCGI processes to have an RSS value of ~30MB, especially when using an opcode cache. I see it all the time on my lighty+PHP setup. Some memory is shared so the numbers don't really add up, but you can't realistically expect PHP to take up only the amount of RAM that is reported by Drupal. The interpreter alone takes up 12MB or more. The amount consumed by your code goes on top of it.

The key to FastCGI on a small VPS is to keep the number of processes as low as possible without hurting performance. In your case you can probably make do with just 4, and likely no more than 8. Just do the following math:

How many dynamic requests do you handle per second? e.g. 20

How long does it take for the average request to be handled? e.g. 0.2 second

Multiply the two numbers, e.g. 20 x 0.2 = 4

Then you need a minimum of 4 FastCGI processes.

@ah:

Good point, I will make this change and see how it goes. My initial idea was to have 2 process trees so that if one dies, the other would be immediately available. Also, I thought that this would utilize the multi-core system better. Keep in mind that I don't fully understand how requests are handled by FastCGI so it is likely that my ideas are inaccurate or wrong.

The children handle the requests, so they're already nicely split across the multiple cores. PHP is handling all of the multi-processor (and probably some of the redundancy) for you. What a deal! :-)

Speaking of xcache, I did some digging through the config and it looks like xcache.count is a good thing to set to "4". That might eek out some more performance.

> Thanks for sharing. Your numbers are a bit lower than mine.

Different applications and sets of extensions, probably. Keep in mind the php interpreter itself is kinda beefy:

rtucker  25281  0.2  1.9  38280  6904 pts/7    S+   16:12   0:00 php

That's from just typing "php" at the command line.

> By the way, you can grab the xcache admin interface here and install it to see if xcache actually works.

Sweeeet. I have done so, and indeed, it is. I've also done some tuning. Thanks! :-)

Thanks everyone for your help.

I installed Munin a few days ago. It looks like memory usage automagically drops every 20-30 hours without any intervention and without changes in PIDs.

I think I should read up on how memory management in Linux works in order to understand the numbers. But for now, things look fine.

Reply

Please enter an answer
Tips:

You can mention users to notify them: @username

You can use Markdown to format your question. For more examples see the Markdown Cheatsheet.

> I’m a blockquote.

I’m a blockquote.

[I'm a link] (https://www.google.com)

I'm a link

**I am bold** I am bold

*I am italicized* I am italicized

Community Code of Conduct