The top
output shows Apache processes consuming 90-100% CPU while memory usage remains relatively low (only 1.9% for MySQL and under 0.5% for most Apache processes). This indicates we're dealing with a CPU-bound workload rather than memory constraints.
First, let's optimize the MPM (Multi-Processing Module) settings. Since you're using prefork (visible in your config), we'll focus there:
StartServers 8
MinSpareServers 5
MaxSpareServers 20
ServerLimit 128 # Reduced from 256
MaxClients 128 # Reduced from 256
MaxRequestsPerChild 1000 # Reduced from 4000
The key changes:
- Reduced
ServerLimit
andMaxClients
to prevent overloading - Lowered
MaxRequestsPerChild
to allow more frequent process recycling
Since this is a LAMP stack, PHP is likely the real CPU hog. Add these to your php.ini
:
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=60
Enable mod_deflate to reduce CPU load from serving uncompressed content:
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript
DeflateCompressionLevel 6
Your current KeepAlive settings may be keeping connections open too long:
KeepAlive On
MaxKeepAliveRequests 50 # Reduced from 100
KeepAliveTimeout 3 # Reduced from 5
Implement these monitoring commands to verify the changes:
# View real-time Apache connections
watch -n 1 "echo -n 'Apache Processes: '; ps -C httpd --no-headers | wc -l"
# CPU usage by Apache
top -b -n 1 | grep httpd | awk '{print $9}' | sort -n | tail -n 20
# Memory usage
free -m && ps -eo pmem,pcpu,vsize,pid,cmd | grep httpd | sort -k 1 -nr | head -10
For CPU-bound workloads, consider switching to event
MPM if possible:
StartServers 2
ServerLimit 64
ThreadLimit 64
ThreadsPerChild 32
MaxRequestWorkers 2048
MaxConnectionsPerChild 1000
Remember to install the event module and disable prefork first:
yum remove mod_php
yum install mod_php72w php72w-opcache
From your server metrics, we can observe several critical patterns:
- Extremely high CPU utilization (90-100%)
- Apache processes dominating CPU usage
- Low memory consumption relative to available resources
- MySQL showing moderate CPU usage spikes
# Sample sar output showing CPU usage pattern
sar -u 1 5
Linux 3.10.0-1160.45.1.el7.x86_64 (web01) 06/15/2023 _x86_64_ (8 CPU)
12:00:01 AM CPU %user %nice %system %iowait %steal %idle
12:00:02 AM all 93.38 0.00 6.62 0.00 0.00 0.00
12:00:03 AM all 94.12 0.00 5.88 0.00 0.00 0.00
Based on your current prefork configuration, here are recommended changes:
<IfModule prefork.c>
StartServers 16
MinSpareServers 10
MaxSpareServers 30
ServerLimit 200
MaxClients 200
MaxRequestsPerChild 1000
</IfModule>
Key modifications and reasoning:
- Reduced MaxRequestsPerChild to 1000 to prevent memory leaks from accumulating
- Adjusted ServerLimit/MaxClients to better match your CPU core count
- Increased spare server counts to handle traffic spikes more efficiently
For CPU-bound scenarios, worker MPM often performs better:
<IfModule worker.c>
StartServers 4
MaxClients 400
MinSpareThreads 50
MaxSpareThreads 150
ThreadsPerChild 50
MaxRequestsPerChild 10000
</IfModule>
To enable worker MPM:
# Stop Apache
service httpd stop
# Switch to worker MPM
yum remove httpd-tools
yum install httpd httpd-tools --enablerepo=centosplus
# Verify MPM
httpd -V | grep -i mpm
Since this is a LAMP stack, PHP configuration significantly impacts CPU usage:
; Recommended php.ini modifications
opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=4000
opcache.revalidate_freq=60
opcache.fast_shutdown=1
realpath_cache_size=256k
realpath_cache_ttl=3600
; For CPU-bound systems
pm = dynamic
pm.max_children = 50
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
Even though MySQL isn't the primary bottleneck, optimizing it will help:
# my.cnf optimizations
[mysqld]
innodb_buffer_pool_size = 2G
innodb_log_file_size = 256M
innodb_flush_log_at_trx_commit = 2
innodb_flush_method = O_DIRECT
query_cache_type = 0
table_open_cache = 4000
thread_cache_size = 50
# Network stack tuning
echo 'net.ipv4.tcp_tw_reuse = 1' >> /etc/sysctl.conf
echo 'net.ipv4.tcp_fin_timeout = 15' >> /etc/sysctl.conf
echo 'net.core.somaxconn = 65535' >> /etc/sysctl.conf
sysctl -p
# File descriptor limits
echo 'www-data soft nofile 65535' >> /etc/security/limits.conf
echo 'www-data hard nofile 65535' >> /etc/security/limits.conf
Implement these monitoring commands to verify improvements:
# Apache status monitoring
apachectl fullstatus
# Real-time process monitoring
watch -n 1 "ps -eo pid,user,pcpu,pmem,cmd --sort=-pcpu | head -20"
# Detailed CPU profiling
perf top -p $(pgrep -d, httpd)