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

# Performances

LemonLDAP::NG is designed to be very performant. In particular, it use Apache2 threads capabilities so to optimize performances, prefer using mpm-worker.

## Global performance

On linux, by default, there is no DNS cache and LemonLDAP::NG portal request DNS at every connexions on LDAP or DB. Under heavy loads, that can generated hundred of DNS queries and many errors on LDAP connexions (timed out) from IO::Socket.

To bypass this, you can:

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

## Handler performance

Handlers check rights and calculate headers for each HTTP hit. So to improve performances, avoid too complex rules by using the macro or the groups or local macros.

### Macros and groups

Macros and groups are calculated during authentication process by the portal:

- macros are used to extend (or rewrite) exported variables. A macro is stored as attributes: it can contain boolean results or any string
- groups are stored as space-separated strings in the special attribute “groups”: it contains the names of groups whose rules were returned true for the current user
- You can also get groups in `$hGroups` which is a Hash Reference of this form:

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

Example for macros:

    # boolean macro
    isAdmin -> $uid eq 'foo' or $uid eq 'bar'
    # other macro
    displayName -> $givenName." ".$surName

    # Use a boolean macro in a rule
    ^/admin -> $isAdmin
    # Use a string macro in a HTTP header
    Display-Name -> $displayName

Example for groups:

    # 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'}

Groups are computed after macros, so a group rule may involve a macro value.
Macros and groups are computed in alphanumeric order, that is, in the order they are displayed in the manager. For example, macro “macro1” will be computed before macro “macro2”: so, expression of macro2 may involve value of macro1. As same for groups: a group rule may involve another, previously computed group.

### Local macros

Macros and groups are stored in session database. Local macros is a special feature of handler that permit to have macros useable localy only. Those macros are calculated only at the first usage and stored in the local session cache (only for this server) and only if the user access to the related applications. This avoid to have to many datas stored.

    # rule
    admin -> $admin ||= ($uid eq 'foo' or $uid eq 'bar')
    # header
    Display-Name -> $displayName ||= $givenName." ".$surName

Note that this feature is interesting only for the Lemonldap::NG systems protecting a high number of applications

## Portal performances

### General performances

The portal is the biggest component of Lemonldap::NG. It is recommended to use ModPerl::Registry instead of using cgi-script as described in Apache configuration file example (portal-apache2.conf):

    <Files *.pl>
        SetHandler perl-script
        PerlResponseHandler ModPerl::Registry
    </Files>

You can also use a FastCGI server using index.fcgi given in portal examples.

In production environment for network performance, prefer using minified versions of javascript and css libs: use `make install PROD=yes`. This is done by default in RPM/DEB packages.

### Configuration access

If you set `useLocalConf` to 1 in lemonldap-ng.ini (section [Portal]), the portal will use only a cached configuration. To refresh it, you have to set an handler on the same server to use the refresh mechanism or to restart the server after each configuration change.

### Starting performances

To make the portal start faster when the server is relaunched, add those lines in Apache configuration file (as described in portal-apache2.conf):

    <Perl>
        require Lemonldap::NG::Portal::SharedConf;
        Lemonldap::NG::Portal::SharedConf->compile(
            qw(delete header cache read_from_client cookie redirect unescapeHTML));
        # Uncomment this line if you use Lemonldap::NG menu
        require Lemonldap::NG::Portal::Menu;
        # Uncomment this line if you use portal SOAP capabilities
        require SOAP::Lite;
    </Perl>

### Apache::Session performances

Lemonldap::NG handlers use a local cache to store sessions (for 10 minutes). So Apache::Session module is not a problem for handlers. It can be a brake for the portal:

1. When you use the multiple sessions restriction parameters, sessions are parsed for each authentication unless you use an Apache::Session::Browseable module.
2. Since MySQL does not have always transaction feature, Apache::Session::MySQL has been designed to use MySQL locks. Since MySQL performances are very bad using this, if you want to store sessions in a MySQL database, prefer one of the following

#### Replace MySQL by Apache::Session::Flex

In “Apache::Session module” field, set “Apache::Session::Flex” and use the following parameters:

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

Since version 1.90 of Apache::Session, you can use Apache::Session::MySQL::NoLock instead

#### Use Apache::Session::Browseable

Apache::Session::Browseable is a wrapper for other Apache::Session modules that add the capability to manage indexes. To use it (with MySQL for example), choose “Apache::Session::Browseable::MySQL” as “Apache::Session module” and use the following parameters:

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

Note that Apache::Session::Browseable::MySQL doesn't use MySQL locks.

A Apache::Session::Browseable::Redis has been created, it is the faster (except for session explorer, defeated by Apache::Session::Browseable::DBI/LDAP >= 1.0)
Some Apache::Session module are not fully usable by Lemonldap::NG such as Apache::Session::Memcached since this modules do not offer capability to browse sessions. They does not allow to use sessions explorer neither manage one-off sessions.

### LDAP performances

LDAP server can be a brake when you use LDAP groups recovery. You can avoid this by setting “memberOf” fields in your LDAP scheme:

    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

So instead of using LDAP groups recovery, you just have to store “memberOf” field in your exported variables. With OpenLDAP, you can use the memberof overlay to do it automaticaly.

Don't forget to create an index on the field used to find users (uid by default)
To avoid having group dn stored in sessions datas, you can use a macro to rewrite memberOf:

- Exported variables

    ldapgroups -> memberOf

For now, ldapgroups contains “cn=admin,dmdName=groups,dc=example,dc=com cn=su,dmdName=groups,dc=example,dc=com”

- A little macro:

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

Now ldapgroups contains “admin su”

## Manager performances

### Disable unused modules

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

    [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.