# documentation:2.0:performances
Keywords: documentation,2.0,performances

# Performances

Lemonldap::NG a été conçu pour être très performant. En particulier, il utilise les capacités multi-threads d'Apache-2, donc pour optimiser les performances, utilisez de préférence mpm-worker.

## Performance globale

On Linux, by default, there is no DNS cache and LemonLDAP::NG portal request DNS at every connexions on LDAP or DB. Sous forte charge, ça peut générer des centaines de requêtes DNS et des erreurs sur les connexions LDAP (timed out).

To bypass this, you can:

- Use IP in configuration to avoid DNS resolution
- Install a DNS cache like nscd, netmask or bind

## Performance des agents (handlers)

To increase handler performance, you can disable “Sessions activity timeout” To prevent it from writing to the session database.

Les agents vérifient les droits et calculent les en-têtes pour chaque requête HTTP. Donc pour augmenter les performances, évitez les règles trop complexes en utilisant les macros, groupes ou macros locales.

### Macros et groupes

Les macros et les groupes sont calculées pendant le processus d'authentification par le portail :

- les macros sont utilisées pour étendre (ou réécrire) les variables exportées. Une macro est stockée comme un attribut : elle peut contenir le résultat d'un calcul booléen ou n'importe quelle chaîne de caractères
- macros can also be used to import environment variables (these variables are in CGI format). Example: `$ENV{HTTP_COOKIE}`
- les groupes sont stockées en chaîne de caractères séparées par des espaces dans l'attribut spécial “groups” : il contient les noms des groupes dont la règle à retournée une valeur non nulle pour l'utilisateur courant
- On peut également définir des groupes dans `$hGroups` qui est une référence à une table de hashage de la forme :

    $hGroups = {
              'group3' => {
                            'description' => [
                                               'Service 3',
                                               'Service 3 TEST'
                                             ],
                            'cn' => [
                                      'group3'
                                    ],
                            'name' => 'group3'
                          },
              'admin' => {
                           'name' => 'admin'
                         }
            }

Exemples de macros:

    # macro booléenne
    isAdmin -> $uid eq 'foo' or $uid eq 'bar'
    # autre macro
    displayName -> $givenName." ".$surName

    # Utiliser une macro booléenne dans une règle
    ^/admin -> $isAdmin
    # Utiliser une macro chaîne dans un en-tête HTTP
    Display-Name -> $displayName

Exemples de groupes:

    # group
    admin -> $uid eq 'foo' or $uid eq 'bar'

    # Use a group in a rule
    ^/admin -> $groups =~ /\badmin\b/

    # Or with hGroups
    ^/admin -> defined $hGroups->{'admin'}

Noter que les groupes sont calculés après les macros, donc une règle de groupe peut utiliser une valeur issue d'une macro.
Les macros et groupes sont calculés dans l'ordre alpha-numerique, c'est à dire dans l'ordre d'affichage dans le manager. Par exemple, la macro “macro1” sear calculée avant la macro “macro2” : donc l'expression de macro2 peut utiliser la valeur $macro1. De même pour les groupes : une règle de groupe peut en utiliser une autre calculée précédemment.

### Macros locales

Les macros et les groupes sont stockées dans la base de données des sessions. Local macros is a special feature of handler that permit one to have macros useable localy only. Ces macros sont calculées seulement à leur premier usage et stockées dans le cache local des sessions (uniquement pour ce serveur) et seulement si l'utilisateur accède à l'application relative. Ce dispositif évite de stocker trop de données.

    # règle
    admin -> $admin ||= ($uid eq 'foo' or $uid eq 'bar')
    # en-tête
    Display-Name -> $displayName ||= $givenName." ".$surName

Notez que cette fonctionnalité n'est intéressante que pour les systèmes Lemonldap::NG protégeant un grand nombre d'applications

## Performances du portail

### Performances générales

Le portail est le composant le plus gros de Lemonldap::NG. Since version 2.0, it is run under FastCGI and rewritten using plugins, so performance is increased in comparison to earlier versions. You just have to disable unused plugins:

- disable unused issuer modules
- disable notifications if not used
- …

By default it uses local storage to store its tokens. If you have more than 1 portal and if your load-balancer doesn't keep state, you have to disable this to use the global session storage (General parameters » portal Parameters » Advanced Parameters » Forms). Note that this will decrease performances.

