When you install PHP-FPM and Apache 2 on Ubuntu, the default settings are hardly optimized for a beefy production server with lots of RAM and CPU cores. I'd like to sketch out a good plan for determining what the configuration settings should be for apache settings like StartServers and MaxRequestWorkers and for PHP-FPM config settings like pm.start_servers and pm.max_spare_servers.
I'm starting from some basic assumptions
1) we would ideally set the max values to utilize all available RAM but no more -- it's preferable to drop connections than to have your server start thrashing (or crash) because you run out of memory
2) I will assume that we need roughly 1 PHP process for each Apache process. Some requests (e.g. images, stylesheets) don't require PHP to run at all, but other requests may make numerous AJAX requests for data.
3) The system will need about 1GB of RAM for basic system operation and everything else that's not Apache or PHP (NOTE I'm running MySQL on a separate machine).
Broadly, this formula seems applicable to determine N, my basic configuration setting for how many apache+php processes I can run at once. I.e., if N is 100, I can run 100 apache processes which make use of 100 PHP processes.
(php_procs x mem_usage_per_php_proc) + (apache_procs x mem_usage_per_apache_proc) = (total_ram - 1GB)
php_procs = apache_procs = N
Total RAM (as reported by the free
command) on my machine is 7930MB so we get:
(N x mem_usage_per_php_proc) + (N x mem_usage_per_apache_proc) = 6930MB
This is pretty straightforward, but I'm having some trouble determining how much RAM Apache and PHP consume per process.
QUESTION: Can anyone help me get a clear idea of how much RAM will be used by each PHP and Apache process?
I realize that this is likely to depend on what the PHP is doing (is it generating a giant array? which modules does PHP load on this machine?) but I'm getting some pretty wildly different results. After much searching, I found a handy command that works on ubuntu which returns a list of processs and an rss value for each which, according to the docs is:
resident set size, the non-swapped physical memory that a task has used (in kilobytes).
The commands which must be tweaked depending on the version of PHP installed, is:
ps -C php-fpm8.2 -o "uname,ppid,pid,%cpu,pmem,rss,command,comm"
For apache it is:
ps -C apache2 -o "uname,ppid,pid,%cpu,pmem,rss,command,comm"
I note that the per-process RAM usage of PHP is considerably higher on my old production server (Ubuntu 16, PHP 7.0 - 75.0M per proc) versus the new server that will replace it (Ubuntu 22, PHP 8.2 - 24.2M per proc). I also checked my own workstation running ubuntu 20/php8.2 and it averages 49M per proc. I also checked another production server I manage and see an average of 29M per proc.
These values are completely different, and much larger, than the values returned by PHP function memory_get_peak_usage
.
They also seem quite different than what I see returned by the ubuntu command pmap
.
I've seen apache memory consumption range anywhere from 6MB per apache proc to 20MB.
Any thoughts anyone has, or broad suggestions about how you deal with this, would be much appreciated. I'm inclined to go with the output of the ps
command and assume that an active server handling page requests will consume more RAM per process than a quiescent server waiting to be deployed.
EDIT: Let me add that the result I get for N can vary a LOT. Assuming 24.2MB for PHP process and 6.1MB for apache process, I get N=228.7. Assuming 75.0MB for PHP process and 17.7MB for apache proc, I get N=74.8.