[jabberd] Jabber2 Stress Testing

Al Starbard al at devianttechnologies.com
Sun Aug 8 14:17:38 CDT 2004


Hi Everyone,

We've been doing some stress testing of the j2 server and have some 
results to share with the list.  The server hardware is as follows:

- Two Intel Xeon 2.4GHz CPU with 512K cache, 533FSB
- 7GB DDR2100 (PC-266) ECC Registered DDR SDRAM

The test was structured to test message throughput and total 
connections.  We had enough client hardware to connect 6000 clients and 
have them continuously sending messages to one another.  The perl script 
used for testing is attached.  The settings are as follows:

- Karma disabled
- No message logging
- Unencrypted communications (5222)
- Message size: 140 chars
- Messages/User/Minute: 3


The results are:
					
Connections	SM Size		CPU	C2S	C2S	Total
		(MB)		Load	CPU %	Size	Msgs/Sec
  				(5 min)		(MB)	
500		15		0.02	10		25
1000		42		0.08	20		50
1500		85		0.2	40		75
2000		140		0.35	65		100
2500		214		0.3	70		125
3000		305		0.4	85		150
3500		431		0.45	90		175
4000		569		0.48	95	520 	200	
4500		713		0.66	98	540 	225
5000		872		0.67	99	596 	250
5500		1033		0.67	99	637 	275
6000		1200		0.67	99	730 	300

Some observations:

- The session manager proc grows continuously.  If clients are 
disconnected and reconnected the SM will grow further.

- The C2S proc continues to grow while under message traffic.  Not sure 
if this is due to a leak or C2S not being able to keep up with the 
message traffic.  It seemed to become CPU bound around 4500-5000 users 
which is somewhere in the 225-250 msg/sec range.  Not sure if this is 
due to a leak or possibly messages being cached because c2s couldn't 
keep up with the message traffic.  Although, at 6000 users and 300 
messages per second we tried sending messages to one another and found 
there to be no noticable delay.

- The server appeared to be stable under load.  It didn't crash until 
the C2S finally got too large.


We plan some further tests in the near future.  We'll send the results 
to the list as get them.

-- 
Al Starbard
Deviant Technologies, Inc.

-------------- next part --------------
#!/usr/bin/perl -w
#===================================================================================
#
#         FILE:  bmark.pl
#
#        USAGE:  ./bmark.pl 
#
#  DESCRIPTION:  
#
#        FILES:  ---
#        NOTES:  ---
#       AUTHOR:    <>
#      COMPANY:  
#      VERSION:  1.0
#      CREATED:  02/28/2004 03:42:10 PM EST
#     REVISION:  ---
# Usage message
my $USAGE = sub { my $scriptname = $0 =~ /[^\/]+$/ ? $& : $0; return

    "\nUsage:\n\n"
  . "  $scriptname [-h]\n"
  . "  $scriptname users start\n"
  . "    -h        : print this help message.\n"
  . "    -w window : time window (in seconds) for sending one message for each user pair.\n"
  . "              : default is 10 seconds.\n"
  . "    -l length : length of message to send.\n"
  . "              : default is 128 characters.\n"
  . "    users     : number of users to connect.\n"
  . "    start     : user number to begin with.\n"
  . "\n";

};

#===================================================================================

use Benchmark;
use Time::HiRes qw(sleep);
use strict;
use Net::Jabber qw(Client);
use Getopt::Std;

# Setup signal handlers.
  
$SIG{INT}  = sub { $main::done = 1; };
$SIG{TERM} = sub { $main::done = 1; };

# Get the command line options.
my ($opt_w, $opt_h, $opt_l);
my $opt_ok = getopts('hl:w:');
   
# Print the usage if -h or if there was an error
die &$USAGE if ((!$opt_ok || $opt_h) || @ARGV != 2);

my $users = shift;
die "Number of users must be a positive integer between 1 and 500.\n"
    unless ($users >= 1 && $users <= 500);

my $start_user = shift;
die "Starting user must be a positive integer between 1 and 20000.\n"
    unless ($start_user >= 1 && $start_user <= 20000);

$opt_w = 10 unless $opt_w;
$opt_l = 128 unless $opt_l;

our $done = 0;
our $caught_sig = 0;
my $server      = "j2.devianttechnologies.com";
my $domain      = "j2.devianttechnologies.com";
my $unames      = "test";
my $padchars    = $opt_l;
my $throttle    = $opt_w;
my $port        = "5222";
my $ssl         = 0;
$port           = "5223"
    if( $ssl == 1 );
my $con_type    = "tcpip";
$con_type       = "http"
    if( $ssl == 1 );
my $resource    = "perl-jabber";
my $debuglevel  = 0;


warn "Total message traffic is " . ($users/2)/$throttle . " $padchars character messages per second.\n";
warn "Equivalent to each user sending " . ($users/2)/$throttle*60/$users . " messages per minute.\n";

