This patch is for qpsmtpd-forkserver 0.30, but looks to be easily
implemented into 0.31 as well. Basically, this patch creates a
function that is called to check the current load and number of
connections. Been in production here for a while and seems to be
stable. Let me know what you think. BTW.. The idea for this patch came
from one I saw on the list but I can't remember for the life of me who
wrote the original one.
******** Start qp-fork-maxload.patch *********
--- qpsmtpd-forkserver-orig 2006-01-23 16:36:50.952304966 -0600
+++ qpsmtpd-forkserver 2006-01-26 18:22:44.447540419 -0600
@@ -18,11 +18,12 @@
$| = 1;
# Configuration
-my $MAXCONN = 90; # max simultaneous connections
-my $PORT = 25; # port number
-my $LOCALADDR = '0.0.0.0'; # ip address to bind to
-my $USER = 'smtpd'; # user to suid to
+my $MAXCONN = 90; # max simultaneous connections
+my $PORT = 25; # port number
+my $LOCALADDR = '0.0.0.0'; # ip address to bind to
+my $USER = 'smtpd'; # user to suid to
my $MAXCONNIP = 5; # max simultaneous connections from one IP
+my $MAXLOAD = 4.0; # max load before we stop accepting
connections, setting of 0.0 will disable
sub usage {
print <<"EOT";
@@ -32,6 +33,8 @@
-c, --limit-connections N : limit concurrent connections to N; default 15
-u, --user U : run as a particular user (default 'smtpd')
-m, --max-from-ip M : limit connections from a single IP; default 5
+ -a, --max-load F.F : Stop accepting connections at this load.
+ A setting of 0.0 will disable this feature;
default 4.0
EOT
exit 0;
}
@@ -41,13 +44,15 @@
'c|limit-connections=i' => \$MAXCONN,
'm|max-from-ip=i' => \$MAXCONNIP,
'p|port=i' => \$PORT,
- 'u|user=s' => \$USER) || &usage;
+ 'u|user=s' => \$USER,
+ 'a|max-load=f' => \$MAXLOAD) || &usage;
# detaint the commandline
if ($PORT =~ /^(\d+)$/) { $PORT = $1 } else { &usage }
if ($LOCALADDR =~ /^([\d\w\-.]+)$/) { $LOCALADDR = $1 } else { &usage }
if ($USER =~ /^([\w\-]+)$/) { $USER = $1 } else { &usage }
if ($MAXCONN =~ /^(\d+)$/) { $MAXCONN = $1 } else { &usage }
+if ($MAXLOAD =~ /^(\d+(\.\d+)?)$/) { $MAXLOAD = $1 } else { &usage }
delete $ENV{ENV};
$ENV{PATH} = '/bin:/usr/bin:/var/qmail/bin';
@@ -69,6 +74,32 @@
exit(0);
}
+my $curload = 0.0;
+sub getLoadAvg {
+ if ( $^O =~ /^linux$/i ) {
+ if ( open PROC_LOADAVG, '/proc/loadavg') {
+ ($curload = <PROC_LOADAVG>) =~
s/^\s*(\d+\.\d+)\s.*$/$1/;
+ close PROC_LOADAVG;
+ }
+ $curload =~ s/\n//;
+ }
+}
+my $ACCEPT_NEW_CONN = 1;
+my $running = 0;
+sub checkStatus {
+ if ( $MAXCONN > 0 ) {
+ $running = scalar keys %childstatus;
+ $ACCEPT_NEW_CONN = 0 if $running >= $MAXCONN;
+ $ACCEPT_NEW_CONN = 1 if $running < $MAXCONN;
+ }
+ if ( $MAXLOAD > 0.0 ) {
+ if ( $ACCEPT_NEW_CONN == 1 ) {
+ getLoadAvg();
+ $ACCEPT_NEW_CONN = 0 if $curload >= $MAXLOAD;
+ }
+ }
+}
+
$SIG{CHLD} = \&REAPER;
$SIG{INT} = \&HUNTSMAN;
$SIG{TERM} = \&HUNTSMAN;
@@ -101,13 +132,25 @@
', group '.
(getgrgid($)) || $)));
+if ( $MAXLOAD > 0.0 ) {
+ ::log(LOGINFO, "MAXLOAD detection enabled, will stop accepting
connections once load avg reaches $MAXLOAD.");
+} else {
+ ::log(LOGINFO, "MAXLOAD detection disabled.");
+}
+if ( $MAXCONN > 0 ) {
+ ::log(LOGINFO, "MAXCONN detection enabled, will stop accepting
connections once $MAXCONN connections is reached.");
+} else {
+ ::log(LOGINFO, "MAXCONN detection disabled.");
+}
+
while (1) {
- my $running = scalar keys %childstatus;
- while ($running >= $MAXCONN) {
- ::log(LOGINFO,"Too many connections: $running >= $MAXCONN. Waiting one
second.");
- sleep(1) ;
$running = scalar keys %childstatus;
- }
+ checkStatus();
+ while ( $ACCEPT_NEW_CONN == 0 ) {
+ ::log(LOGINFO,"Either load or connections are too high. Connections:
$running/$MAXCONN Load: $curload/$MAXLOAD. Waiting one second.");
+ sleep(1) ;
+ checkStatus();
+ }
my $hisaddr = accept(my $client, $server);
if (!$hisaddr) {
# possible something condition...
@@ -167,7 +210,7 @@
# don't do this!
#$0 = "qpsmtpd-forkserver: $ENV{TCPREMOTEIP} / $ENV{TCPREMOTEHOST}";
-
+ $running++;
::log(LOGINFO, "Accepted connection $running/$MAXCONN from
$ENV{TCPREMOTEIP} / $ENV{TCPREMOTEHOST}");
# dup to STDIN/STDOUT
********** End qp-fork-maxload.patch ***************
Ed McLain
Sr. Colocation Engineer
TekLinks, Inc.