One of my associates suggested this patch. The idea is to reduce
loop_sleep if we had to spawn a lot of children last time through the
loop. This way on restart (since $created_children is initialized to
$idle_children), and on sudden concurrency spikes, we loop quickly
enough to spawn the children we need very quickly; whereas under normal
conditions, we don't bother. I still decreased loop_sleep by half in
our own version, so that the longest wait clients will experience during
a drastic concurrency increase would be just slightly above 15 seconds.
Would there be any interest in accepting this if I tested it and put
it in my git?
-Jared
On 06/02/2009 08:09 AM, Jared Johnson wrote:
Why not set --idle-children at start-up to something higher (or just 0
to disable)?
Setting it higher is a bit bothersome because our QP children use too
much memory right now (mainly from using DBIx::Class), so it would be a
bit unfortunate to have more memory-consuming kids around that aren't
needed. As for disabling idle-children.. what exactly would the
behavior be with disabled idle children? In a situation where
concurrency is saturated, it seems that QP spawns $idle_children
processes every $loop_wait seconds. Would QP instead spawn a new child
_immediately_ when a new connection attempt came in? Or if it still
waits $loop_wait seconds, how many children does it spawn when it sees
some are needed?
-Jared
--- a/qpsmtpd-prefork
+++ b/qpsmtpd-prefork
@@ -75,7 +75,7 @@ my $max_children = 15; # max number of child processes to spawn
my $idle_children = 5; # number of idle child processes to spawn
my $maxconnip = 10;
my $child_lifetime = 100; # number of times a child may be reused
-my $loop_sleep = 30; # seconds main_loop sleeps before checking children
+my $loop_sleep = 15; # seconds main_loop sleeps before checking children
my $re_nice = 5; # substracted from parents current nice level
my $d_start = 0;
my $quiet = 0;
@@ -339,10 +339,11 @@ sub reaper {
#arg0: void
#ret0: void
sub main_loop {
+ my $created_children = $idle_children;
while (1) {
# if there is no child death to process, then sleep EXPR seconds
# or until signal (i.e. child death) is received
- sleep $loop_sleep unless @children_term;
+ sleep $loop_sleep / ($created_children * 2 + 1) unless @children_term;
# block CHLD signals to avoid race
my $sigset = block_signal(SIGCHLD);
@@ -379,9 +380,9 @@ sub main_loop {
}
# spawn children
- for (my $i = scalar(keys %children) ; $i < $chld_pool ; $i++) {
- new_child(); # add to the child pool
- }
+ $created_children = $chld_pool - keys %children;
+ $created_children = 0 if $created_children < 0;
+ new_child() for 1..$created_children;
# unblock signals
unblock_signal($sigset);