Over the last several years, I’ve worked a lot with cPanel (phenomenal product if you are in the market for a web hosting control panel – easy for sysadmins and developers). I’ve run a variety of web workloads on the platform and it never ceases to amaze me (and you cannot beat the EDU/non-profit licensing).
At one point, I was tasked with tuning apache on a cPanel server with a slightly different work load (1 very heavily trafficked application) and was provided with a high performance virtual machine (example setup: 4 CPUs, 12 GB memory) to accommodate. The application was to use SSL (HTTPS), so I opted for mpm_worker (mpm_event is nice, but performs similarly to worker when SSL is in use).
Much literature exists regarding tuning mpm_worker for small (low memory) virtual private servers (VPS), but I was not readily able to find information regarding tuning apache for a larger (high end, high memory) server. Hence, this post was created. For the remainder of this post, I will assume that you have already compiled httpd to use the worker mpm (with EasyApache) on your cPanel server. Also note, this process only applies to well-balanced VPS (CPU count scaled to match amount of memory – say 1 CPU core for every 2-3 GB of RAM).
cPanel/WHM does not allow adjustment of ThreadsPerChild via the web interface – it defaults to 25 (although you can change this in httpd.conf and distill the configuration, I advise against that)
Given the above, MaxClients must be divisible by 25 (ThreadsPerChild)
Most tuning is achieved by manipulating MaxClients (MaxRequestWorkers) and ServerLimit
Prework (initial calculations)
To tune httpd with mpm_worker under cPanel, a little background information is required. This process will vary slightly from server to server, but you must calculate the average amount of memory (RAM) that each apache process uses. When performing this calculation, the server should be under “normal” load. If it is idle, the calculation will be inaccurate.
I use top -u and specify the username that httpd runs as (on cPanel, this is “nobody” but many distributions use “apache” as well). We are most interested in the RES column – more specifically, the average RES for all apache processes.
As an example:
top -u nobody
Then, calculate the average memory (RES) consumed per process:
113 + 115 + 45 + 48 + 114 + 44 + 31 + 14 = 524 / 8 = 65.5
This means each apache/httpd process consumes ~66 MB of memory on average. cPanel uses the default value of 25 for ThreadsPerChild, so we can conclude that for every 25 clients, ~66 MB of memory is required.
Calculating your server’s value for MaxClients (aka MaxRequestWorkers)
Next, you must decide how much memory you can allocate for httpd and impose that limit with Max Clients. To get a baseline, I recommend stopping apache and assessing the amount of available memory on the system.
On the example server, let’s say that 9259430k (~9.5 GB) of memory is available when httpd is not running. Say you are comfortable allocating 75% of that (~7 GB) to apache. Use your judgement here – depending on your system, you may need to adjust your allocation. Several factors can affect memory usage as load increases so it is not safe to assume that what is available when apache is stopped will scale linearly. Under no circumstances should you allow apache to swap. If that occurs, your estimate/allocation is too high.
7 GB * 1024 = 7168 MB / 66 MB (from above) = 108.6 processes (round down) = 100 processes
This means ~100 apache processes can run in the 7 GB we allocated. Now, multiply by ThreadsPerChild (25) to obtain Max Clients:
100 * 25 = 2500
For this server, a Max Clients setting of 2500 is reasonable (and since Server Limit simply caps the upper limit, set it to 2500 or greater). Since we rounded down to the nearest 100, MaxClients will be divisible by 25 (it needs to be). If your calculation is different, round down appropriately so that your Max Clients setting is divisible by 25.
Updating cPanel’s httpd configuration
Implementing these settings in WHM is easy:
WHM -> Service Configuration -> Apache Configuration -> Global Configuration
Then, update the 2 settings based on your calculation:
Finally, restart apache, and you should be good to go.
It could not hurt to perform a load test against your server as a sanity check (jmeter is free and well documented). This will ensure your estimate/calculation from above is within spec. Again, you want to keep httpd out of swap at all costs. A load test will also help identify other potential bottlenecks on your server (CPU, disk performance, network bandwidth, etc.). At this point, you may also consider putting your extra threads to work (or wait) by enabling KeepAlive and increasing your Keep Alive Timeout (if you have not already).