our $reciever_pid;
if( $reciever_pid = fork ) {
    sender( $server, $port, $resource, $domain, $padchars, $throttle, $ssl, $con_type, $debuglevel, $users, $start_user );
} elsif( defined $reciever_pid ) {
    reciever( $server, $port, $resource, $debuglevel, $ssl, $con_type);
}


sub reciever {
    my $server      = shift;
    my $port        = shift;
    my $resource    = shift;
    my $debug       = shift;
    my $ssl         = shift;
    my $con_type    = shift;

    my @con;

    my $i = $start_user + 1;
    while( $i < ($users + $start_user) ) {
        my $user = "test" . $i;
        my $pass = "test" . $i;

        my $con = jabber_connect( $server, $port, $user, $pass, $resource, $debug, $ssl, $con_type );

        $con->SetMessageCallBacks(
            normal=>\&handle_message,
            chat=>\&handle_message
        );
        $con->RosterGet();
        $con->PresenceSend();
        $i += 2;
        push(@con, $con);
    }

    # Keep processing events
    while (1) {
        foreach( @con ) {
            print "Event did not process correctly!\n"
                unless( defined($_->Process()) );
        }
        if ($done) {
            warn "Receivier exiting.\n";
            last;
        }
    }

    foreach( @con ) {
        $_->Disconnect();
    }
}

sub sender {
    my $server      = shift;
    my $port        = shift;
    my $resource    = shift;
    my $domain      = shift;
    my $padchars    = shift;
    my $throttle    = shift;
    my $ssl         = shift;
    my $con_type    = shift;
    my $debug       = shift;
    my $users       = shift;
    my $start_user  = shift;

    my $padding;
    foreach( 1..$padchars ) {
        $padding .= ".";
    }

    my @con;

    my $i = $start_user;
    while( $i < ($users + $start_user) ) {
        my $user = "test" . $i;
        my $pass = "test" . $i;

        my $con = jabber_connect( $server, $port, $user, $pass, $resource, $debug, $ssl, $con_type );
        $con->RosterGet();
        $con->PresenceSend();

        my $recipient = "test" . ($i + 1);
        $con->{recipient} = $recipient . "\@" . $domain;
        $i = $i + 2;
        push(@con, $con);
    }

    my $delay = $throttle / @con;

    while (1) {
        my $t0 = new Benchmark;
    	foreach( @con ) {
            my $timestamp = time();
            my $mess = new Net::Jabber::Message();
            $mess->SetMessage(
                to=>$_->{recipient},
                type=>"chat",
                body=>"$padding :$timestamp"
            );
            $_->Send($mess);
            sleep($delay);
        }
        my $t1 = new Benchmark;
        #warn "Sent " . scalar(@con) . " messages in " . timestr(timediff($t1, $t0)) . "\n";
        if ($done) {
            warn "Sender exiting.\n";
            last;
        }
    }

    my $mess = new Net::Jabber::Message();
    $mess->SetMessage(
        to=>$_->{recipient},
        type=>"chat",
        body=>"DONE!"
    );
    $con[0]->Send($mess);

    sleep(10);
    foreach( @con ) {
        $_->Disconnect();
    }
}

sub jabber_connect { 
    my $con_server     = shift;
    my $con_port       = shift;
    my $con_user       = shift;
    my $con_password   = shift;
    my $con_resource   = shift;
    my $debug          = shift;
    my $ssl            = shift;
    my $con_type       = shift;
    
    my $ReCon = new Net::Jabber::Client(debuglevel=>$debug);

    my @result = ();
    $result[0] = "not ok";

    while( $result[0] ne "ok" ) {
        while( !($ReCon->Connected()) ) {
            $ReCon->Connect( 
                hostname        =>  $con_server,
                port            =>  $con_port,
                connectiontype  =>  $con_type,
                ssl             =>  $ssl,
            );
        }

        @result = $ReCon->AuthSend (
            username=>$con_user,
            password=>$con_password,
            resource=>$con_resource,
            timeout => 60,
        );
	
        $result[0] = "not ok"
	    unless $result[0];
    }

    return $ReCon;
}


sub handle_message {
    shift;
    my $message = new Net::Jabber::Message(@_);
    my $type = $message->GetType();

    my $recieved_msg = $message->GetBody();

    if( $recieved_msg eq 'DONE!' ) {
        $done = 1;
        return;
    }

    if( $type eq "chat" ) {
        my $user_from = $message->GetFrom();
        my( $bulk, $timestamp ) = split( /:/, $recieved_msg );
        my $timelapse = time() - $timestamp;

        my( $uname,$crap ) = split( /\@/, $user_from );
        #print "message from $user_from - $timelapse secs\n";
    }
}


More information about the jabberd mailing list