You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
408 lines
15 KiB
408 lines
15 KiB
#!/usr/bin/perl
|
|
#
|
|
# Session Backend Performance Test
|
|
# --------------------------------
|
|
#
|
|
# This test is used to compare different session backend. To use it, you have
|
|
# to:
|
|
# * have a PostgreSQL database running on this host. PostgreSQL DB must:
|
|
# * listen on 127.0.0.1:5432
|
|
# * have a database names "sessions"
|
|
# * have "hstore" extension enabled is database "sessions":
|
|
# psql# CREATE EXTENSION hstore;
|
|
# * have a Pg user named "sso" identified by "sso" password
|
|
# * "sso" user must have right to create tables in database "sessions"
|
|
# * have a MySQL or MriaDB database running on this host. DB must:
|
|
# * listen on 127.0.0.1:3306
|
|
# * have a database names "sessions"
|
|
# * have a user named "sso" identified by "sso" password
|
|
# * "sso" user must have right to create tables in database "sessions"
|
|
# * have a Redis server installed on this host listen on 127.0.0.1:6379
|
|
#
|
|
# If you want to enable LDAP test:
|
|
# * set LLNGTESTLDAP environment variable to 1
|
|
# * if OpenLDAP schemes aren't available in /etc/slapd/schema, set the scheme
|
|
# directory in environment variables:
|
|
# LLNGTESTLDAP_SCHEMA_DIR=/etc/ldap/schema
|
|
# * prepare some coffee or tea
|
|
# * open the window or light a fan
|
|
# * launch the test, run away and come back 5mn later
|
|
#
|
|
#
|
|
# (c) Copyright: 2017, LemonLDAP::NG team
|
|
#
|
|
#This library is free software; you can redistribute it and/or modify
|
|
#it under the terms of the GNU General Public License as published by
|
|
#the Free Software Foundation; either version 2, or (at your option)
|
|
#any later version.
|
|
#
|
|
#This program is distributed in the hope that it will be useful,
|
|
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
#GNU General Public License for more details.
|
|
#
|
|
#You should have received a copy of the GNU General Public License
|
|
#along with this program. If not, see L<http://www.gnu.org/licenses/>.
|
|
|
|
use strict;
|
|
use DBI;
|
|
use JSON qw(from_json to_json);
|
|
use Time::HiRes;
|
|
use LWP::UserAgent;
|
|
use Redis;
|
|
|
|
system 'make stop_web_server';
|
|
|
|
eval { Redis->new->flushall };
|
|
|
|
my @legend = (
|
|
'Apache::Session::Browseable::LDAP' => 'LDAP',
|
|
'Apache::Session::MySQL (no lock)' => 'BMySQL',
|
|
'Apache::Session::Browseable::MySQL' => 'BiMySQL',
|
|
'Apache::Session::Browseable::MySQLJSON' => 'MySQLJSON',
|
|
'Apache::Session::Postgres (logged table)' => 'Postgres',
|
|
'Apache::Session::Postgres' => 'UPostgres',
|
|
'Apache::Session::Browseable::Postgres' => 'BPostgres',
|
|
'Apache::Session::Browseable::PgJSON' => 'PgJSON',
|
|
'Apache::Session::Browseable::PgJSONB' => 'PgJSONB',
|
|
'Apache::Session::Browseable::PgHstore' => 'PgHstore',
|
|
'Apache::Session::Redis' => 'Redis',
|
|
'Apache::Session::Browseable::Redis' => 'BRedis',
|
|
);
|
|
|
|
my $tests = {
|
|
(
|
|
$ENV{LLNGTESTLDAP}
|
|
? (
|
|
LDAP => {
|
|
cmd => 'cd lemonldap-ng-portal;perl t/test-ldap.pm;cd -',
|
|
globalStorage => 'Apache::Session::Browseable::LDAP',
|
|
globalStorageOptions => {
|
|
ldapServer => 'ldap://localhost:19389',
|
|
ldapBindDN => 'cn=admin,dc=example,dc=com',
|
|
ldapBindPassword => 'admin',
|
|
ldapConfBase => 'ou=sessions,dc=example,dc=com',
|
|
Index => '_whatToTrace _session_kind'
|
|
},
|
|
}
|
|
)
|
|
: ()
|
|
),
|
|
Redis => {
|
|
globalStorage => 'Apache::Session::Browseable::Redis',
|
|
globalStorageOptions => {},
|
|
},
|
|
BRedis => {
|
|
globalStorage => 'Apache::Session::Browseable::Redis',
|
|
globalStorageOptions => {
|
|
Index => '_whatToTrace _session_kind'
|
|
},
|
|
},
|
|
BMySQL => {
|
|
globalStorage => 'Apache::Session::Browseable::MySQL',
|
|
globalStorageOptions => {
|
|
DataSource => 'dbi:mysql:host=127.0.0.1;database=sessions',
|
|
UserName => 'sso',
|
|
Password => 'sso',
|
|
},
|
|
pg => [
|
|
'DROP TABLE IF EXISTS sessions',
|
|
'CREATE TABLE sessions (id varchar(64) not null primary key, a_session text)',
|
|
],
|
|
},
|
|
BiMySQL => {
|
|
globalStorage => 'Apache::Session::Browseable::MySQL',
|
|
globalStorageOptions => {
|
|
DataSource => 'dbi:mysql:host=127.0.0.1;database=sessions',
|
|
UserName => 'sso',
|
|
Password => 'sso',
|
|
Index => '_whatToTrace _session_kind _utime'
|
|
},
|
|
pg => [
|
|
'DROP TABLE IF EXISTS sessions',
|
|
'CREATE TABLE sessions (id varchar(64) not null primary key, a_session text, _whatToTrace varchar(64), _session_kind varchar(15), _utime bigint)',
|
|
'CREATE INDEX uid1 ON sessions (_whatToTrace) USING BTREE',
|
|
'CREATE INDEX _s1 ON sessions (_session_kind) USING BTREE',
|
|
'CREATE INDEX _u1 ON sessions (_utime) USING BTREE',
|
|
],
|
|
},
|
|
MySQLJSON => {
|
|
globalStorage => 'Apache::Session::Browseable::MySQLJSON',
|
|
globalStorageOptions => {
|
|
DataSource => 'dbi:mysql:host=127.0.0.1;database=sessions',
|
|
UserName => 'sso',
|
|
Password => 'sso',
|
|
},
|
|
pg => [
|
|
'DROP TABLE IF EXISTS sessions',
|
|
'CREATE TABLE sessions (id varchar(64) not null primary key, a_session json,'
|
|
. 'as_wt varchar(32) AS (a_session->"$._whatToTrace") VIRTUAL,'
|
|
. 'as_sk varchar(12) AS (a_session->"$._session_kind") VIRTUAL,'
|
|
. 'as_ut bigint AS (a_session->"$._utime") VIRTUAL,'
|
|
. 'as_ip varchar(64) AS (a_session->"$.ipAddr") VIRTUAL,'
|
|
. 'KEY as_wt (as_wt),'
|
|
. 'KEY as_sk (as_sk),'
|
|
. 'KEY as_ut (as_ut),'
|
|
. 'KEY as_ip (as_ip))'
|
|
. 'ENGINE=InnoDB',
|
|
],
|
|
},
|
|
Postgres => {
|
|
globalStorage => 'Apache::Session::Browseable::Postgres',
|
|
globalStorageOptions => {
|
|
DataSource => 'dbi:Pg:host=127.0.0.1;database=sessions',
|
|
UserName => 'sso',
|
|
Password => 'sso',
|
|
Commit => 1,
|
|
},
|
|
pg => [
|
|
'DROP TABLE IF EXISTS sessions',
|
|
'DROP INDEX IF EXISTS uid1',
|
|
'DROP INDEX IF EXISTS _s1',
|
|
'DROP INDEX IF EXISTS _u1',
|
|
'CREATE TABLE sessions (id varchar(64) not null primary key, a_session text)',
|
|
],
|
|
},
|
|
UPostgres => {
|
|
globalStorage => 'Apache::Session::Browseable::Postgres',
|
|
globalStorageOptions => {
|
|
DataSource => 'dbi:Pg:host=127.0.0.1;database=sessions',
|
|
UserName => 'sso',
|
|
Password => 'sso',
|
|
Commit => 1,
|
|
},
|
|
pg => [
|
|
'DROP TABLE IF EXISTS sessions',
|
|
'DROP INDEX IF EXISTS uid1',
|
|
'DROP INDEX IF EXISTS _s1',
|
|
'DROP INDEX IF EXISTS _u1',
|
|
'CREATE UNLOGGED TABLE sessions (id varchar(64) not null primary key, a_session text)',
|
|
],
|
|
},
|
|
BPostgres => {
|
|
globalStorage => 'Apache::Session::Browseable::Postgres',
|
|
globalStorageOptions => {
|
|
DataSource => 'dbi:Pg:host=127.0.0.1;database=sessions',
|
|
UserName => 'sso',
|
|
Password => 'sso',
|
|
Commit => 1,
|
|
Index => '_whatToTrace _session_kind _utime'
|
|
},
|
|
pg => [
|
|
'DROP TABLE IF EXISTS sessions',
|
|
'DROP INDEX IF EXISTS uid1',
|
|
'DROP INDEX IF EXISTS _s1',
|
|
'DROP INDEX IF EXISTS _u1',
|
|
'CREATE UNLOGGED TABLE sessions (id varchar(64) not null primary key, a_session text, _whatToTrace text, _session_kind text, _utime bigint)',
|
|
'CREATE INDEX uid1 ON sessions USING BTREE (_whatToTrace text_pattern_ops)',
|
|
'CREATE INDEX _s1 ON sessions (_session_kind)',
|
|
'CREATE INDEX _u1 ON sessions (_utime)',
|
|
],
|
|
},
|
|
PgHstore => {
|
|
globalStorage => 'Apache::Session::Browseable::PgHstore',
|
|
globalStorageOptions => {
|
|
DataSource => 'dbi:Pg:host=127.0.0.1;database=sessions',
|
|
UserName => 'sso',
|
|
Password => 'sso',
|
|
Commit => 1,
|
|
},
|
|
pg => [
|
|
'DROP TABLE IF EXISTS sessions',
|
|
'DROP INDEX IF EXISTS uid1',
|
|
'DROP INDEX IF EXISTS _s1',
|
|
'DROP INDEX IF EXISTS _u1',
|
|
'CREATE UNLOGGED TABLE sessions (id varchar(64) not null primary key, a_session hstore)',
|
|
"CREATE INDEX uid1 ON sessions USING BTREE ( (a_session -> '_whatToTrace') text_pattern_ops )",
|
|
"CREATE INDEX _s1 ON sessions ( (a_session -> '_session_kind') )",
|
|
"CREATE INDEX _u1 ON sessions ( ( cast(a_session -> '_utime' AS bigint) ) )",
|
|
],
|
|
},
|
|
PgJSON => {
|
|
globalStorage => 'Apache::Session::Browseable::PgJSON',
|
|
globalStorageOptions => {
|
|
DataSource => 'dbi:Pg:host=127.0.0.1;database=sessions',
|
|
UserName => 'sso',
|
|
Password => 'sso',
|
|
Commit => 1,
|
|
},
|
|
pg => [
|
|
'DROP TABLE IF EXISTS sessions',
|
|
'DROP INDEX IF EXISTS uid1',
|
|
'DROP INDEX IF EXISTS _s1',
|
|
'DROP INDEX IF EXISTS _u1',
|
|
'CREATE UNLOGGED TABLE sessions (id varchar(64) not null primary key, a_session json)',
|
|
"CREATE INDEX uid1 ON sessions USING BTREE ( (a_session ->> '_whatToTrace') text_pattern_ops )",
|
|
"CREATE INDEX _s1 ON sessions ( (a_session ->> '_session_kind') )",
|
|
"CREATE INDEX _u1 ON sessions ( ( cast(a_session ->> '_utime' AS bigint) ) )",
|
|
],
|
|
},
|
|
PgJSONB => {
|
|
globalStorage => 'Apache::Session::Browseable::PgJSON',
|
|
globalStorageOptions => {
|
|
DataSource => 'dbi:Pg:host=127.0.0.1;database=sessions',
|
|
UserName => 'sso',
|
|
Password => 'sso',
|
|
Commit => 1,
|
|
},
|
|
pg => [
|
|
'DROP TABLE IF EXISTS sessions',
|
|
'DROP INDEX IF EXISTS uid1',
|
|
'DROP INDEX IF EXISTS _s1',
|
|
'DROP INDEX IF EXISTS _u1',
|
|
'CREATE UNLOGGED TABLE sessions (id varchar(64) not null primary key, a_session jsonb)',
|
|
"CREATE INDEX uid1 ON sessions USING BTREE ( (a_session ->> '_whatToTrace') text_pattern_ops )",
|
|
"CREATE INDEX _s1 ON sessions ( (a_session ->> '_session_kind') )",
|
|
"CREATE INDEX _u1 ON sessions ( ( cast(a_session ->> '_utime' AS bigint) ) )",
|
|
],
|
|
},
|
|
};
|
|
|
|
my $times = {};
|
|
|
|
if(@ARGV) {
|
|
foreach my $t ( keys %$tests ) {
|
|
delete $tests->{$t} unless(grep /^$t$/, @ARGV);
|
|
}
|
|
}
|
|
|
|
foreach my $name ( keys %$tests ) {
|
|
my $opts = $tests->{$name}->{globalStorageOptions};
|
|
if ( my $cmd = delete $tests->{$name}->{cmd} ) {
|
|
system $cmd;
|
|
}
|
|
if ( my $cmd = delete $tests->{$name}->{pg} ) {
|
|
my $dbh = DBI->connect( $opts->{DataSource}, $opts->{UserName},
|
|
$opts->{Password}, { RaiseError => 1, AutoCommit => 1 } );
|
|
foreach (@$cmd) {
|
|
print STDERR "$_\n";
|
|
$dbh->do($_);
|
|
}
|
|
$dbh->disconnect;
|
|
}
|
|
system 'make start_web_server';
|
|
print STDERR "Removing manager protection\n";
|
|
system
|
|
q(perl -i -pe 's/protection\s*=\s*manager/protection=none/' e2e-tests/conf/lemonldap-ng.ini);
|
|
print STDERR "Read conf\n";
|
|
open F, 'e2e-tests/conf/lmConf-1.json' or die;
|
|
my $conf = join '', <F>;
|
|
close F;
|
|
$conf = from_json($conf);
|
|
|
|
foreach my $k ( keys %{ $tests->{$name} } ) {
|
|
$conf->{$k} = $tests->{$name}->{$k};
|
|
}
|
|
|
|
# Fix timeout to 2h
|
|
$conf->{timeout} = 7200;
|
|
print STDERR "Write conf\n";
|
|
open F, '>e2e-tests/conf/lmConf-1.json' or die;
|
|
print F to_json($conf);
|
|
close F;
|
|
|
|
#system 'cat e2e-tests/conf/lmConf-1.json';
|
|
sleep(1);
|
|
system 'make reload_web_server';
|
|
|
|
# Insert 1000 sessions
|
|
my $t = Time::HiRes::time();
|
|
system './e2e-tests/populate.pl';
|
|
$times->{$name}->{insert} = Time::HiRes::time() - $t;
|
|
|
|
# Initialize manager
|
|
my $ua = LWP::UserAgent->new;
|
|
$ua->get('http://manager.example.com:19876/sessions.html');
|
|
|
|
my $tmp = {
|
|
read => 0,
|
|
getLetter => 0,
|
|
getUid => 0,
|
|
getSession => 0,
|
|
};
|
|
|
|
# First loop isn't used in averages
|
|
foreach my $i ( 0 .. 10 ) {
|
|
|
|
# Test first Session Explorer access
|
|
$t = Time::HiRes::time();
|
|
my $res = $ua->get(
|
|
'http://manager.example.com:19876/manager.fcgi/sessions/global?groupBy=substr(_whatToTrace,1)'
|
|
);
|
|
$tmp->{read} += Time::HiRes::time() - $t if ($i);
|
|
$res = from_json( $res->content );
|
|
|
|
# Partial "_whatToTrace" search
|
|
my $letter = $res->{values}->[0]->{value};
|
|
$t = Time::HiRes::time();
|
|
$res = $ua->get(
|
|
'http://manager.example.com:19876/manager.fcgi/sessions/global?_whatToTrace='
|
|
. $letter
|
|
. '*&groupBy=_whatToTrace' );
|
|
$tmp->{getLetter} += Time::HiRes::time() - $t if ($i);
|
|
$res = from_json( $res->content );
|
|
|
|
# Search for an uid
|
|
my $user = $res->{values}->[$i]->{value};
|
|
$t = Time::HiRes::time();
|
|
$res = $ua->get(
|
|
'http://manager.example.com:19876/manager.fcgi/sessions/global?_whatToTrace='
|
|
. $user );
|
|
$tmp->{getUid} += Time::HiRes::time() - $t if ($i);
|
|
$res = from_json( $res->content );
|
|
|
|
# Get a session
|
|
my $id = $res->{values}->[0]->{session};
|
|
$t = Time::HiRes::time();
|
|
$res = $ua->get(
|
|
'http://manager.example.com:19876/manager.fcgi/sessions/global/'
|
|
. $id );
|
|
$tmp->{getSession} += Time::HiRes::time() - $t if ($i);
|
|
$res = from_json( $res->content );
|
|
}
|
|
|
|
# Average
|
|
foreach my $type ( keys %$tmp ) {
|
|
$times->{$name}->{$type} = $tmp->{$type} / 10;
|
|
}
|
|
|
|
# Purge half sessions
|
|
$t = Time::HiRes::time();
|
|
system 'LLNG_DEFAULTCONFFILE=e2e-tests/conf/lemonldap-ng.ini '
|
|
. 'perl -Ilemonldap-ng-common/blib/lib '
|
|
. 'lemonldap-ng-portal/site/cron/purgeCentralCache';
|
|
$times->{$name}->{purge} = Time::HiRes::time() - $t;
|
|
|
|
# Turn off webserver
|
|
system 'make stop_web_server';
|
|
}
|
|
|
|
if ( $ENV{LLNGTESTLDAP} ) {
|
|
if ( open F, 'lemonldap-ng-portal/t/testslapd/slapd.pid' ) {
|
|
my $pid = join '', <F>;
|
|
system "kill $pid";
|
|
}
|
|
system 'rm -rf lemonldap-ng-portal/t/testslapd/slapd.d';
|
|
system 'rm -rf lemonldap-ng-portal/t/testslapd/data';
|
|
system 'rm -rf lemonldap-ng-portal/t/testslapd/slapd-test.ldif';
|
|
}
|
|
|
|
#use Data::Dumper;
|
|
#print Dumper($times);
|
|
|
|
print <<EOT;
|
|
+-----------------------------------------+-------------------------------------+-----------------------------------+
|
|
| | Main use | Session explorer |
|
|
| Backend | Insert 1000 | Get 1 | Purge 500 | Parse all | 1 letter | 1 user |
|
|
+-----------------------------------------+-------------------------------------+-----------------------------------+
|
|
EOT
|
|
for ( my $i = 0 ; $i < @legend ; $i += 2 ) {
|
|
my $type = $legend[ $i + 1 ];
|
|
next unless ( $times->{$type} );
|
|
printf "|%40s |%11.5f | %.5f | %7.4f | %.5f | %.5f | %.5f |\n",
|
|
$legend[$i],
|
|
map { $times->{$type}->{$_} }
|
|
qw(insert getSession purge read getLetter getUid);
|
|
}
|
|
print
|
|
"+-----------------------------------------+-------------------------------------+-----------------------------------+\n";
|
|
|