20130425 checking httpd resource limits - plembo/onemoretech GitHub Wiki

title: Checking httpd resource limits link: https://onemoretech.wordpress.com/2013/04/25/checking-httpd-resource-limits/ author: phil2nc description: post_id: 4729 created: 2013/04/25 21:05:32 created_gmt: 2013/04/26 01:05:32 comment_status: closed post_name: checking-httpd-resource-limits status: publish post_type: post

Checking httpd resource limits

Recently found a nice script that checks a web server's system and Apache configurations to determine if there it has sufficient RAM. Check Apache HTTPD MPM Config Limits introduces the check_httpd_limits.pl script, which may be the coolest thing I've seen in a long time. Sure all these relationships and calculating what they mean is something many of us know, but being able to run a script like this and get back a quick analysis is worth it's weight in gold because of the time it saves. Here's an example of verbose script output from the project wiki:

$ sudo ./check_httpd_limits.pl --verbose

Check Apache Httpd MPM Config Limits (Version 2.2.1)
by Jean-Sebastien Morisset - http://surniaulula.com/

Httpd Binary

 - CONFIG                : /etc/httpd/conf/httpd.conf
 - EXE                   : /usr/sbin/httpd
 - MPM                   : prefork
 - ROOT                  : /etc/httpd
 - VERSION               : 2.2

Httpd Processes

 - PID 4245 (httpd)      : 31.60 MB / 8.02 MB shared [excluded from averages]
 - PID 7442 (httpd)      : 25.01 MB / 1.37 MB shared
 - PID 7443 (httpd)      : 24.43 MB / 0.82 MB shared
 - PID 7444 (httpd)      : 24.43 MB / 0.82 MB shared
 - PID 7445 (httpd)      : 24.43 MB / 0.82 MB shared
 - PID 7446 (httpd)      : 24.43 MB / 0.82 MB shared

 - HttpdRealAvg          :  23.61 MB [excludes shared]
 - HttpdSharedAvg        :   0.86 MB
 - HttpdRealTot          : 141.66 MB [excludes shared]

Httpd Config

 - MaxClients            : 40
 - MaxRequestsPerChild   : 3000
 - MaxSpareServers       : 10
 - MinSpareServers       : 5
 - ServerLimit           : 40
 - StartServers          : 5

Server Memory

 - Cached                : 1768.24 MB
 - MemFree               :  659.98 MB
 - MemTotal              : 3938.62 MB
 - SwapFree              : 5983.86 MB
 - SwapTotal             : 5983.99 MB

Calculations Summary

 - NonHttpdProcs         : 1367.88 MB (MemTotal - Cached - MemFree - HttpdRealTot - HttpdSharedAvg)
 - FreeWithoutHttpd      : 2570.74 MB (MemFree + Cached + HttpdRealTot + HttpdSharedAvg)
 - MaxHttpdProcs         :  945.26 MB (HttpdRealAvg * MaxClients + HttpdSharedAvg)
 - AllProcsTotal         : 2313.14 MB (NonHttpdProcs + MaxHttpdProcs)

Config for 100% of MemTotal

   
        MaxClients               109    # (40 -> 109) (MemFree + Cached + HttpdRealTot + HttpdSharedAvg) / HttpdRealAvg
        MaxRequestsPerChild     3000    # (no change) Default is 10000
        MaxSpareServers           10    # (no change) Default is 10
        MinSpareServers            5    # (no change) Default is 5
        ServerLimit              109    # (40 -> 109) MaxClients
        StartServers               5    # (no change) Default is 5
   

Result

OK: AllProcsTotal (2313.14 MB) fits within available RAM (MemTotal 3938.62 MB).

Pretty impressive, if you ask me. So much so that I'm about to post the longest code sample I've every had here that wasn't written by myself or one of my associates.

#!/usr/bin/perl
 
# 

Copyright 2012 - Jean-Sebastien Morisset - http://surniaulula.com/ # # This script is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 3 of the License, or (at your option) any later # version. # # This script is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details at http://www.gnu.org/licenses/.

# Perl script to compare the size of running Apache httpd processes, the
# configured prefork/worker limits, and the available server memory. Exits with
# a warning or error message if the configured limits exceed the server's
# memory.
#
# Syntax: check_httpd_limits.pl --help
 
