Installing and Configuring Apache with Event MPM and PHP 8.2-FPM on RHEL 9: Complete Performance Playbook
System Preparation and Package Installation
This guide assumes a clean RHEL 9 installation. We will leverage the AppStream repository for Apache and PHP, ensuring we get well-supported versions. Prior to installation, it’s prudent to update the system to the latest packages.
Execute the following commands to update your system and install the necessary components:
sudo dnf update -y sudo dnf install -y httpd php php-fpm php-cli php-common php-mysqlnd php-gd php-xml php-mbstring php-opcache
The `php-fpm` package is crucial for integrating PHP with Apache using the FastCGI Process Manager. `php-opcache` is essential for performance by caching compiled PHP bytecode.
Apache Configuration: Enabling Event MPM
RHEL 9’s default Apache installation typically uses the `worker` MPM. For high-concurrency scenarios, the `event` MPM offers superior performance by leveraging non-blocking I/O for keep-alive connections, allowing worker threads to handle new requests more efficiently. We need to disable the `worker` MPM and enable the `event` MPM.
First, locate the MPM configuration files. These are usually found in /etc/httpd/conf.modules.d/.
sudo dnf module list httpd sudo dnf module enable httpd:2.4 sudo dnf install -y httpd
Now, we’ll disable the `worker` MPM and enable the `event` MPM. This involves manipulating symbolic links within the Apache configuration directory.
sudo systemctl stop httpd sudo dnf module disable httpd sudo dnf module enable httpd:2.4 sudo dnf install -y httpd sudo systemctl enable httpd sudo systemctl start httpd
Verify the MPM is loaded:
sudo apachectl -V | grep -i "server mpm"
The output should indicate MPM event.
Tuning Apache Event MPM Parameters
The performance of the `event` MPM is heavily influenced by its configuration directives. These are typically found in /etc/httpd/conf.modules.d/00-mpm.conf or a similar file. We will adjust key parameters for optimal concurrency.
Edit the MPM configuration file. The exact path might vary slightly, but look for the section related to the `event` MPM.
# /etc/httpd/conf.modules.d/00-mpm.conf (Example snippet)
<IfModule event.c>
# Start with a reasonable number of threads per process.
# This value should be tuned based on your server's CPU cores and memory.
# A good starting point is 25-50 threads per core.
ThreadsPerChild 100
# MaxRequestWorkers defines the maximum number of requests that can be served
# simultaneously. This is calculated as:
# MaxRequestWorkers = ServerLimit * ThreadsPerChild
# We'll set ServerLimit to a reasonable value and let MaxRequestWorkers be derived.
# For a 16-core server, starting with ServerLimit 16 is sensible.
ServerLimit 16
# MaxConnectionsPerChild: The maximum number of connections that a child
# process will handle before it dies and is replaced.
# Setting this too low can cause excessive process churn.
# Setting it too high can lead to memory leaks in long-running processes.
# A value between 10,000 and 50,000 is common.
MaxConnectionsPerChild 20000
</IfModule>
After modifying the configuration, restart Apache:
sudo systemctl restart httpd
Tuning Strategy:
ThreadsPerChild: This is the number of threads each Apache process will spawn. Start with a value that is a multiple of your CPU cores (e.g., 25-50 threads per core). Monitor CPU and memory usage. If threads are constantly busy and CPU is high, increase this. If memory is exhausted, decrease it.ServerLimit: This directive sets the maximum value forThreadsPerChild. It also limits the number of child processes. The total number of concurrent requests isServerLimit * ThreadsPerChild. Ensure this product does not exceed your available RAM.MaxConnectionsPerChild: This prevents memory leaks in long-running processes. A value of 10,000 to 50,000 is a good range. If you experience memory issues, consider lowering this.
PHP-FPM Configuration and Tuning
PHP-FPM runs as a separate service and communicates with Apache via a FastCGI socket. Its configuration is critical for PHP application performance. The main configuration file is typically located at /etc/php-fpm.d/www.conf.
First, ensure the PHP-FPM service is enabled and started:
sudo systemctl enable php-fpm sudo systemctl start php-fpm
Now, let’s tune the PHP-FPM pool configuration. We’ll focus on the `[www]` pool, which is the default.
; /etc/php-fpm.d/www.conf ; Choose the process management strategy. ; 'dynamic' is recommended for most environments. ; 'static' can offer slightly better performance but requires more upfront tuning. ; 'ondemand' is for very low traffic sites. pm = dynamic ; If pm is 'dynamic', these configure the dynamic process management. ; pm.max_children: The maximum number of children that can be started. ; This should be tuned based on available RAM and expected load. ; A common starting point is (total RAM - OS/Apache overhead) / average PHP process size. ; For a 16GB server, with Apache using ~1GB, and PHP processes ~30MB, you might start with 200-300. pm.max_children = 250 ; pm.start_servers: The number of script processes to create when PHP-FPM starts. pm.start_servers = 5 ; pm.min_spare_servers: The minimum number of idle script processes. pm.min_spare_servers = 2 ; pm.max_spare_servers: The maximum number of idle script processes. pm.max_spare_servers = 10 ; pm.process_idle_timeout: The number of seconds after which an idle process will be killed. ; Set to '10s' or '15s' to prevent too many idle processes. pm.process_idle_timeout = 10s ; pm.max_requests: The number of requests each child process should execute before respawning. ; This is similar to Apache's MaxConnectionsPerChild and helps prevent memory leaks. ; A value between 500 and 1000 is typical. pm.max_requests = 500 ; The address on which to accept FastCGI requests. ; For Apache with event MPM, using a Unix socket is generally faster than TCP/IP. ; Ensure the user Apache runs as (e.g., apache) has permissions to access this socket. listen = /run/php-fpm/www.sock ; Set the user and group for the FPM pool. user = apache group = apache ; Set the permissions for the socket. listen.owner = apache listen.group = apache listen.mode = 0660 ; Set the maximum amount of memory a script may consume. ; Adjust based on your application's needs. memory_limit = 256M ; Set the maximum execution time for scripts. max_execution_time = 60 ; Enable OPcache for bytecode caching. ; Ensure php-opcache is installed. opcache.enable=1 opcache.memory_consumption=128 opcache.interned_strings_buffer=16 opcache.max_accelerated_files=10000 opcache.revalidate_freq=2 opcache.validate_timestamps=1 opcache.enable_cli=1
After making these changes, restart PHP-FPM:
sudo systemctl restart php-fpm
Tuning Strategy for PHP-FPM:
pm:dynamicis usually the best balance.staticcan be faster if you can accurately predict load and have ample RAM, but it consumes resources even when idle.pm.max_children: This is the most critical parameter. Over-allocating will lead to Out-Of-Memory errors. Under-allocating will lead to request queuing and slow response times. Calculate this based on your server’s RAM and the average memory footprint of a PHP process.pm.max_requests: Essential for preventing memory leaks. A lower value means more frequent process respawning, which has a small overhead but ensures stability.listen: Using a Unix socket (/run/php-fpm/www.sock) is generally preferred over a TCP port for performance and security when Apache and PHP-FPM are on the same server. Ensure correct permissions.- OPcache Settings: These are vital for PHP performance. Adjust
opcache.memory_consumptionbased on your application’s complexity and the number of files.opcache.max_accelerated_filesshould be set high enough to cache all your application’s PHP files.opcache.revalidate_freqcontrols how often OPcache checks for file changes; set to 0 in production if you deploy manually and want maximum performance, or a small value (like 2) if you have frequent deployments and want automatic revalidation.
Apache Virtual Host Configuration for PHP-FPM
To enable PHP processing via PHP-FPM, we need to configure Apache’s virtual host to use the FastCGI interface. This involves setting up a ProxyPassMatch directive pointing to the PHP-FPM socket.
Edit your virtual host configuration file. For a default setup, this might be /etc/httpd/conf.d/your_site.conf or /etc/httpd/conf/httpd.conf.
# Example Virtual Host Configuration
<VirtualHost *:80>
ServerName your_domain.com
DocumentRoot /var/www/your_site
# Enable .htaccess overrides if needed
AllowOverride All
# Configure Apache to use PHP-FPM via FastCGI
<FilesMatch "\.php$">
SetHandler "proxy:unix:/run/php-fpm/www.sock|fcgi://localhost/"
</FilesMatch>
# Optional: For Apache 2.4.10+ you can use ProxyFCGISetEnvIf
# ProxyFCGISetEnvIf "REQUEST_URI" "^/.*" PHP_VALUE "display_errors=1"
# DirectoryIndex for PHP files
DirectoryIndex index.php index.html
ErrorLog /var/log/httpd/your_site_error.log
CustomLog /var/log/httpd/your_site_access.log combined
# Optional: Apache performance tuning directives
# KeepAlive On
# KeepAliveTimeout 5
# MaxKeepAliveRequests 100
</VirtualHost>
Ensure the DocumentRoot exists and has appropriate permissions for the Apache user (e.g., apache).
sudo mkdir -p /var/www/your_site sudo chown -R apache:apache /var/www/your_site sudo chmod -R 755 /var/www/your_site
After configuring the virtual host, test Apache’s configuration and restart the service:
sudo apachectl configtest sudo systemctl restart httpd
Security Considerations and SELinux
SELinux can prevent Apache from communicating with the PHP-FPM socket if not configured correctly. We need to allow Apache to connect to the PHP-FPM socket.
# Allow Apache to connect to the PHP-FPM socket sudo setsebool -P httpd_can_network_connect 1 sudo semanage fcontext -a -t httpd_var_run_t "/run/php-fpm/www.sock" sudo restorecon -Rv /run/php-fpm/www.sock
It’s also good practice to restrict access to sensitive configuration files and ensure Apache runs with minimal privileges. The default `apache` user and group are generally appropriate.
Performance Monitoring and Further Tuning
Continuous monitoring is key to maintaining optimal performance. Use tools like:
toporhtop: To monitor overall CPU and memory usage by Apache and PHP-FPM processes.apachectl status: Provides basic Apache server status information.php-fpm -m: Lists loaded PHP modules.php -i: Detailed PHP information, including OPcache status.- Application Performance Monitoring (APM) tools: Such as New Relic, Datadog, or Prometheus/Grafana for in-depth application-level performance insights.
Tuning Iterations:
- High CPU Usage: If
topshows consistently high CPU usage by Apache or PHP-FPM, you might need to reduceThreadsPerChildorpm.max_children, or investigate inefficient application code. - High Memory Usage: If the server is running out of memory, decrease
ThreadsPerChild,pm.max_children, oropcache.memory_consumption. EnsureMaxConnectionsPerChildandpm.max_requestsare set appropriately to mitigate memory leaks. - Slow Response Times: This could indicate insufficient worker processes (increase
ThreadsPerChild/pm.max_children), slow application logic, or I/O bottlenecks.
Remember to restart Apache and PHP-FPM after making any configuration changes and always test thoroughly in a staging environment before deploying to production.
Leave a Reply
You must be logged in to post a comment.