En environnement de production et pour de meilleures performances réseau, utiliser les versions compactées des librairies javascript et css : utiliser `make install PROD=yes`. Ceci est fait par défaut avec les paquets RPM/DEB.

### Performances d'Apache::Session

Les agents (handlers) Lemonldap::NG utilisent un cache local pour stocker les sessions (pour 10 minutes). Ainsi, les modules Apache::Session ne posent pas de problèmes aux agents. En revanche, ce peut-être un frein pour le portail :

1. Lorsque sont activées les paramètres de restriction d'ouverture de session, celles-ci sont toutes examinées à chaque nouvelle authentification sauf lorsqu'un module de la famille Apache::Session::Browseable est utilisé.
2. Comme MySQL ne dispose pas toujours de dispositif de transaction, Apache::Session::MySQL a été conçu en utilisant les verrous MySQL. Ceci dégrade fortement les performances de MySQL, si vous voulez stocker les sessions dans une base de données MySQL, utilisez l'une des solutions suivantes

Since 1.9.6, LLNG portal and handler check if session is valid at each access, so purgeCentralCache cron no longer needs to be launched every 10 minutes: one or two times per day is enough.

#### Remplacer MySQL par Apache::Session::Flex

Dans le champ “Module Apache::Session”, indiquez ”Apache::Session::Flex” et utilisez les paramètres suivants :

    Store      -> MySQL
    Lock       -> Null
    Generate   -> MD5
    Serialize  -> Storable
    DataSource -> dbi:mysql:sessions;host=...
    UserName   -> ...
    Password   -> ...

Depuis la version 1.90 d'Apache::Session, on peut utiliser Apache::Session::MySQL::NoLock à la place

#### Utiliser Apache::Session::Browseable

Apache::Session::Browseable est une surcouche d'autres modules Apache::Session qui ajoute des capacités d'indexation. Prefer versions ≥ 1.2.5 to have better performances in DB cleaning. To use it (with PostgreSQL for example), choose “Apache::Session::Browseable::Postgres” as “Apache::Session module” and use the following parameters:

    DataSource -> dbi:Pg:database=sessions;host=...
    UserName   -> user
    Password   -> password
    Index      -> ipAddr uid

Notez que Apache::Session::Browseable::MySQL n'utilise pas les verrous MySQL.

Look at Browseable session backend to known which index to choose.

Some Apache::Session module are not fully usable by Lemonldap::NG such as Apache::Session::Memcached since these modules do not offer capability to browse sessions. They does not allow one to use sessions explorer neither manage one-off sessions.

#### Performance test

A Apache::Session::Browseable::Redis has been created, it is the faster (except for session explorer, defeated by Apache::Session::Browseable::DBI/LDAP])

This test isn't a “only-backend” test but embed some LLNG methods, so real differences between engines are mitigate here.

Backend | Portal and handlers | Session explorer and one-off sessions
--- | --- | ---
Nom | Configuration | Insert 1000 | Search 1 | Purge 500 | Parse all | Search by substring | Search by UID
Apache::Session::Browseable::LDAP | mdb | 159.66 | 0.0120 | 49.22 | 0.1110 | 0.0076 | 0.0050
Apache::Session::MySQL | No lock | 87.20 | 0.0039 | 23.14 | 0.0281 | 0.0252 | 0.0235
Apache::Session::Browseable::MySQL |  | 91.79 | 0.0039 | 0.139 (1) | 0.0272 | 0.0036 | 0.0026
Apache::Session::Browseable::MySQLJSON |  | 86.06 | 0.0145 | 0.151 (2) | 0.0104 | 0.0137 | 0.0038
Apache::Session::Postgres |  | 18.31 | 0.0095 | 13.40 | 0.0323 | 0.0277 | 0.0264
Apache::Session::Postgres | Unlogged table | 9.16 | 0.0095 | 7.91 | 0.0318 | 0.0270 | 0.0254
Apache::Session::Browseable::Postgres | Unlogged table with indexes | 9.24 | 0.0094 | 0.103 (1) | 0.0301 | 0.0036 | 0.0028
Apache::Session::Browseable::PgJSON | Unlogged table, json field | 9.25 | 0.0091 | 0.108 (1) | 0.0247 | 0.0035 | 0.0029
Apache::Session::Browseable::PgJSON | Unlogged table, jsonb field | 9.25 | 0.0091 | 0.105 (1) | 0.0126 | 0.0034 | 0.0029
Apache::Session::Browseable::PgHstore | Unlogged table, hstore field | 9.62 | 0.0111 | 0.105 (1) | 0.0125 | 0.0033 | 0.0029
Apache::Session::Redis |  | 2.13 | 0.0033 | 1.158 | 0.0623 | 0.0570 | 0.0550
Apache::Session::Browseable::Redis |  | 2.36 | 0.0033 | 1.154 | 0.0643 | 0.1048 | 0.0024
The source of this test is available in sources: e2e-tests/sbperf.pl