# The script performs the following tasks:
#
# - Reads the /proc/meminfo file for server memory values.
# - Reads the /proc/*/exe symbolic links to find the matching httpd binaries.
# - Reads the /proc/*/stat files for pid, process name, ppid, and rss.
# - Reads the /proc/*/statm files for the shared memory size.
# - Executes HTTP binary with "-V" to get the config file path and MPM info.
# - Reads the HTTP config file to get MPM (prefork or worker) settings.
# - Calculates the average and total HTTP process sizes, taking into account
#   the shared memory used.
# - Calculates possible changes to MPM settings based on available memory and
#   process sizes.
# - Displays all the values found and settings calculated if the --verbose
#   parameter is used.
# - Exits with OK (0), WARNING (1), or ERROR (2) based on projected memory use
#   with all (allowed) HTTP processes running.
#        OK: Maximum number of HTTP processes fit within available RAM.
#   WARNING: Maximum number of HTTP processes exceeds available RAM, but still
#            fits within the free swap.
#     ERROR: Maximum number of HTTP processes exceeds available RAM and swap.
 
# Changes:
#
# v2.4:
# - Added config for Apache Httpd v2.5 and 2.6 (identical to 2.4).
# - Added config for 'eventopt' MPM (identical to 'event' MPM).
 
use strict;
use warnings;
use POSIX;
use Getopt::Long;
 
no warnings 'once';    # no warning for $DBI::err
 
my $VERSION = '2.4';
my $pagesize = POSIX::sysconf(POSIX::_SC_PAGESIZE);
my @stathrefs;
my $err = 0;
my %mem = (
    'MemTotal' => '',
    'MemFree' => '',
    'Cached' => '',
    'SwapTotal' => '',
    'SwapFree' => '',
);
my %httpd = (
    'EXE' => '',
    'ROOT' => '',
    'CONFIG' => '',
    'MPM' => '',
    'VERSION' => '',
);
my $cf_IfModule = '';
my $cf_MaxName = '';    # defined based on httpd version (MaxClients or MaxRequestWorkers)
my $cf_LimitName = '';    # defined once MPM is determined (MaxClients/MaxRequestWorkers or ServerLimit)
my $cf_ver = '';
my $cf_min = '2.2';
my $cf_mpm = '';
my %cf_read = ();
my %cf_changed = ();
my %cf_defaults = (
    '2.2' => {
        'prefork' => {
            'StartServers' => 5,
            'MinSpareServers' => 5,
            'MaxSpareServers' => 10,
            'ServerLimit' => 256,
            'MaxClients' => 256,
            'MaxRequestsPerChild' => 10000,
        },
        'worker' => {
            'StartServers' => 3,
            'MinSpareThreads' => 75,
            'MaxSpareThreads' => 250,
            'ThreadsPerChild' => 25,
            'ServerLimit' => 16,
            'MaxClients' => 400,
            'MaxRequestsPerChild' => 10000,
        },
    },
    '2.4' => {
        'prefork' => {
            'StartServers' => 5,
            'MinSpareServers' => 5,
            'MaxSpareServers' => 10,
            'ServerLimit' => 256,
            'MaxRequestWorkers' => 256,    # aka MaxClients
            'MaxConnectionsPerChild' => 0,    # aka MaxRequestsPerChild
        },
        'worker' => {
            'StartServers' => 3,
            'MinSpareThreads' => 75,
            'MaxSpareThreads' => 250,
            'ThreadsPerChild' => 25,
            'ServerLimit' => 16,
            'MaxRequestWorkers' => 400,    # aka MaxClients
            'MaxConnectionsPerChild' => 0,    # aka MaxRequestsPerChild
        },
    },
);
$cf_defaults{'2.5'} = $cf_defaults{'2.4'};
$cf_defaults{'2.6'} = $cf_defaults{'2.5'};
 
# The event MPM config is identical to the worker MPM config
# Uses a hashref instead of copying the hash elements
for my $ver ( keys %cf_defaults ) {
    $cf_defaults{$ver}{'event'} = $cf_defaults{$ver}{'worker'};
    $cf_defaults{$ver}{'eventopt'} = $cf_defaults{$ver}{'event'};
}
# easiest way to copy the three-dimensional hash without using a module
for my $ver ( keys %cf_defaults ) {
    for my $mpm ( keys %{$cf_defaults{$ver}} ) {
        for my $el ( keys %{$cf_defaults{$ver}{$mpm}} ) {
            $cf_read{$ver}{$mpm}{$el} = $cf_defaults{$ver}{$mpm}{$el};

Copyright 2004-2019 Phil Lembo