Re: killing of greater than MaxSpareServers

2001-01-22 Thread Balazs Rauznitz


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 " ", ;
  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");
}

Re: killing of greater than MaxSpareServers

2001-01-18 Thread ___cliff rayman___

i think tuning like this is available already.
probably something like:

MinSpareServers 100
MaxSpareServers 110
StartServers 100
MaxClients 110

i haven't checked the source code to see if these values
might drive apache a little crazy (such a small range to work
in) , but it seems like the above would keep apache between 100-110
servers at all times.

you'd have to make sure Apache::GtopLimit wasn't killing
processes off too early or their would be lots of killing and
respawning of processes.

--
___cliff [EMAIL PROTECTED]http://www.genwax.com/

Jayme Frye wrote:

> This may not be quite on topic. I wonder in the case of a dedicated
> Apache/Mod_Perl server if it wouldn't be best to spawn up to a maximum
> number of child procs that the server can handle at startup. Maximum
> child procs calculated based on the amount of core memory minus amount
> of real memory used by each proc (Stas Bekman mod_perl guide Performance
> Tuning Section) with a cushion of free core memory to allow for some
> process growth and handle misc. house keeping duties of the server. Then
> use the Apache::GtopLimit module to prune child procs based on memory
> size. If a child proc grows too large because of memory leaks for
> example it is killed and a fresh proc spawned in its place. In this way
> you always have as many procs available as your server can handle for
> periods of high load. No wasted time spawning up to meet the load.
>
> Jayme Frye
> System Administrator
> Inventive Comm.






Re: killing of greater than MaxSpareServers

2001-01-18 Thread Jayme Frye

Perrin Harkins 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.
 >
 >
 > I've thought about that too.  The trick is, Apache would need to know
 > things about your application to do that right.  It would need to 
know how
 > big your processes were likely to be and how big they could get before
 > they die.  Otherwise, it has no way of knowing whether or not there's
 > enough room for another process.
 >
 > A combination of Apache::SizeLimit and a dynamically changing MaxClients
 > could possibly accomplish this, but you wouldn't want to run it too close
 > to the edge since you don't want to have to axe a process that's in the
 > middle of doing something just because it got a little too big (i.e. no
 > hard limits on per-process memory usage).
 >
 > You can't change MaxClients while the server is running, can you?
 >
 > - Perrin

This may not be quite on topic. I wonder in the case of a dedicated
Apache/Mod_Perl server if it wouldn't be best to spawn up to a maximum
number of child procs that the server can handle at startup. Maximum
child procs calculated based on the amount of core memory minus amount
of real memory used by each proc (Stas Bekman mod_perl guide Performance
Tuning Section) with a cushion of free core memory to allow for some
process growth and handle misc. house keeping duties of the server. Then
use the Apache::GtopLimit module to prune child procs based on memory
size. If a child proc grows too large because of memory leaks for
example it is killed and a fresh proc spawned in its place. In this way
you always have as many procs available as your server can handle for
periods of high load. No wasted time spawning up to meet the load.


Jayme Frye
System Administrator
Inventive Comm.





Re: killing of greater than MaxSpareServers

2001-01-17 Thread ___cliff rayman___

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/





Re: killing of greater than MaxSpareServers

2001-01-17 Thread Balazs Rauznitz


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




Re: killing of greater than MaxSpareServers

2001-01-17 Thread ___cliff rayman___

if you are able to determine how much core memory
is left, you may also be able to determine average apache
process size and variance.  then, apache can determine
whether or not to start up any additional children.  i'm not
sure how much processor time would be taken to determine
free core memory.  might not be something worth doing on
every scoreboard cycle.

there is an additional bonus for determining child size mean
and variance.  if it is noted that a process is growing exceptionally
large compared to other processes, it could be slated for death
based on its growth size and rate, rather than the number of
requests that it served.

Perrin Harkins 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.
>
> I've thought about that too.  The trick is, Apache would need to know
> things about your application to do that right.  It would need to know how
> big your processes were likely to be and how big they could get before
> they die.  Otherwise, it has no way of knowing whether or not there's
> enough room for another process.
>
> A combination of Apache::SizeLimit and a dynamically changing MaxClients
> could possibly accomplish this, but you wouldn't want to run it too close
> to the edge since you don't want to have to axe a process that's in the
> middle of doing something just because it got a little too big (i.e. no
> hard limits on per-process memory usage).
>
> You can't change MaxClients while the server is running, can you?
>
> - Perrin

--
___cliff [EMAIL PROTECTED]http://www.genwax.com/





Re: killing of greater than MaxSpareServers

2001-01-17 Thread Perrin Harkins

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.

I've thought about that too.  The trick is, Apache would need to know
things about your application to do that right.  It would need to know how
big your processes were likely to be and how big they could get before
they die.  Otherwise, it has no way of knowing whether or not there's
enough room for another process.

A combination of Apache::SizeLimit and a dynamically changing MaxClients
could possibly accomplish this, but you wouldn't want to run it too close
to the edge since you don't want to have to axe a process that's in the
middle of doing something just because it got a little too big (i.e. no
hard limits on per-process memory usage).

You can't change MaxClients while the server is running, can you?

- Perrin




Re: killing of greater than MaxSpareServers

2001-01-17 Thread ___cliff rayman___

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.

Perrin Harkins wrote:

> On Wed, 17 Jan 2001, ___cliff rayman___ wrote:
>
> > here is an excerpt from httpd.h:
>
> Good reading.  Thanks.
>
> It looks as if Apache should find the right number of servers for a steady
> load over time, but it could jump up too high for a bit when the load
> spike first comes in, pushing into swap if MaxClients is not configured
> correctly.  That may be what Sam was seeing.
>
> - Perrin

--
___cliff [EMAIL PROTECTED]http://www.genwax.com/





Re: killing of greater than MaxSpareServers

2001-01-17 Thread Perrin Harkins

On Wed, 17 Jan 2001, ___cliff rayman___ wrote:

> here is an excerpt from httpd.h:

Good reading.  Thanks.

It looks as if Apache should find the right number of servers for a steady
load over time, but it could jump up too high for a bit when the load
spike first comes in, pushing into swap if MaxClients is not configured
correctly.  That may be what Sam was seeing.

- Perrin