Cliff,
Here's the diff of src/main/http_main.c No children are spawned if the
file /tmp/spawn.lock is readable by the root webserver.
I also post yet another watchdog script. It touches the spawnlock file and
kills/shuts down too large apache children.
It uses the /proc filesystem heavily, so might not be too portable.
Enjoy,
-Balazs
[balazs@felix apache_1.3.14]$ diff src/main/http_main.c.ORIG src/main/http_main.c
4419a4420,4423
> /* BALAZSD */
> int spawn_lock=0;
> FILE *SPAWN;
> /* BALAZSD */
4483a4488,4495
>
> /* BALAZSD */
> if( SPAWN=fopen( "/tmp/spawn.lock", "r" )){
> fclose( SPAWN );
> spawn_lock = 1;
> }
> /* BALAZSD */
>
4506a4519,4526
> /* BALAZSD */
> else if ( spawn_lock ) {
> ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, server_conf,
> "Server would've spawned, but lockfile found");
>
> idle_spawn_rate = 1;
> }
> /* BALAZSD */
#!/usr/bin/perl
use strict;
# ===================== D E C L A R A T I O N S ===================
#These are the variables that are worth changing through USR2
use vars qw( $STOPPED $INTERVAL $DEFAULT $USR1LIM $TERMLIM $SPAWNLIM );
# Bad globals...
use vars qw( $opt_i $opt_s $FREEMEM $LOADAVG $CPUUTIL $CHILDINFO $SPAWNLOCK_SET
@SIGKILLNEXT);
# ======================== C O N F I G =============================
# File to log to using append
my $LOGFILE = "/tmp/balazsd.log";
# File that stops apache from spawning news kids
my $SPAWNLOCK = "/tmp/spawn.lock";
require 'getopts.pl';
&Getopts('i:s:');
# Default interval at which processes are checked
$INTERVAL = $opt_i || 3;
# =================== E N D O F C O N F I G =====================
# Detach
exit if fork();
`renice -20 $$`;
# Or have some other way to run this as max priority
# For example start as root and then change user to web
$| = 1;
my $scriptname = $opt_s || usage();
logme ("Monitoring <$scriptname> at $INTERVAL seconds with PID #$$\n");
$SIG{TERM} = sub { $STOPPED = 1 };
$SIG{USR1} = sub { $DEFAULT = 1 };
my $default_action = \&autopilot_action;
$SIG{USR2} = \&handle_usr2;
# Default values for the limits
$USR1LIM = 45_000_000; # send SIGUSR1 to a process if uses more mem then
$USR1LIM
$TERMLIM = 80_000_000; # || SIGTERM ||
$SPAWNLIM = 30_000_000; # Stop apache spawning new kids if free mem <
$SPAWNLIM
my ($oldstarttime, $oldstartproc, $starttime, $startproc);
while( not $STOPPED ){
( $oldstarttime, $oldstartproc ) = ($starttime, $startproc);
($starttime, $startproc) = getproctime();
$CPUUTIL = 100 * (1-( $startproc-$oldstartproc ) / (
$starttime-$oldstarttime ));
gather_data();
if( $DEFAULT ){
logme("!!! AUTOPILOT MODE !!!");
&$default_action();
}
else {
eval {action()};
logme("action ERROR: $@") if $@;
}
my $currtime;
($currtime, undef) = getproctime();
my $sleeptime = $starttime + $INTERVAL - $currtime;
select undef, undef, undef, $sleeptime if $sleeptime > 0;
}
logme ("Finished successfully\n");
exit 0;
# =========================== S U B S ===============================
sub usage {
warn "Usage: $0 -s scriptname [ -i interval ]\n";
exit 1;
}
sub logme {
my $extralinefeed = $_[$#_] =~ /\n$/ ? "" : "\n";
open LOGFILE, ">>$LOGFILE";
print LOGFILE "balazsd: ", scalar localtime, ": @_$extralinefeed";
close LOGFILE;
}
sub getproctime {
unless ( open (UPTIME, "/proc/uptime")){
logme ("getproctime failed: $!\n");
return ( 0 , 0 );
}
my ($rtime, $utime) = split " ", <UPTIME>;
close UPTIME;
($rtime, $utime);
}
sub handle_usr2 {
do "/tmp/balazsd.eval";
# FIXME
`(echo; echo;echo -n "At ";date;cat /tmp/balazsd.eval;echo =================) >>
/tmp/balazsd.eval.log`;
if( $@ ){
logme("handle_usr2 ERROR $@");
}
else {
logme("Caught USR2 and evaled code successfully.");
}
}
# This is the piece of code that is always executed when
# $DEFAULT == 1 no matter what was evaled.
sub autopilot_action {
my $lockfile = $FREEMEM < $SPAWNLIM ? 1 : 0;
if( $lockfile ){
open SPAWNLOCK , ">$SPAWNLOCK";
print SPAWNLOCK ".";
close SPANLOCK;
logme("Setting SPANLOCK") if ! $SPAWNLOCK_SET;
$SPAWNLOCK_SET = 1;
}
else {
unlink $SPAWNLOCK;
logme("Releasing SPANLOCK") if $SPAWNLOCK_SET;
$SPAWNLOCK_SET = 0;
}
for ( @SIGKILLNEXT ){
if( kill 0, $_){
kill 9, $_ ;
logme (" $_ SIGKILLED");
}
}
@SIGKILLNEXT = ();
for my $pid ( keys %{$CHILDINFO->{children}} ){
if( $CHILDINFO->{children}{$pid}{mem} > $TERMLIM ){
kill 15, $pid;
push @SIGKILLNEXT, $pid;
logme(" $pid SIGTERM-ed");
}
elsif ( $CHILDINFO->{children}{$pid}{mem} > $USR1LIM ){
kill 10, $pid;
logme(" $pid SIGUSR1-ed");
}
}
}
# The default for action is of course autopilot_action
sub action {
autopilot_action();
}
sub gather_data {
&read_loadavg();
&read_freemem();
&read_childinfo();
logme("MEM: $FREEMEM LOADAVG: $LOADAVG CPUUTIL: $CPUUTIL");
}
sub read_loadavg {
open LOADAVG, "/proc/loadavg";
($LOADAVG, undef) = split / /, <LOADAVG>, 2;
close (LOADAVG );
}
sub read_freemem {
open FREEMEM, "/proc/meminfo";
<FREEMEM>;
(undef, undef, undef, $FREEMEM, undef ) = split / +/, <FREEMEM>;
close FREEMEM;
}
sub read_childinfo {
delete $CHILDINFO->{children};
chdir "/proc";
my @pids = <*>;
for my $pid ( @pids ){
next unless $pid =~ /^\d+$/;
my (@pidstat);
open PIDSTAT, "$pid/stat";
@pidstat = split / +/, <PIDSTAT>;
close PIDSTAT;
next if $pidstat[3] == 1; # Don't take the parent
next unless $pidstat[1] =~ /^\($opt_s\)/;
$CHILDINFO->{children}{$pid}{mem} = $pidstat[22];
}
}
On Wed, 17 Jan 2001, ___cliff rayman___ wrote:
> i think its worth posting to the list. it will be forever in the
> archives when someone needs it.
>
> thanks!
>
> Balazs Rauznitz wrote:
>
> > On Wed, 17 Jan 2001, ___cliff rayman___ wrote:
> >
> > > i and others have written on the list before, that pushing apache
> > > children into swap causes a rapid downward spiral in performance.
> > > I don't think that MaxClients is the right way to limit the # of children. i
>think
> > > MaxSpareCoreMemory would make more sense. You could
> > > set this to 1K if your server was designated for Apache
> > > only, or set it to a higher value if it were a multipurpose machine.
> > > mod_perl/apache and paging/swapping just don't mix.
> >
> > Once I wrote a patch to apache so that it would not spawn new children if
> > a certain file was present in the filesystem. You can then have a watchdog
> > process touch or delete that file based on any criteria you want. Imo
> > having a separate and flexible process is better than apache trying to
> > make these decisions...
> > I'll dig it up if interested.
> >
> > -Balazs
>
> --
> ___cliff [EMAIL PROTECTED]http://www.genwax.com/
>
>