When working with Magento on a Nginx + PHP-FPM stack, performance degradation over time is a common yet frustrating issue. After server reboot, everything runs smoothly, but within 24 hours, response times balloon to 2+ minutes per page. SSH sessions become sluggish, and CPU spikes occur despite low apparent utilization.
Your free -m
output shows:
total used free shared buffers cached
Mem: 5963 5217 745 0 192 314
-/+ buffers/cache: 4711 1252
Swap: 4047 4 4042
This indicates significant memory usage (4.7GB actual used), but crucially shows minimal swap usage. The Linux memory management system is working as expected - cached memory isn't the issue here.
Looking at your top
output, multiple php-fpm processes are consuming 50-120MB RSS each. For Magento, this isn't unusual, but the accumulation suggests either:
- Improper PHP-FPM pool configuration
- Memory leaks in PHP extensions
- Unbounded session storage
Try these adjustments in your /etc/php-fpm.d/www.conf
:
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.max_requests = 500
For Magento specifically, add these PHP settings:
php_admin_value[memory_limit] = 512M
php_admin_value[realpath_cache_size] = 256K
php_admin_value[opcache.memory_consumption] = 256
Install and run this monitoring script to track PHP-FPM memory usage over time:
#!/bin/bash
while true; do
date >> /var/log/phpfpm_mem.log
ps -ylC php-fpm --sort:rss >> /var/log/phpfpm_mem.log
sleep 300
done
Complement your PHP-FPM tuning with these Nginx settings in your Magento server block:
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
For temporary relief while investigating, set up a cron job to gracefully restart PHP-FPM during low-traffic periods:
0 3 * * * /bin/kill -USR2 $(cat /var/run/php-fpm/php-fpm.pid)
When working with Nginx + PHP-FPM configurations (especially for Magento), memory issues can creep up in unexpected ways. Based on your diagnostics, we're dealing with a classic "gradual performance degradation" scenario rather than immediate failure.
Your memory output shows:
-/+ buffers/cache: 4711 1252
This reveals the true available memory after accounting for disk caching. The 1.2GB free suggests your system isn't actually out of memory. The key indicators are:
- Low swap usage (good)
- Moderate cache usage (normal)
- No obvious memory hog in top
Your top output shows multiple PHP-FPM processes consuming 50-120MB each. For a Magento setup, this isn't unreasonable, but the cumulative effect matters. Consider these tuning parameters in your www.conf
:
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 10
pm.max_requests = 500
The max_requests
parameter is particularly important - it gracefully restarts processes after serving X requests, preventing memory leaks.
Add these to your Magento's local.xml
:
<cache>
<backend>memcached</backend>
<slow_backend>database</slow_backend>
</cache>
And configure PHP-FPM with these additional parameters:
php_admin_value[memory_limit] = 256M
php_admin_value[realpath_cache_size] = 256K
php_admin_value[opcache.enable] = 1
Add these to your nginx config for PHP handling:
fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
Instead of just watching free -m
, use these more revealing commands:
# Watch PHP-FPM memory usage per process
watch -n 5 'ps -ylC php-fpm --sort:rss | awk \'{sum+=$8; ++n} END {print "Tot="sum"("n") Avg="sum/n/1024"MB"}\''
# Real-time PHP-FPM status
watch -n 5 'curl -s http://localhost/php-fpm-status | grep -E "accepted conn|pool|idle processes"'
Magento's caching can actually cause memory issues when improperly configured. Verify your cache storage method:
# Check current cache configuration
n98-magerun.phar sys:info | grep -i cache
For emergency situations, create this watchdog script (/usr/local/bin/phpfpm_watchdog.sh
):
#!/bin/bash
THRESHOLD=80
LOAD=$(cat /proc/loadavg | cut -d' ' -f1 | awk '{print int($1)}')
if [ "$LOAD" -gt "$THRESHOLD" ]; then
systemctl restart php-fpm
echo "$(date) - Restarted PHP-FPM due to load $LOAD" >> /var/log/phpfpm_watchdog.log
fi
Add to cron:
* * * * * /usr/local/bin/phpfpm_watchdog.sh