- (1) : “purge” test is done with Apache::Session::Browseable-1.2.5 and LLG-2.0. Earlier results are not so good.
- (2) : “purge” test is done with Apache::Session::Browseable-1.2.6 and LLG-2.0.

Analysis:

- LDAP servers are “write-once-read-many”, so write performances are very bad. Don't use this on heavy load if “Session activity timeout” is enabled (if set, handler “write” sessions)
- MySQL/MariaDB is better to read than to write. Prefer PostgreSQL if you use “Session activity timeout”
- Logged tables decrease a lot insert performances with PostgreSQL, so use unlogged tables for sessions except for persistent sessions
- Redis is the best for main usage
- Browseable::Postgres/PgHstore/PgJSON are the best SQL solutions on average

### Performances LDAP

Le serveur LDAP peut être un frein lorsque vous utilisez la récupération des groupes LDAP. Vous pouvez contourner cette dificulté en utilisant les champs “memberOf” dans votre schéma LDAP :

    dn: uid=foo,dmdName=people,dc=example,dc=com
    ...
    memberOf: cn=admin,dmdName=groups,dc=example,dc=com
    memberOf: cn=su,dmdName=groups,dc=example,dc=com

Ainsi au lieu d'utiliser la récupération des groupes LDAP, vous avez juste à stocker le champ “memberOf” dans vos variables exportées. With OpenLDAP, you can use the memberof overlay to do it automatically.

N'oubliez pas de créer un index sur le champ utilisé pour trouver les utilisateurs (uid par défaut)
Pour éviter de stocker les dn dans votre base de sessions, vous pouvez utiliser une macro pour réécrire memberOf :

- Variables exportées

    ldapgroups -> memberOf

Pour l'instant, ldapgroups contient “cn=admin,dmdName=groups,dc=example,dc=com cn=su,dmdName=groups,dc=example,dc=com”

- Une petite macro :

    ldapgroups -> join(" ",($ldapgroups =~ /cn=(.*?),/g))

Maintenant, ldapgroups contient “admin su”

## Performances du Manager

### Désactiver les modules inutilisés

In lemonldap-ng.ini, set only modules that you will use. By default, configuration, sessions explorer and notifications explorer are enabled. Exemple :

    [manager]
    enabledModules = conf, sessions

### Use static HTML files

Once Manager is installed, browse enabled modules (configuration, sessions, notifications) and save the web pages respectively under `manager.html`, `sessions.html` and `notifications.html` in the `DocumentRoot` directory. Then replace this in Manager file of Apache configuration:

    RewriteRule "^/$" "/psgi/manager-server.fcgi" [PT]
    # DirectoryIndex manager.html
    # RewriteCond "%{REQUEST_FILENAME}" "!\.html$"
    RewriteCond "%{REQUEST_FILENAME}" "!^/(?:static|doc|fr-doc|lib).*"
    RewriteRule "^/(.+)$" "/psgi/manager-server.fcgi/$1" [PT]

by:

    # RewriteRule "^/$" "/psgi/manager-server.fcgi" [PT]
    DirectoryIndex manager.html
    RewriteCond "%{REQUEST_FILENAME}" "!\.html$"
    RewriteCond "%{REQUEST_FILENAME}" "!^/(?:static|doc|fr-doc|lib).*"
    RewriteRule "^/(.+)$" "/psgi/manager-server.fcgi/$1" [PT]

So manager HTML templates will be no more generated by Perl but directly given by the web server.