The next step is to make sure we are using Apache with the Event MPM. Don't worry too much about messing around with Apache settings, the ones I have below are the default setting. Don't add this to the main httpd.conf file, instead add this to pre_virtualhost_global.conf, or use the WHM includes editor.
vim /usr/local/apache/conf/includes/pre_virtualhost_global.conf
##Apache Event Default Settings (overrides main httpd.conf)
KeepAlive On
KeepAliveTimeout 2
MaxKeepAliveRequests 500
<IfModule event.c>
ThreadsPerChild 25
ServerLimit 16
MaxRequestWorkers 400
StartServers 6
MinSpareThreads 150
MaxSpareThreads 400
MaxRequestsPerChild 0
</IfModule>
<IfModule mod_fcgid.c>
FcgidMaxRequestLen 1073741824
FcgidOutputBufferSize 1073741824
FcgidMinProcessesPerClass 0
FcgidMaxRequestsPerProcess 0
FcgidInitialEnv PHP_FCGI_MAX_REQUESTS 0
FcgidInitialEnv PHP_FCGI_CHILDREN 0
FcgidMaxProcesses 20
FcgidMaxProcessesPerClass 10
FcgidFixPathinfo 1
FcgidIdleTimeout 3
FcgidBusyTimeout 300
FcgidProcessLifeTime 300
FcgidIOTimeout 300
FcgidIdleScanInterval 1
FcgidErrorScanInterval 1
FcgidZombieScanInterval 1
</IfModule>
Go ahead and stop, then start apache, don't just restart it. I find that sometimes if you change start server settings, or other directives a restart does not always apply the changes, not sure if this is a cpanel thing or what.
service httpd stop; service httpd start
2GB VPS / cPanel Server
vim /usr/local/lib/php.ini
zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20121212/opcache.so
opcache.memory_consumption=64
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=7963
opcache.revalidate_freq=0
opcache.fast_shutdown=1
opcache.enable_cli=1
opcache.enable=1
vim /usr/local/apache/conf/includes/pre_virtualhost_global.conf
##Apache Event Default Settings (overrides main httpd.conf)
KeepAlive On
KeepAliveTimeout 2
MaxKeepAliveRequests 500
<IfModule event.c>
ThreadsPerChild 25
ServerLimit 16
MaxRequestWorkers 400
StartServers 6
MinSpareThreads 150
MaxSpareThreads 400
MaxRequestsPerChild 0
</IfModule>
<IfModule mod_fcgid.c>
FcgidMaxRequestLen 1073741824
FcgidOutputBufferSize 1073741824
FcgidMinProcessesPerClass 0
FcgidMaxRequestsPerProcess 0
FcgidInitialEnv PHP_FCGI_MAX_REQUESTS 0
FcgidInitialEnv PHP_FCGI_CHILDREN 0
FcgidMaxProcesses 40
FcgidMaxProcessesPerClass 20
FcgidFixPathinfo 1
FcgidIdleTimeout 3
FcgidBusyTimeout 300
FcgidProcessLifeTime 300
FcgidIOTimeout 300
FcgidIdleScanInterval 1
FcgidErrorScanInterval 1
FcgidZombieScanInterval 1
</IfModule>
service httpd stop; service httpd start
4GB VPS / cPanel Server
vim /usr/local/lib/php.ini
zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20121212/opcache.so
opcache.memory_consumption=64
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=7963
opcache.revalidate_freq=0
opcache.fast_shutdown=1
opcache.enable_cli=1
opcache.enable=1
vim /usr/local/apache/conf/includes/pre_virtualhost_global.conf
##Apache Event Default Settings (overrides main httpd.conf)
KeepAlive On
KeepAliveTimeout 2
MaxKeepAliveRequests 500
<IfModule event.c>
ThreadsPerChild 25
ServerLimit 16
MaxRequestWorkers 400
StartServers 6
MinSpareThreads 150
MaxSpareThreads 400
MaxRequestsPerChild 0
</IfModule>
<IfModule mod_fcgid.c>
FcgidMaxRequestLen 1073741824
FcgidOutputBufferSize 1073741824
FcgidMinProcessesPerClass 0
FcgidMaxRequestsPerProcess 0
FcgidInitialEnv PHP_FCGI_MAX_REQUESTS 0
FcgidInitialEnv PHP_FCGI_CHILDREN 0
FcgidMaxProcesses 80
FcgidMaxProcessesPerClass 40
FcgidFixPathinfo 1
FcgidIdleTimeout 3
FcgidBusyTimeout 300
FcgidProcessLifeTime 300
FcgidIOTimeout 300
FcgidIdleScanInterval 1
FcgidErrorScanInterval 1
FcgidZombieScanInterval 1
</IfModule>
service httpd stop; service httpd start
8GB VPS / cPanel Server
vim /usr/local/lib/php.ini
zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20121212/opcache.so
opcache.memory_consumption=64
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=7963
opcache.revalidate_freq=0
opcache.fast_shutdown=1
opcache.enable_cli=1
opcache.enable=1
vim /usr/local/apache/conf/includes/pre_virtualhost_global.conf
##Apache Event Default Settings (overrides main httpd.conf)
KeepAlive On
KeepAliveTimeout 2
MaxKeepAliveRequests 500
<IfModule event.c>
ThreadsPerChild 25
ServerLimit 16
MaxRequestWorkers 400
StartServers 6
MinSpareThreads 150
MaxSpareThreads 400
MaxRequestsPerChild 0
</IfModule>
<IfModule mod_fcgid.c>
FcgidMaxRequestLen 1073741824
FcgidOutputBufferSize 1073741824
FcgidMinProcessesPerClass 0
FcgidMaxRequestsPerProcess 0
FcgidInitialEnv PHP_FCGI_MAX_REQUESTS 0
FcgidInitialEnv PHP_FCGI_CHILDREN 0
FcgidMaxProcesses 160
FcgidMaxProcessesPerClass 80
FcgidFixPathinfo 1
FcgidIdleTimeout 3
FcgidBusyTimeout 300
FcgidProcessLifeTime 300
FcgidIOTimeout 300
FcgidIdleScanInterval 1
FcgidErrorScanInterval 1
FcgidZombieScanInterval 1
</IfModule>
service httpd stop; service httpd start
mod_fcgid configuration settings
FcgidMaxRequestLen
If the size of the request body exceeds this amount, the request will fail with 500 Server Error. By default this is set to 131072 Bytes. For cPanel the default is 1073741824, which is about 1GB.
<IfModule mod_fcgid.c>
FcgidMaxRequestLen 1073741824
</IfModule>
FcgidMaxProcessesPerClass
This directive sets the maximum number of processes that can be started for each process class, turns out that class means PER USER. If you have multiple users, or have a cPanel server please DO NOT USE THIS. Use FcgidMaxProcesses which sets the global limit. If you set the per class value, it gets multiplied by the amount of users. By default this value is set to 100. If you do not have lots of RAM, lower this to around 20 or so, assuming your app uses about 30MB per process.
<IfModule mod_fcgid.c>
FcgidMaxProcessesPerClass 100 (default)
</IfModule>
FcgidMaxProcesses
This sets the global / server limit for how many PHP processes can run. Unlike the FcgidMaxProcessesPerClass directive, which is a per user limit, this directive is for all users. This is basically MaxClients but for PHP. If you have more users than processes, you may run into an issue where some websites appear to hang up for well over a minute. Read on to find out how to get around this issue by lowering various timeout and scan interval settings.
<IfModule mod_fcgid.c>
FcgidMaxProcesses 20
</IfModule>
FcgidMaxRequestsPerProcess
FastCGI application processes will be terminated after handling the specified number of requests. By default this is set to 0 which means there is no limit / check.
<IfModule mod_fcgid.c>
FcgidMaxRequestsPerProcess 0
</IfModule>
FcgidConnectTimeout
This is the maximum period of time the module will wait while trying to connect to a FastCGI application on Windows. (This directive is not respected on Unix, where AF_UNIX defaults will apply.)
FcgidIOTimeout
This is the maximum period of time the module will wait while trying to read from or write to a FastCGI application. If you have a slow application you may want to raise this, however 40 seconds is plenty of time. IF you site / app takes 40 seconds to load then odds are no one will ever want to visit your site again.
FcgidIdleTimeout
Application processes which have not handled a request for this period of time will be terminated, if the number of processses for the class exceeds FcgidMinProcessesPerClass. A value of 0 disables the check. The default value is 300 seconds, which means that a FCGI process could serve 1 request, and then remain idle for up to 1 minute or more. This can be a huge waste of resources if you have lots of sites on your server.
<IfModule mod_fcgid.c>
FcgidIdleTimeout 300 (default)
</IfModule>
If you notice that some websites are hanging up when you try to load them, it could be because all the FCGI processes are active and assigned to a user. If you have more users than FCGI processes then lowing FcgidIdleTimeout to a smaller value like 30, or even 3 will significantly reduce the chances of this happening.
<IfModule mod_fcgid.c>
FcgidIdleTimeout 3
</IfModule>
FcgidMinProcessesPerClass
This directive sets the minimum number of processes that will be retained in a process class after finishing requests. By default the value is 3.
<IfModule mod_fcgid.c>
FcgidMinProcessesPerClass 3
</IfModule>
FcgidProcessLifeTime
Idle application processes which have existed for greater than this time will be terminated, if the number of processses for the class exceeds FcgidMinProcessesPerClass. A value of 0 disables the check. By Default this is set to 3600, if you want to save RAM you can set this to something like 30 to kill off unused processes
<IfModule mod_fcgid.c>
FcgidProcessLifeTime 60
</IfModule>
FcgidIdleScanInterval
This is the interval at which the module will search for processes which have exceeded FcgidIdleTimeout or FcgidProcessLifeTime. The default is 120 seconds, you can lower this if you want shorter living processes. If you notice that on occasion, some websites seem to hang for over a minute or more when you try to load the page, you will want to lower this setting. If all FCGI processes are in use, and you have more users than the process limit, lowering this to 5 or even 0 will cause processes to clear out much faster instead of hanging around. Setting this to 0 is a valid way to go. You will need to lower some other scan intervals besides this one to make sure that processes are not hanging around wasting space.
<IfModule mod_fcgid.c>
FcgidIdleScanInterval 120 (default)
</IfModule>
FcgidTerminationScore
Lowing the FcgidTerminationScore value increases the allowed spawn rate, the value can be negative which can be useful for allowing process replacement without increasing the score. I did notice that lowering FcgidTerminationScore to 1 did seem to slightly boost performance while running Apache Benchmark, a basic Wordpress blog was requested 100 times and with a score of 2 the server pumped out 23 request/s. With a score of 1 the server was able to reach 29 request/s. Values that were lower than 0 seemed to reduce performance slightly, but every server / website will perform differently so you might want to test the differences for yourself.
<IfModule mod_fcgid.c>
FcgidTerminationScore 2 (default)
</IfModule>
FcgidTimeScore
The value set for FcgidTimeScore determines the amount subtracted from the activity score of a FCGI process each second. Higher values increase the spawn rate, usually this means faster response times, and potentially higher amounts of CPU usage under large amounts of traffic. I've found that raising FcgidTimeScore to 3 seems to help with clearing old processes out and quickly creating new processes to handle new user requests.
<IfModule mod_fcgid.c>
FcgidTimeScore 1 (default)
</IfModule>
Zend opcache
Zend OPcache Links
opcache.max_accelerated_files
opcache.max_accelerated_files - Controls how many PHP files can be held in memory at the same time. Should be set to a Prime number for better performance. { 223, 463, 983, 1979, 3907, 7963, 16229, 32531, 65407, 130987 }
To find out how many files you have, you can use a command like this.
find . -type f -print | grep php | wc -l
I set this to 7963 for my 1GB server and this value seems to work well.
opcache.max_accelerated_files = 7963
opcache.memory_consumption
opcache.memory_consumption - The default is 64MB, if you have a ton of sites or large amounts of PHP code in general you might want to raise this. For a 1GB server I set this to 64MB.
opcache.memory_consumption = 64
opcache.interned_strings_buffer
opcache.interned_strings_buffer - PHP uses string interning to improve performance. If you have the string "mahstring" 100 times in your code, PHP will store 1 variable for the string and will use a pointer to it for the other 99 times it gets used. This value is in MB. Raising this value too high causes each PHP process to use more RAM, or at least appear to. When this was set to 16MB each PHP process was around 48MB. When set to 4MB each PHP process used around 32MB RAM each. This is shared RAM so the usage may not matter much, but just keep that in mind when you tune this and use high values.
opcache.interned_strings_buffer = 4
opcache.revalidate_freq
opcache.revalidate_freq How often in seconds should the code cache expire and check if your code has changed. 0 means it checks your PHP code every single request which can hurt performance. If you don't update PHP code all that often then setting this to 120 seconds could help with performance and still get refreshed every 2 minutes.
opcache.revalidate_freq=120
Using a Custom / Local php.ini with FCGI
cd /home/$user/public-html/cgi-bin
cp /usr/local/lib/php.ini /home/$user/public_html/cgi-bin/
vim /home/$user/public_html/cgi-bin/php.fcgi
##Create the file with this##
#!/bin/sh
export PHP_FCGI_CHILDREN=0
export PHP_FCGI_MAX_REQUESTS=0
exec /usr/local/cpanel/cgi-sys/php5
Save the file, then make sure it is executable
chmod +x /home/$user/public_html/cgi-bin/php.fcgi
chown -R $user:$user /home/$user/public_html/cgi-bin/
Add this to the user's .htaccess file
vim /home/$user/public_html/.htaccess
##Add to top##
AddHandler php5-fastcgi .php
Action php5-fastcgi /cgi-bin/php.fcgi
Now it's time to modify the php.conf file, but before you do, please back up the original one.
cp -a /usr/local/apache/conf/php.conf /usr/local/apache/conf/php.conf.`date +%F.%H.%M`
vim /usr/local/apache/conf/php.conf
##Make sure these two lines are in the conf##
Action php5-fastcgi /cgi-bin/php.fcgi
AddType application/x-httpd-php .php
Save the file and distill the apache conf and restart apache
/usr/local/cpanel/bin/apache_conf_distiller --update
/scripts/rebuildhttpdconf
/etc/init.d/httpd restart
Create a php info file to test out the changes
vim /home/$user/public_html/phpinfo.php
##Add this##
<?php
phpinfo();
?>
Make sure the php info file has the correct ownerships
chown $user:$user /home/$user/public_html/phpinfo.php
Near the top of the page you should see that the custom path / php.ini file is in use
Loaded Configuration File /home/user/public_html/cgi-bin/php.ini
Additional Information
Video: Scaling PHP in the Real World - Dustin Whittle
Links