Skip to content

Instantly share code, notes, and snippets.

@kraih
Last active March 20, 2021 14:33
Show Gist options
  • Save kraih/5551292 to your computer and use it in GitHub Desktop.
Save kraih/5551292 to your computer and use it in GitHub Desktop.
#
# Open 10k concurrent WebSocket connections with the client and server running
# in the same process and perform 10k WebSocket message roundtrips
#
# Tested on OS X 10.9.2 (MacBook Air) with Perl 5.18.2 and EV 4.17 (kqueue)
#
# 560.9MB memory usage, 0% CPU usage once roundtrips are finished after 36s
# (with all 20k sockets still open)
#
# Get the latest version of Mojolicious from http://github.com/kraih/mojo
# $ sudo sysctl -w kern.maxfiles=40960 kern.maxfilesperproc=20480
# $ ulimit -n 20480
# $ LIBEV_FLAGS=8 perl c10k.pl
#
use Mojo::Base -strict;
use Mojolicious::Lite;
use Mojo::IOLoop;
use Mojo::Server::Daemon;
use Mojo::UserAgent;
# Silence
app->log->level('error');
# Echo incoming WebSocket messages
my $num;
websocket '/' => sub {
my $self = shift;
say 'Opened: ', ++$num;
$self->on(message => sub { shift->send(shift) });
$self->on(finish => sub { say 'Closed: ', --$num });
};
# Server with longer than normal inactivity timeout
my $daemon = Mojo::Server::Daemon->new(
silent => 1,
app => app,
inactivity_timeout => 300,
listen => ['http://127.0.0.1']
)->start;
my $port
= $daemon->ioloop->acceptor($daemon->acceptors->[0])->handle->sockport;
# Our event loop will have to handle 20k sockets
Mojo::IOLoop->singleton->max_connections(100000);
# Client with longer than normal connect and inactivity timeout
my $ua
= Mojo::UserAgent->new(connect_timeout => 300, inactivity_timeout => 300);
# 100 batches of 100 WebSocket connections
my $start = time;
my $timing = Mojo::IOLoop->delay(
sub { say '10k roundtrips finished in ', (time - $start), ' seconds.' });
_batch(100);
Mojo::IOLoop->start;
sub _batch {
return unless my $batch = shift;
say 'Batch: ', $batch--;
my $next = Mojo::IOLoop->delay(sub { _batch($batch) });
for (1 .. 100) {
my $connected = $next->begin;
my $received = $timing->begin;
$ua->websocket("ws://localhost:$port" => sub {
my ($ua, $tx) = @_;
say 'WebSocket handshake failed!' and return unless $tx->is_websocket;
$tx->on(message => $received);
$tx->send('Hello Mojo!');
$connected->();
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment