performances https://www.vincentliefooghe.net/ fr Utilisation de SLAMD pour les benchmarks LDAP https://www.vincentliefooghe.net/content/utilisation-slamd-pour-les-benchmarks-ldap <span property="dc:title" class="field field--name-title field--type-string field--label-hidden">Utilisation de SLAMD pour les benchmarks LDAP</span> <div property="content:encoded" class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><p>Lorsqu'on réalise des études comparatives sur les annuaires LDAP, il est fréquent que le client demande d'établir des tests de performances, pour s'assurer que la solution en place sera capable de répondre à ses exigences.</p> <p>Pour faire cela, j'utilisais souvent les outils <em>authrate</em> ou <em>searchrate</em> présents dans les binaires des annuaires de Forgerock ou Ping.</p> <p>Si ces outils permettent de tester de manière unitaire, et avec un certain nombre de paramètres, ils manquait certaines possibilités / fonctionnalités :</p> <ul><li>pas de possibilité de lancer plusieurs clients en parallèle, de manière synchronisée</li> <li>pas de reporting de base</li> <li>pas de réutilisation des modèles de "tirs"</li> </ul><p>Dans le cadre d'un nouveau projet d'étude, je suis tombé sur l'outil <em>SLAMD</em> disponible sur <a href="https://github.com/dirmgr/slamd">GitHub</a>.</p> <h2>Présentation de SLAMD</h2> <p>Il s'agit d'un outil écrit en Java, par un ancien employé de Sun qui travaillait sur les annuaires OpenDS notamment.</p> <p>On trouve également chez Oracle (qui a racheté Sun il y a plusieurs années), les binaires à télécharger : <a href="https://www.oracle.com/security/identity-management/technologies/slamd-downloads/">Oracle SLAMD Downloads</a></p> <p>L'outil se présente comme "<em>Distributed Load Generation Engine</em>", ce qui donne une idée de son architecture répartie. En effet, <em>SLAMD</em> est articulé autour de plusieurs composants :</p> <ul><li>un serveur, qui tourne dans un serveur Tomcat, qui permet de paramétrer les <em>jobs</em>, et construire les rapports</li> <li>un (ou plusieurs) clients, qui vont communiquer avec le serveur pour récupérer les <em>jobs</em> à traiter, et qui vont effectuer les requêtes demandées (ce sont eux qui vont vraiment faire le travail)</li> <li>un service de monitoring que l'on peut installer sur les serveurs LDAP pour remonter les informations au serveur SLAMD.</li> </ul><p>L'outil a été développé à l'origine pour remplacer / améliorer les <em>authrate</em> et autres, avec une orientation LDAP, mais peut aussi être utilisé pour d'autres protocoles réseau (http, smtp, pop,imap).</p> <h2>Utilisation</h2> <p>Une fois qu'on a récupéré les binaires ou compilé à partir de GitHub et installé les composants sur les serveurs, est de définir les <em>jobs</em> qui seront ensuite activés.</p> <p>Ceci se fait via l'option de menu "Schedule a job", dans laquelle on voit toute la richesse de l'outil.</p> <p>Pour les tests LDAP, on dispose d'une vingtaine de modèle prédéfinis, notamment :</p> <ul><li>Add and Delete : ajout et suppression, utilisé pour les tests d'écriture</li> <li>Basic Bind : connexion simple, sans recherche préalable</li> <li>Basic Search and Bind : connexion après recherche de l'utilisateur ; c'est ce que j'utilise pour tester les mécanismes d'authentification</li> <li>Comprehensive Search : possibilité de mettre plusieurs serveurs, plusieurs filtres et de préciser les attributs retournés</li> <li>Mix load : mélange de Add, Bind, Search, etc</li> </ul><h2>Paramétrage du Search + Bind</h2> <p>Dans la majorité des cas en mode <em>Authentification</em>, celle-ci se passe en 2 étapes :</p> <ul><li>on fait d'abord une recherche de l'utilisateur dans la base, via le RDN (ou un autre attribut)</li> <li>une fois le DN récupéré, on va faire une tentative de connexion avec le mot de passe.</li> </ul><p>Pour tester ceci, on va utiliser différents paramètres (en mode Basic) :</p> <ul><li>Durée du Job</li> <li>Nombre de clients (à savoir que si on n'a pas assez de clients disponibles, le job ne va pas démarrer)</li> <li>Nombre de threads par client</li> <li>Durée de montée en charge / descente de charge</li> <li>Nom et port du serveur LDAP, ainsi que la méthode de sécurité (aucune, StartTLS ou SSL)</li> <li>Bind DN et mot de passe utilisé pour la recherche (généralement, un compte de service)</li> <li>DN de base pour la recherche (par exemple : ou=Users,dc=example,dc=com)</li> <li>Périmètre de recherche (scope = subtree, single-level, base)</li> <li>Search Filter Pattern : le motif de recherche.</li> <li>Mot de passe utilisateur</li> </ul><p>Pour que cela fonctionne, on aura au préalable inséré dans l'annuaire des utilisateurs de tests, avec le même mot de passe, puisque celui-ci est donné dans la configuration.</p> <p>Le motif de recherche LDAP peut être variabilisé. Par exemple, si j'ai généré des utilisateurs avec un uid=userXXXXX (XXXXX = numérique de 1 à 99999), je peux avoir différents motifs pour mon filtre LDAP :</p> <ul><li>(uid=user[1-100000]) : recherche de user1 à user100000 de manière aléatoire</li> <li>(uid=user[1:100000]) : recherche de user1 à user100000 de manière séquentielle</li> </ul><p>Un bouton permet de tester les paramètres (connexion à l'annuaire, existence du Base DN, etc).</p> <p>Une fois le job préparé, on peut l'activer pour qu'il soit traité par les clients. Il passe alors en état "<strong>Running</strong>".</p> <p>Lorsqu'il est terminé, il passe à l'état "<strong>Completed</strong>".</p> <p>On peut dupliquer / cloner un job si on veut le relancer tel quel, ou le modifier pour changer ses paramètres.</p> <h2>Données récupérées</h2> <p>Une fois que le <em>job</em> est terminé, on peut avoir accès aux données recueillies par les clients et centralisées sur le serveur.</p> <p>Les données peuvent être affichées sous forme de graphique, directement sur le serveur, ou être générées sous forme de rapport HTML ou PDF.</p> <p>Le rapport contient pas mal d'informations par défaut :</p> <ul><li>le nom du job, sa description</li> <li>les informations de planification : durée, nombre de clients, nombre de threads</li> <li>paramètres du job</li> <li>les informations d'exécution : date de début et fin, durée, nom des machines clients</li> <li>les résultats des différentes requêtes : nombre, moyenne / seconde, moyenne / intervalle de collecte, ainsi qu'un graphe des données, et la même chose en temps de réponse.</li> <li>répartition des requêtes par statut et temps de réponse.</li> </ul><h2>Autres éléments</h2> <p>Un système de "<em>folders</em>" permet de regrouper ses différents <em>jobs</em> ce qui peut être intéressant pour gérer les séances de tests, soit par type d'annuaire si on en compare plusieurs, soit par type de tests si on fait par exemple changer le nombre de threads.</p> </div> <span rel="sioc:has_creator" class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/users/vincentl" typeof="schema:Person" property="schema:name" datatype="">vincentl</span></span> <span property="dc:date dc:created" content="2021-10-13T16:24:59+00:00" datatype="xsd:dateTime" class="field field--name-created field--type-created field--label-hidden">mer 13/10/2021 - 18:24</span> <div class="field field--name-field-categorie field--type-entity-reference field--label-above"> <div class="field__label">Catégorie</div> <div class="field__item"><a href="/cat%C3%A9gorie/autres" hreflang="fr">Autres</a></div> </div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field__label">Tag</div> <div class="field__items"> <div class="field__item"><a href="/tags/ldap" hreflang="fr">ldap</a></div> <div class="field__item"><a href="/tags/benchmark" hreflang="fr">benchmark</a></div> <div class="field__item"><a href="/tags/performances" hreflang="fr">performances</a></div> </div> </div> <section class="field field--name-comment-node-blog field--type-comment field--label-hidden comment-wrapper"> <h2 class="title comment-form__title">Ajouter un commentaire</h2> <drupal-render-placeholder callback="comment.lazy_builders:renderForm" arguments="0=node&amp;1=212&amp;2=comment_node_blog&amp;3=comment_node_blog" token="rGeZhG9defyDWatkcDCg4uVhSr1m77C8ZNq7sKOkxhE"></drupal-render-placeholder> </section> Wed, 13 Oct 2021 16:24:59 +0000 vincentl 212 at https://www.vincentliefooghe.net Optimisation du temps de démarrage Ubuntu Linux https://www.vincentliefooghe.net/content/optimisation-du-temps-d%C3%A9marrage-ubuntu-linux <span property="dc:title" class="field field--name-title field--type-string field--label-hidden">Optimisation du temps de démarrage Ubuntu Linux</span> <div property="content:encoded" class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><p>Depuis quelques temps, je trouve que le temps de démarrage de mon PC sous Ubuntu est bien long... alors que le disque principal est un SSD.</p> <h2>Identifier le temps total de démarrage</h2> <p>Sur les O.S. qui utilisent <em>systemd</em>, il existe une commande permettant de connaître le temps nécessaire au démarrage : <strong>systemd-analyze</strong>.</p> <p>Sans option, cette commande donne juste le temps total nécessaire au démarrage, ainsi que le temps après lequel on arrive à l'écran de connexion. Exemple :</p> <pre>systemd-analyze Startup finished in 8.078s (kernel) + 52.777s (userspace) = 1min 856ms graphical.target reached after 27.874s in userspace </pre><p> </p> <h2>Identifier les services les plus lents</h2> <p>La commande <strong>system-analyze</strong> utilisée avec l'option <em>blame</em> donne la liste des services en cours, triés par ordre de temps nécessaire à leur initialisation (ordre décroissant).</p> <p>Exemple :</p> <pre> systemd-analyze blame 24.810s apt-daily.service 16.382s lvm2-pvscan@8:2.service 6.372s NetworkManager-wait-online.service 5.261s plymouth-quit-wait.service 2.539s dev-sdb1.device 1.871s systemd-journal-flush.service 1.010s apt-daily-upgrade.service 929ms postfix@-.service 901ms fwupd.service 876ms grub-common.service 838ms udisks2.service 831ms lvm2-monitor.service 824ms plymouth-start.service 822ms accounts-daemon.service 784ms systemd-hwdb-update.service 769ms libvirtd.service 749ms snapd.service 707ms NetworkManager.service 638ms networking.service 627ms ModemManager.service 577ms data.mount 574ms phpsessionclean.service .../... 13ms ureadahead-stop.service 10ms systemd-update-utmp.service 10ms systemd-update-utmp-runlevel.service 7ms systemd-user-sessions.service 7ms resolvconf.service 6ms var-tmp.mount 4ms setvtrgb.service 3ms sys-kernel-config.mount 3ms postfix.service </pre><p><b>Note</b> : le temps de démarrage d'un service peut être long car il attend la fin d'un autre service.</p> <p> </p> <p>On peut utiliser l'option <em>critical-chain</em> pour identifier toute la chaine des services qui sont sur le "<em>chemin critique</em>", ce qui permet de mieux cibler les pistes d'amélioration.<br />Exemple :</p> <pre>systemd-analyze critical-chain The time after the unit is active or started is printed after the "@" character. The time the unit takes to start is printed after the "+" character. graphical.target @27.874s └─multi-user.target @27.874s └─postfix.service @27.870s +3ms └─postfix@-.service @26.939s +929ms └─network-online.target @26.938s └─NetworkManager-wait-online.service @20.565s +6.372s └─NetworkManager.service @19.850s +707ms └─dbus.service @19.796s └─basic.target @19.782s └─sockets.target @19.782s └─snapd.socket @19.756s +22ms └─sysinit.target @19.733s └─systemd-timesyncd.service @19.580s +152ms └─systemd-tmpfiles-setup.service @19.501s +73ms └─local-fs.target @19.490s └─run-user-1000-gvfs.mount @39.321s └─run-user-1000.mount @35.922s └─swap.target @2.766s └─dev-disk-by\x2duuid-4d84083a\x2d5db7\x2d4856\x2d8642\x2defa9 └─dev-disk-by\x2duuid-4d84083a\x2d5db7\x2d4856\x2d8642\x2def </pre><p>Comme l'indique la commande, le temps de démarrage du service (<em>unit</em> dans la terminologie <em>systemd</em>) est donné après le caractère '+'.<br />Dans l'exemple ci-dessus, on constate donc que l'on passe près de 8 secondes avec les services :</p> <ul><li>NetworkManager (707 ms)</li> <li>NetworkManager-wait-online (6372ms)</li> <li>postfix (932ms)</li> </ul><h2>Optimisation</h2> <p>La liste des services "<em>lents</em>" doit ensuite être analysée, en fonction du contexte. Sur mon PC personnel, je n'ai pas forcément besoin de lancer à chaque démarrage :</p> <ul><li>un serveur nginx</li> <li>les daemon libvirtd et qemu (pour des VM KVM)</li> <li>le service ModemManager (mais pourquoi donc)</li> <li>un serveur postfix</li> </ul><p>On peut donc désactiver les différents services au démarrage :</p> <pre>sudo systemctl disable nginx sudo systemctl disable libvirtd sudo systemctl disable postfix sudo systemctl disable ModemManager </pre><p>Sachant qu'on pourra toujours démarrer les services manuellement, par exemple :</p> <pre># démarrage nginx sudo systemctl start nginx </pre><p>On peut ensuite rebooter pour vérifier l'impact :</p> <pre>systemd-analyze Startup finished in 8.293s (kernel) + 27.220s (userspace) = 35.514s graphical.target reached after 26.075s in userspace </pre><p>On a gagné environ 30 secondes sur le temps de démarrage. Par contre l'écran de connexion ne s'affiche qu'une seconde plus tôt.<br />On a aussi désactivé des processus et donc potentiellement amélioré l'utilisation de la mémoire et de la CPU.</p> </div> <span rel="sioc:has_creator" class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/user/1" typeof="schema:Person" property="schema:name" datatype="">Vincent</span></span> <span property="dc:date dc:created" content="2018-10-07T13:28:22+00:00" datatype="xsd:dateTime" class="field field--name-created field--type-created field--label-hidden">dim 07/10/2018 - 15:28</span> <div class="field field--name-field-categorie field--type-entity-reference field--label-above"> <div class="field__label">Catégorie</div> <div class="field__item"><a href="/cat%C3%A9gorie/linux" hreflang="fr">Linux</a></div> </div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field__label">Tag</div> <div class="field__items"> <div class="field__item"><a href="/tags/boot" hreflang="fr">boot</a></div> <div class="field__item"><a href="/tags/performances" hreflang="fr">performances</a></div> </div> </div> <section class="field field--name-comment-node-blog field--type-comment field--label-hidden comment-wrapper"> </section> Sun, 07 Oct 2018 13:28:22 +0000 Vincent 194 at https://www.vincentliefooghe.net OpenDJ : mise en place du suivi des connexions https://www.vincentliefooghe.net/content/opendj-mise-place-du-suivi-des-connexions <span class="field field--name-title field--type-string field--label-hidden">OpenDJ : mise en place du suivi des connexions</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><p>Par défaut, il n'est pas possible de déterminer la date de dernière connexion réussie sur un annuaire LDAP (last login time). Seules les erreurs de connexion peuvent être détectées dans les politiques de mots de passe.</p> <p>Parfois cependant, il est intéressant de connaître la date de dernière connexion, afin de pouvoir supprimer - ou bloquer - des comptes inutilisés depuis plusieurs mois.</p> <p>Certains annuaire permettent de modifier les politiques de mots de passe pour tracer les connexions réussies, mais ceci a un impact sur les authentifications. En effet, à chaque authentification réussie, l'annuaire doit écrire la date de connexion sur l'objet utilisateur. On passe donc d'une suite d'opérations <em>search and bind</em> à une suite <em>search and bind and mod</em>.</p> <p>Quel est donc l'impact de ce suivi sur les performances d'un annuaire ? C'est l'objet de ce test, réalisé sur un annuaire LDAP Forgerock Opendj (DS 5.5).</p> <h2>Configuration utilisée</h2> <p>La configuration utilisée est la suivante :</p> <ul><li>2 vCPU Intel(R) Xeon(R) CPU E5-2698 v3 @ 2.30GHz</li> <li>16 Go de RAM</li> </ul><p>Le jeu de test est constitué d'un fichier LDIF de 481 Mo, comprenant 220 000 entrées utilisateur.</p> <p>Parmi ces 220 000 entrées, 50 000 sont situées dans une OU (<em>organizational unit</em>) spécifique : ou=People,ou=FR,o=example.</p> <h2>Politique de mots de passe par défaut</h2> <p>La politique de mot de passe par défaut est utilisée, avec le chargement des entrées.</p> <pre><code>Property : Value(s) ------------------------------------------:------------------------------------ account-status-notification-handler : - allow-expired-password-changes : false allow-multiple-password-values : false allow-pre-encoded-passwords : false allow-user-password-changes : true default-password-storage-scheme : Salted SHA-512 deprecated-password-storage-scheme : - expire-passwords-without-warning : false force-change-on-add : false force-change-on-reset : false grace-login-count : 0 idle-lockout-interval : 0 s java-class : org.opends.server.core.PasswordPolicyFactory last-login-time-attribute : - last-login-time-format : - lockout-duration : 0 s lockout-failure-count : 0 lockout-failure-expiration-interval : 0 s max-password-age : 25 w 5 d max-password-reset-age : 0 s min-password-age : 0 s password-attribute : userPassword password-change-requires-current-password : false password-expiration-warning-interval : 5 d password-generator : Random Password Generator password-history-count : 5 password-history-duration : 0 s password-validator : Length-Based Password Validator previous-last-login-time-format : - require-change-by-time : - require-secure-authentication : false require-secure-password-changes : false skip-validation-for-administrators : false state-update-failure-policy : reactive </code></pre><h2>Outils de benchmark</h2> <p>Les tests sont lancés avec les utilitaires <em>authrate</em> et <em>searchrate</em>, qui sont intégrés aux binaires de l'annuaire.</p> <p>Pour la recherche :</p> <p><style type="text/css"> <!--/*--><![CDATA[/* ><!--*/ <!--/*--><![CDATA[/* ><!--*/ p, li { white-space: pre-wrap; } /*--><!]]]]><![CDATA[>*/ /*--><!]]>*/ </style></p> <pre style="margin: 0px; text-indent: 0px;">/opt/opendj/bin/searchrate -h 10.150.29.161 -p 1389 -D 'uid=user.1,ou=people,ou=fr,o=example' -w password -F -c 10 -b o=example -m 300000 -g 'rand(100,49000)' '(uid=user.%d)'</pre><p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"> </p> <p>Pour les authentifications, en mode search + bind :</p> <pre><code>/opt/opendj/bin/authrate -h 10.150.29.161 -p 1389 -D '%2$s' -w password -f -c 10 -b ou=people,ou=fr,o=example -s sub -m 300000 -g 'rand(100,49000)' '(uid=user.%d)' </code></pre><h2>Procédure de tests</h2> <p>La procédure de tests est la suivante :</p> <ul><li>démarrage de l'annuaire</li> <li>lancement d'un premier test de type <em>searchrate</em>, qui permet de cacher les entrées en RAM</li> <li>lancement d'un test d'authentification avec <em>authrate</em> en mode search + bind</li> </ul><h2>Mesures sans suivi de la date de dernière connexion</h2> <p>Avec le paramétrage par défaut, on obtient un débit moyen de 4283 authentifications par seconde, avec un temps de réponse moyen de 2.131 millisecondes.</p> <pre><code>------------------------------------------------------------------------------ Throughput Response Time (ops/second) (milliseconds) recent average recent average 99.9% 99.99% 99.999% err/sec bind time % ------------------------------------------------------------------------------ 3901.6 3907.1 2.573 2.573 25.304 162.729 167.620 0.0 44.4 4186.4 4047.8 2.372 2.469 26.546 166.949 195.819 0.0 46.6 4540.4 4212.9 2.183 2.365 23.388 166.223 195.819 0.0 44.2 4624.0 4315.7 2.147 2.307 22.435 162.729 195.819 0.0 42.6 4609.7 4374.6 2.156 2.275 22.083 160.540 172.100 0.0 43.0 4663.1 4422.7 2.130 2.250 21.634 158.399 172.100 0.0 42.5 4765.9 4471.7 2.088 2.225 21.431 154.617 172.100 0.0 42.8 4764.9 4508.4 2.089 2.207 20.982 141.395 172.100 0.0 42.0 4864.1 4547.9 2.050 2.188 21.024 39.778 169.393 0.0 42.2 4811.6 4574.2 2.077 2.177 20.934 34.832 169.393 0.0 42.0 4777.0 4592.6 2.091 2.169 20.525 32.932 169.393 0.0 41.8 4825.5 4611.9 2.072 2.160 20.090 32.724 169.393 0.0 41.9 4101.4 4572.6 1.898 2.142 19.807 32.213 169.393 0.0 41.7 530.8 4283.0 0.869 2.131 19.703 32.118 167.620 0.0 41.0 </code></pre><p>La CPU est utilisée à 90 % environ sur le serveur cible (qui dispose de 2 vCPU).</p> <h2>Mise en place du suivi du <em>last login time</em></h2> <h3>Création d'un attribut spécifique</h3> <p>La mise en place du suivi demande tout d'abord de créer un attribut qui sera utilisé pour stocker la date de dernière connexion. La documentation donne justement un exemple de politique de mots de passe qui met en oeuvre le suivi.</p> <pre><code>dn: cn=schema changetype: modify add: attributeTypes attributeTypes: ( lastLoginTime-oid NAME 'lastLoginTime' DESC 'Last time the user logged in' EQUALITY generalizedTimeMatch ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation X-ORIGIN 'OpenDJ example documentation' ) </code></pre><p>On ajoute l'attribut au schéma via la commande <em>ldapmodify</em> :</p> <pre><code>ldapmodify \ --hostname localhost \ --port 1389 \ --bindDN "cn=Directory Manager" \ --bindPassword password \ lastLoginTime.ldif </code></pre><h3>Création d'une politique de mots de passe spécifique</h3> <p>Si on veut cibler certains comptes utilisateurs, on peut créer une politique de mots de passe spécifiquement pour cet usage :</p> <pre><code>/opt/opendj/bin/dsconfig \ create-password-policy \ --hostname localhost --port 4444 \ --bindDN "cn=Directory Manager" \ --bindPassword password \ --policy-name "Track Last Login Time" \ --type password-policy \ --set default-password-storage-scheme:"Salted SHA-512" \ --set password-attribute:userPassword \ --set last-login-time-attribute:lastLoginTime \ --set last-login-time-format:"yyyyMMddHH'Z'" \ --trustAll \ --no-prompt </code></pre><h3>Modification de la politique de mots de passe</h3> <p>On peut créer une nouvelle politique de mots de passe, ou modifier la politique existante. Dans ce cas, la commande à utiliser est la suivante :</p> <pre><code>/opt/opendj/bin/dsconfig set-password-policy-prop \ --policy-name Default\ Password\ Policy \ --set last-login-time-attribute:lastLoginTime \ --set last-login-time-format:"yyyyMMddHH'Z'" \ --hostname localhost \ --port 4444 \ --bindDn cn=Directory\ Manager \ --bindPassword password \ --trustAll \ --no-prompt </code></pre><h2>Test sur une entrée</h2> <p>Si on fait une requête avec un utilisateur en se connectant, on peut ensuite récupérer la date de dernière connexion sur son entrée, à condition de disposer des droits adéquats.</p> <p>Par exemple :</p> <pre><code>ldapsearch -x -h localhost -p 1389 -D 'cn=Directory Manager' -w password -b o=example '(uid=user.2)' lastLoginTime dn: uid=user.2,ou=People,ou=FR,o=example lastLoginTime: 2017121909Z </code></pre><p>On constate que la date est bien au format déclaré, c'est à dire comprenant l'année, le mois, le jour et l'heure. En effet, il n'est pas nécessaire de suivre les connexions à la minute près.</p> <h2>Mesures AVEC suivi de la date de dernière connexion</h2> <p>Avec le nouveau paramétrage, incluant la mise à jour de la dernière date de connexion, on obtient un débit maximum de 2860 authentifications par seconde en moyenne, avec un temps de réponse moyen de 3.382 millisecondes.</p> <p>La charge CPU sur le serveur d'annuaire oscille entre 50 et 95%, avec des I/O wait.</p> <p>On a bien un impact assez fort, avec notamment des phases pendant laquelle l'annuaire est en I/O wait, révélateur des mises à jour effectuées sur les entrées.</p> <pre><code>------------------------------------------------------------------------------ Throughput Response Time (ops/second) (milliseconds) recent average recent average 99.9% 99.99% 99.999% err/sec bind time % ------------------------------------------------------------------------------ 1570.3 1573.1 6.421 6.421 152.833 177.026 177.026 0.0 63.6 2308.4 1942.2 4.325 5.170 53.701 176.974 177.026 0.0 57.0 2479.4 2122.0 4.023 4.722 49.889 165.267 177.026 0.0 53.3 1025.2 1847.4 3.712 4.581 48.670 165.267 177.026 0.0 51.6 0.0 1477.0 - 4.581 48.670 165.267 177.026 0.0 NaN 1013.4 1399.8 25.871 7.149 50.589 11195.648 11204.023 0.0 93.5 2996.8 1627.5 3.332 6.147 46.142 11193.992 11204.023 0.0 49.8 3301.1 1836.1 3.028 5.447 44.262 11187.622 11204.023 0.0 48.4 3329.9 2001.8 2.737 4.948 41.735 11165.580 11204.023 0.0 47.0 0.0 1800.9 - 4.948 41.735 11165.580 11204.023 0.0 NaN 92.4 1645.4 226.166 6.078 43.042 11156.315 11204.023 0.0 99.2 4024.9 1843.1 2.485 5.426 39.488 10339.090 11203.705 0.0 45.4 4193.7 2023.6 2.382 4.942 38.478 10328.566 11203.705 0.0 44.3 4487.2 2199.3 2.227 4.547 36.814 10316.059 11203.705 0.0 43.1 4496.0 2352.3 2.222 4.251 35.540 10313.618 11203.705 0.0 43.3 4530.5 2488.3 2.207 4.018 34.530 10213.330 11203.705 0.0 43.0 4535.5 2608.8 2.204 3.833 33.649 168.792 11202.112 0.0 43.3 4479.8 2712.7 2.230 3.686 33.112 163.941 11202.112 0.0 42.7 4722.0 2818.5 2.116 3.547 32.285 160.038 11202.112 0.0 42.6 4710.9 2913.1 2.108 3.431 31.666 79.285 11202.112 0.0 42.5 1816.5 2860.5 1.834 3.382 31.418 75.221 11195.866 0.0 42.9 </code></pre><p><em>Note</em> : ceci est cependant à modérer, puisque notre première campagne de tir va déclencher une écriture pour chaque utilisateur qui s'authentifie. Si on relance un deuxième tir dans l'heure (qui est l'unité minimale de suivi de la date de connexion), on retrouve des résultats quasiment identiques au premier cas : un débit de 4291 authentifications par seconde, et un temps de réponse de 2.195 ms. Si on regarde la charge sur le serveur d'annuaire, on ne constate plus d'écritures sur disque.</p> <pre><code>------------------------------------------------------------------------------ Throughput Response Time (ops/second) (milliseconds) recent average recent average 99.9% 99.99% 99.999% err/sec bind time % ------------------------------------------------------------------------------ 3988.3 3994.8 2.514 2.514 23.066 163.522 167.640 0.0 42.6 .../... 4628.0 4525.7 2.159 2.206 18.978 28.433 158.819 0.0 42.9 4327.2 4510.4 2.219 2.207 19.051 28.221 158.819 0.0 43.0 1450.9 4291.0 1.721 2.195 18.968 28.071 158.406 0.0 42.1 </code></pre><h2>Conclusion</h2> <p>Si l'impact du suivi de la date de dernière connexion n'est pas anodin, surtout dans le cas d'un test, en situation réelle, l'impact peut être relativement négligeable, notamment si les authentifications se font au fil de l'eau.</p> </div> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/users/vincentl" typeof="schema:Person" property="schema:name" datatype="">vincentl</span></span> <span class="field field--name-created field--type-created field--label-hidden">mar 19/12/2017 - 10:42</span> <div class="field field--name-field-categorie field--type-entity-reference field--label-above"> <div class="field__label">Catégorie</div> <div class="field__item"><a href="/cat%C3%A9gorie/iam" hreflang="fr">IAM</a></div> </div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field__label">Tag</div> <div class="field__items"> <div class="field__item"><a href="/tags/forgerock" hreflang="fr">forgerock</a></div> <div class="field__item"><a href="/tags/opendj" hreflang="fr">opendj</a></div> <div class="field__item"><a href="/tags/ldap" hreflang="fr">ldap</a></div> <div class="field__item"><a href="/tags/performances" hreflang="fr">performances</a></div> </div> </div> <section class="field field--name-comment-node-book field--type-comment field--label-hidden comment-wrapper"> </section> Tue, 19 Dec 2017 09:42:42 +0000 vincentl 187 at https://www.vincentliefooghe.net https://www.vincentliefooghe.net/content/opendj-mise-place-du-suivi-des-connexions#comments OpenIDM : purge des tables audit https://www.vincentliefooghe.net/content/openidm-purge-des-tables-audit <span class="field field--name-title field--type-string field--label-hidden">OpenIDM : purge des tables audit </span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><h2>Contexte</h2> <p>Dans un environnement client OpenIDM 3.1 en production depuis plusieurs mois, l'accès à l'écran d'administration des mappings met de plus en plus longtemps à s'afficher.</p> <h3>English Summary</h3> <p>It may help : if the access time to mapping administration form in OpenIDM becomes very slow, then check the numbers of lines in <em>auditrecon</em> table, and delete old records.</p> <h2>Analyse du problème</h2> <p>En regardant les échanges avec le serveur (via la console du navigateur), on voit que l'URL "endpoint/mappingDetails" est celle qui prend le plus de temps.<br />Ce endpoint appelle un script Javascript, <code>./bin/defaults/script/ui/mappingDetails.js</code>, qui lance une requête SQL permettant de récupérer la date de dernière réconciliation, et ce pour chaque <em>mapping</em> :</p> <pre> lastRecon = openidm.query("audit/recon", { "_queryId": "audit-last-recon-for-mapping", "mapping": m.name, "formatted": false }); </pre><p>En regardant dans le fichier <code>conf/repo.jdbc.json</code>, on peut récupérer le détail de la requête :</p> <pre>audit-last-recon-for-mapping" : "SELECT * FROM ${_dbSchema}.auditrecon WHERE entryType = 'start' AND mapping = ${mapping} and reconaction &lt;&gt; 'reconById' ORDER BY activitydate DESC LIMIT 1" </pre><p>C'est cette requête qui pose problème, notamment car la table <em>auditrecon</em> n'a jamais été purgée.</p> <p>Si on regarde le nombre de lignes par type de <em>mapping</em>, on peut avoir une idée de la volumétrie :</p> <pre>select mapping, count(1) from auditrecon group by mapping ; +-------------------------------------+----------+ | mapping | count(1) | +-------------------------------------+----------+ | AdOrganizationalUnit_Officelocation | 3956 | | ldapFunctionnal_Orga | 482874 | +-------------------------------------+----------+ 2 rows in set (3.36 sec) </pre><p>On peut alors tester la requête lancée par le script <code>mappingDetails.js</code> :</p> <pre>SELECT * FROM auditrecon WHERE entryType = 'start' AND mapping = 'ldapFunctionnal_Orga' and reconaction &lt;&gt; 'reconById' ORDER BY activitydate DESC LIMIT 1 ; </pre><p>Le nombre élevé s'explique car il s'agit d'une réconciliation lancée à intervalle régulier (toutes les 15 minutes), pour récupérer des objets de type 'organisation' : départements, fonctions, sections.<br />De ce fait, on arrive rapidement à un nombre élevé de lignes, sachant que chaque réconciliation traite près de 500 lignes, soit 4*24*500 = 48 000 lignes par jour !</p> <p>On peut tenter d'en savoir un peu plus sur la volumétrie. Pour avoir la taille des tables :</p> <pre>SELECT table_name, table_rows as 'Rows #', data_length /1024 as 'Data size KB', index_length/1024 as 'Index size KB' , round( (data_length + index_length) / 1024 / 1024,2 ) as 'Taille MB' FROM information_schema.tables WHERE table_schema = 'openidm' AND table_name like 'audit%'; +---------------+--------+--------------+---------------+-----------+ | table_name | Rows # | Data size KB | Index size KB | Taille MB | +---------------+--------+--------------+---------------+-----------+ | auditaccess | 6153 | 2080.0000 | 2144.0000 | 4.13 | | auditactivity | 843 | 22544.0000 | 1056.0000 | 23.05 | | auditrecon | 449959 | 541952.0000 | 592448.0000 | 1107.81 | | auditsync | 797 | 7696.0000 | 0.0000 | 7.52 | +---------------+--------+--------------+---------------+-----------+ 4 rows in set (0.15 sec) </pre><p><strong>Note</strong> : s'agissant de tables utilisant le moteur InnoDB, le nombre de lignes donnés par cette requête peut varier. Il vaut mieux utiliser un SELECT COUNT pour avoir le nombre réel de lignes. La volumétrie en KB, par contre, semble stable.</p> <h2>Epuration des tables d'audit</h2> <p>Il existe une tâche programmée qui permet de lancer un nettoyage régulier des tables d'audit. Sur une installation OpenIDM 3.1, le fichier de définition se trouve dans <code>samples/schedules/schedule-autoPurgeAuditRecon.json</code> :</p> <pre>{ "enabled" : false, "type" : "cron", "schedule" : "0 0 */12 * * ?", "persisted" : true, "misfirePolicy" : "doNothing", "invokeService" : "script", "invokeContext" : { "script" : { "type" : "text/javascript", "file" : "audit/autoPurgeAuditRecon.js", "input" : { "mappings" : [ "%" ], "purgeType" : "purgeByNumOfReconsToKeep", "numOfRecons" : 1, "intervalUnit" : "minutes", "intervalValue" : 1 } } } } </pre><p>Dans la configuration par défaut, on limite à un nombre fini de réconciliations. Si on veut garder un nombre de jours limité, il faut modifier la définition pour utiliser le type de purge <em>purgeByExpired</em> :</p> <pre>{ "enabled" : true, "type" : "cron", "schedule" : "0 0 22 * * ?", "persisted" : true, "misfirePolicy" : "doNothing", "invokeService" : "script", "invokeContext" : { "script" : { "type" : "text/javascript", "file" : "audit/autoPurgeAuditRecon.js", "input" : { "mappings" : [ "%" ], "purgeType" : "purgeByExpired", "numOfRecons" : 1, "intervalUnit" : "days", "intervalValue" : 30 } } } } </pre><p>Le souci étant dans ce cas que, puisqu'on n'a jamais lancé de purge, la requête tombe en time-out...</p> <p>Dans ce cas, On peut aussi utiliser une méthode plus radicale, consistant à supprimer les lignes dans la table, de la manière suivante :</p> <pre>DELETE FROM auditaccess WHERE activitydate &lt; 'YYYY-MM-DD' ; </pre><p>On peut générer les instructions avec un script shell, qui va calculer la date (ce qui est plus rapide que d'utiliser les fonctions MySQL) :</p> <pre>#!/bin/bash # ----------------------------- # Purge OpenIDM audit database # ----------------------------- # # Please stop openidm first, and there remove felix-cache content before restarting #----------------------------------------------------------------------------------- # Set data retention period here LongTimeAgo=$(date -d 'now -6 months' +'%Y-%m-%d') echo "DELETE FROM auditaccess WHERE activitydate &lt; '$LongTimeAgo' ;" &gt; /tmp/purge.sql echo "DELETE FROM auditactivity WHERE activitydate &lt; '$LongTimeAgo' ;" &gt;&gt; /tmp/purge.sql echo "DELETE FROM auditrecon WHERE activitydate &lt; '$LongTimeAgo' ;" &gt;&gt; /tmp/purge.sql echo "DELETE FROM auditsync WHERE activitydate &lt; '$LongTimeAgo' ;" &gt;&gt; /tmp/purge.sql # Ou utiliser la commande mysql en ligne echo "SELECT table_name, data_length /1024 AS 'Data size KB', index_length/1024 AS 'Index size KB' , round( (data_length + index_length) / 1024 / 1024,2 ) AS 'Taille MB' FROM information_schema.tables WHERE table_schema = 'openidm' and table_name like 'audit%'; " &gt;&gt; /tmp/purge.sql echo "exit" &gt;&gt; /tmp/purge.sql SQLUSER=openidm SQLPWD=openidm SQLDB=openidm DBHOST=db.mydomain.com DBPORT=3306 mysql -h ${DBHOST} -P ${DBPORT} -u ${SQLUSER} -p${SQLPWD} ${SQLDB} &lt; /tmp/purge.sql # # --- End of script # </pre><p>Il ne reste plus qu'à lancer le script shell, de manière réguliere (une fois par semaine par exemple), pour limiter le nombre de lignes dans la table, et retrouver un temps de réponse correct lorsqu'on passe par l'écran de gestion des <em>mappings</em></p> <h2>En conclusion</h2> <p>Si l'accès à la page <em>Mappings</em> de la console d'administration OpenIDM est de plus en plus long, vérifier le nombre de lignes dans la table <em>auditrecon</em>, et lancer régulièrement une purge de cette table, soit via le <em>schedule-autoPurgeAuditRecon</em>, soit directement en SQL.</p> </div> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/users/vincentl" typeof="schema:Person" property="schema:name" datatype="">vincentl</span></span> <span class="field field--name-created field--type-created field--label-hidden">mer 14/12/2016 - 09:31</span> <div class="field field--name-field-categorie field--type-entity-reference field--label-above"> <div class="field__label">Catégorie</div> <div class="field__item"><a href="/cat%C3%A9gorie/iam" hreflang="fr">IAM</a></div> </div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field__label">Tag</div> <div class="field__items"> <div class="field__item"><a href="/taxonomy/term/3" hreflang="fr">openidm</a></div> <div class="field__item"><a href="/tags/forgerock" hreflang="fr">forgerock</a></div> <div class="field__item"><a href="/tags/audit" hreflang="fr">audit</a></div> <div class="field__item"><a href="/tags/performances" hreflang="fr">performances</a></div> </div> </div> <section class="field field--name-comment-node-book field--type-comment field--label-hidden comment-wrapper"> </section> Wed, 14 Dec 2016 08:31:54 +0000 vincentl 171 at https://www.vincentliefooghe.net https://www.vincentliefooghe.net/content/openidm-purge-des-tables-audit#comments OpenIDM : réduire les logs du scheduler https://www.vincentliefooghe.net/content/openidm-r%C3%A9duire-les-logs-du-scheduler <span class="field field--name-title field--type-string field--label-hidden">OpenIDM : réduire les logs du scheduler</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item">Chez un client, nous avons activé le niveau de log à INFO par défaut afin d'avoir des traces des opérations, notamment car on travaille sur la base d'un changelog depuis un annuaire LDAP Sun, avec un polling toutes les 10 secondes. Plusieurs providers sont ainsi déclenchés : l'un pour les utilisateurs du LDAP, un autre pour les groupes, et encore un pour les groupes AD.Ceci a pour effet de bord de remplir les logs d'informations peu utiles, du genre : Nov 22, 2016 5:36:00 PM org.forgerock.openidm.util.LogUtil logAtLevel INFO: Scheduled service "scheduler-service-group.AD" found, invoking. Nov 22, 2016 5:36:00 PM org.forgerock.openidm.util.LogUtil logAtLevel INFO: Scheduled service "scheduler-service-group.DSEE-LDAP" found, invoking. Nov 22, 2016 5:36:00 PM org.forgerock.openidm.util.LogUtil logAtLevel INFO: Scheduled service "scheduler-service-group.DSEE-LDAP" invoke completed successfully. Nov 22, 2016 5:36:00 PM org.forgerock.openidm.util.LogUtil logAtLevel INFO: Scheduled service "scheduler-service-group.AD" invoke completed successfully. Nov 22, 2016 5:36:10 PM org.forgerock.openidm.util.LogUtil logAtLevel INFO: Scheduled service "scheduler-service-group.AD" found, invoking. Nov 22, 2016 5:36:10 PM org.forgerock.openidm.util.LogUtil logAtLevel INFO: Scheduled service "scheduler-service-group.DSEE-LDAP" found, invoking. Nov 22, 2016 5:36:10 PM org.forgerock.openidm.util.LogUtil logAtLevel INFO: Scheduled service "scheduler-service-group.DSEE-LDAP" invoke completed successfully. Nov 22, 2016 5:36:10 PM org.forgerock.openidm.util.LogUtil logAtLevel INFO: Scheduled service "scheduler-service-group.AD" invoke completed successfully. Dans le fichier logging.properties, il n'y a pas moyen de spécifier le niveau de log pour le scheduler. En fait, ceci se fait directement dans le fichier de configuration du scheduler, en ajoutant l'option <strong>"invokeLogLevel" : "debug"</strong>Par exemple : { "enabled" : true, "type" : "cron", "persisted" : true, "misfirePolicy" : "fireAndProceed", "schedule" : "0/10 * * * * ?", "concurrentExecution" : false, "invokeService" : "provisioner", "invokeContext" : { "action" : "liveSync", "source" : "system/DSEE/user" }, "invokeLogLevel" : "debug" } Du coup, on gagne en lisibilité dans les logs, et on épargne de l'espace disque, tout en pouvant garder un historique un peu plus long.L'option est présente dans la documentation (Integrator's guide). Mais comme elle n'est pas intégrée dans le fichier <em>logging.properties</em>, elle n'est pas forcément facile à trouver. </div> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/users/vincentl" typeof="schema:Person" property="schema:name" datatype="">vincentl</span></span> <span class="field field--name-created field--type-created field--label-hidden">mar 22/11/2016 - 17:52</span> <div class="field field--name-field-categorie field--type-entity-reference field--label-above"> <div class="field__label">Catégorie</div> <div class="field__item"><a href="/cat%C3%A9gorie/iam" hreflang="fr">IAM</a></div> </div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field__label">Tag</div> <div class="field__items"> <div class="field__item"><a href="/taxonomy/term/3" hreflang="fr">openidm</a></div> <div class="field__item"><a href="/tags/performances" hreflang="fr">performances</a></div> </div> </div> <section class="field field--name-comment-node-book field--type-comment field--label-hidden comment-wrapper"> </section> Tue, 22 Nov 2016 16:52:28 +0000 vincentl 168 at https://www.vincentliefooghe.net https://www.vincentliefooghe.net/content/openidm-r%C3%A9duire-les-logs-du-scheduler#comments Tuning OpenLDAP avec DB_CONFIG https://www.vincentliefooghe.net/content/tuning-openldap-avec-dbconfig <span class="field field--name-title field--type-string field--label-hidden">Tuning OpenLDAP avec DB_CONFIG</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><p><em>Afin d'améliorer les performances de OpenLDAP, il est recommandé de pouvoir utiliser le plus de cache possible pour monter en mémoire les données OpenLDAP. </em></p> <p>Ceci se fait via les réglagles du fichier <strong>DB_CONFIG</strong>, qui se trouve dans le répertoire contenant les données de l'annuaire, et qui permet de paramétrer la base de données Berkeley, utilisée comme <em>back-end </em>de stockage par OpenLDAP.<br />Par défaut, il n'y a pas de fichier DB_CONFIG créé. Par contre on peut trouver un exemple dans <code>/usr/share/openldap-servers/DB_CONFIG.example</code> :</p> <pre># $OpenLDAP$ # Example DB_CONFIG file for use with slapd(8) BDB/HDB databases. # # See the Oracle Berkeley DB documentation # <http: berkeley-db="" db="" db_config.html="" documentation="" env="" ref="" technology="" www.oracle.com=""> # for detail description of DB_CONFIG syntax and semantics. # # Hints can also be found in the OpenLDAP Software FAQ # <http: faq="" file="2" www.openldap.org=""> # in particular: # <http: faq="" file="1075" www.openldap.org=""> # Note: most DB_CONFIG settings will take effect only upon rebuilding # the DB environment. # one 0.25 GB cache set_cachesize 0 268435456 1 # Data Directory #set_data_dir db # Transaction Log settings set_lg_regionmax 262144 set_lg_bsize 2097152 #set_lg_dir logs # Note: special DB_CONFIG flags are no longer needed for "quick" # slapadd(8) or slapindex(8) access (see their -q option). </http:></http:></http:></pre><p> </p> <p>Un exemple d'un "vrai" fichier DB_CONFIG :</p> <pre># # DB_CONFIG # # Database size : 2.0 GB # # The optimal database cache size "is just the size of the (dn2id.bdb + id2entry.bdb) file, plus about 10% for growth." # http://www.openldap.org/doc/admin24/tuning.html (OpenLDAP AdminGuide) # # if id2entry.bdb is 700 MB and and dn2id.bdb is 50MB, then size should be (700 + 50)*1,1 = 825 MB at least # One cache of 1.0 GB set_cachesize 1 0 1 # Data Directory #set_data_dir db # Transaction Log settings set_lg_regionmax 262144 set_lg_bsize 2097152 set_lg_max 8388608 set_flags DB_LOG_AUTOREMOVE set_lg_dir /data/logs/ldap-transactions # Note: special DB_CONFIG flags are no longer needed for "quick" # slapadd(8) or slapindex(8) access (see their -q option). set_lk_max_locks 4000 set_lk_max_lockers 200 set_lk_max_objects 2000 </pre><h2>Variables du fichier DB_CONFIG</h2> <p>On peut identifier les variables intéressantes :</p> <ul><li>set_cachesize : la taille du cache (GB BYTES #de segments)</li> <li>set_lg-regionmax : taille maximale en mémoire pour cacher les noms de fichier de database</li> <li>set_lg_bsize : taille de la mémoire cache pour les informations de log</li> <li>set_lg_max : taille maximale des fichiers de logs de transaction. Au moins 4 fois la taille de set_lg_bsize. Une rotation de fichier sera déclenchée lorsque le log aura atteint cette taille</li> <li>set_lg_dir : permet de préciser le répertoire où l'on va stocker les fichiers de logs. Il est recommandé (pour des raisons de sécurité) de ne pas les mettre au même endroit que les données</li> <li>set_flags : DB_LOG_AUTOREMOVE (signifie que les logs seront supprimés lorsqu'ils sont inutiles)</li> </ul><p>On trouve ensuite la configuration concernant les <em>locks</em> (verrous)</p> <ul><li>set_lk_max_locks : nombre maximal de locks</li> <li>set_lk_max_lockers : nombre de gestionnaire de verrous</li> <li>set_lk_max_objects : nombre maximal d'objets "lockés"</li> </ul><p><strong>Note</strong> : si on modifie les valeurs dans le fichier DB_CONFIG, il faut ensuite relancer une commande <strong>db_recover</strong> pour que la base Berkeley DB prenne en compte les modifications, après avoir arrêté l'annuaire :</p> <pre>service slapd stop db_recover -h /product/openldap/data/mydomain-fr service slapd start </pre><h2>Paramétrage au niveau Root Suffix</h2> <p>Il faut aussi modifier le paramètre <strong>olcDbCacheSize</strong> dans le fichier de configuration du rootSuffix.<br />Ce paramètre doit être égal aux nombre d'entrées de l'annuaire + 10%.</p> <p>Le paramètre <strong>olcDbIDLcacheSize</strong> peut également être positionné. Il s'agit du cache pour les index.</p> <p>Le guide d'administration OpenLDAP stipule "une taille égale à trois fois la taille du cache des entrées est un bon point de départ".<br />Par exemple :</p> <pre>olcDbCacheSize: 100000 olcDbIDLcacheSize : 300000 olcDbLinearIndex: FALSE olcDbMode: 0600 olcDbSearchStack: 16 olcDbShmKey: 0 olcDbCacheFree: 1 olcDbDNcacheSize: 0 </pre><h2>Calcul de la taille du cache</h2> <p>La taille du cache (paramètre <strong>set_cachesize</strong>) doit être égale à la taille des fichiers bdb utilisés par l'instance. On peut les calculer de la manière suivante :</p> <pre>cd /product/openldap/data/mydomain-fr du -c -h *.bdb </pre><h2>Positionnement du nombre de locks</h2> <p>Pour vérifier le nombre de locks, on peut utiliser les commandes <strong>db_stat</strong></p> <pre>db_stat -c -h /product/openldap/data/mydomain-fr | head -20 149 Last allocated locker ID 0x7fffffff Current maximum unused locker ID 9 Number of lock modes 10000 Maximum number of locks possible 1000 Maximum number of lockers possible 10000 Maximum number of lock objects possible 20 Number of lock object partitions 7 Number of current locks 3661 Maximum number of locks at any one time 20 Maximum number of locks in any one bucket 0 Maximum number of locks stolen by for an empty partition 0 Maximum number of locks stolen for any one partition 34 Number of current lockers 90 Maximum number of lockers at any one time 7 Number of current lock objects 1862 Maximum number of lock objects at any one time </pre><p>On récupère donc les valeurs pour les locks, lockers et objects (<em>Maximum number of XXX at any time</em>), ce qui donne une indication pour le paramétrage dans le fichier DB_CONFIG.</p> <p> </p> </div> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/users/vincentl" typeof="schema:Person" property="schema:name" datatype="">vincentl</span></span> <span class="field field--name-created field--type-created field--label-hidden">jeu 13/10/2016 - 12:57</span> <div class="field field--name-field-categorie field--type-entity-reference field--label-above"> <div class="field__label">Catégorie</div> <div class="field__item"><a href="/cat%C3%A9gorie/iam" hreflang="fr">IAM</a></div> </div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field__label">Tag</div> <div class="field__items"> <div class="field__item"><a href="/tags/openldap" hreflang="fr">openldap</a></div> <div class="field__item"><a href="/tags/performances" hreflang="fr">performances</a></div> <div class="field__item"><a href="/tags/ldap" hreflang="fr">ldap</a></div> </div> </div> <section class="field field--name-comment-node-book field--type-comment field--label-hidden comment-wrapper"> </section> Thu, 13 Oct 2016 10:57:49 +0000 vincentl 164 at https://www.vincentliefooghe.net Influence du paramétrage APC sur les performances Drupal https://www.vincentliefooghe.net/content/influence-du-param%C3%A9trage-apc-sur-les-performances-drupal <span class="field field--name-title field--type-string field--label-hidden">Influence du paramétrage APC sur les performances Drupal</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><p>Avec une version PHP inférieure à 5.5 il est recommandé d'utiliser un cache d'OpCode. Ce cache permet d'améliorer les performances de PHP, en mettant en cache le code PHP une fois qu'il a été analysé.</p> <p>L'un des caches les plus utilisés est <a href="http://php.net/manual/en/book.apc.php">APC</a>. Son installation sur une distribution type Debian consiste simplement en une commande</p> <pre>apt-get install php-apc</pre><p>Par défaut, la taille mémoire réservée est de 32 Mo.</p> <p><strong>Si cette taille n'est pas optimale, les performances peuvent être dégradées au lieu d'être améliorées</strong>. En effet, on a alors un phénomène de saturation du cache, de fragmentation, et le code doit passer par des phases de check / miss / insert.</p> <p>Pour nos tests, nous réalisons une première séance de tirs avec l'outil <a href="http://www.joedog.org/siege-home/">siege</a>, pendant 2 minutes, sur une liste de 200 urls (les contenus ont été générés par le module <em>Devel generate</em>).</p> <h2>Résultats sans APC</h2> <pre>Transactions: 770 hits Availability: 100.00 % Elapsed time: 119.15 secs Data transferred: 3.97 MB Response time: 3.81 secs Transaction rate: 6.46 trans/sec Throughput: 0.03 MB/sec Concurrency: 24.63 Successful transactions: 766 Failed transactions: 0 Longest transaction: 4.65 Shortest transaction: 0.55 </pre><p>Typiquement, sans Cache d'OpCode et sans cache Drupal, les performances sont assez faibles.</p> <h2>Résultats avec 16 Mo</h2> <p>Le résultat de la commande siege est :</p> <pre>Transactions: 2928 hits Availability: 100.00 % Elapsed time: 119.51 secs Data transferred: 14.98 MB Response time: 1.02 secs Transaction rate: 24.50 trans/sec Throughput: 0.13 MB/sec Concurrency: 24.89 Successful transactions: 2917 Failed transactions: 0 Longest transaction: 2.78 Shortest transaction: 0.55 </pre><p>Sur cette VM de test, on obtient 24 transactions par secondes, sans cache drupal activé. On constate que la taille mémoire utilisée par le cache est de 15 Mo environ. Par rapport à la configuration sans le cache APC, on augmente les performances d'un rapport 4 environ.</p> <p>La consommation mémoire APC est la suivante :</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/drupal-S%C3%A9lection_001.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;drupal-Sélection_001.png&quot;}" role="button" title="drupal-Sélection_001.png" data-colorbox-gallery="gallery-all-EKd_tqs2qn8" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;drupal-Sélection_001.png&quot;}"><img src="/sites/default/files/styles/large/public/drupal-S%C3%A9lection_001.png?itok=YMbLje5e" width="480" height="259" alt="drupal-Sélection_001.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <h2>Résultats avec 12 Mo</h2> <pre>Transactions: 784 hits Availability: 99.87 % Elapsed time: 119.73 secs Data transferred: 3.99 MB Response time: 3.75 secs Transaction rate: 6.55 trans/sec Throughput: 0.03 MB/sec Concurrency: 24.58 Successful transactions: 778 Failed transactions: 1 Longest transaction: 4.42 Shortest transaction: 0.58 </pre><p>Dans ce cas, le paramétrage du cache APC n'est pas correct. En effet, la taille du cache n'est pas suffisante pour stocker toutes les opérations.<br />Du coup, les performances chutent drastiquement (environ 1/4 des performances précédentes), et l'on a des performances identiques au fonctionnement sans le cache APC.</p> <p>On constate que le cache APC est saturé, et que l'on voit des "cache full count", qui signifient que le cache a été rempli et qu'il a fallu vider des éléments, ce qui est très pénalisant.</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/drupal-APC-12Mo.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;drupal-APC-12Mo.png&quot;}" role="button" title="drupal-APC-12Mo.png" data-colorbox-gallery="gallery-all-EKd_tqs2qn8" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;drupal-APC-12Mo.png&quot;}"><img src="/sites/default/files/styles/large/public/drupal-APC-12Mo.png?itok=OSIYFlmZ" width="480" height="267" alt="drupal-APC-12Mo.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <h2>Résultats avec 24 Mo</h2> <pre>Transactions: 3104 hits Availability: 100.00 % Elapsed time: 119.67 secs Data transferred: 15.90 MB Response time: 0.96 secs Transaction rate: 25.94 trans/sec Throughput: 0.13 MB/sec Concurrency: 24.89 Successful transactions: 3085 Failed transactions: 0 Longest transaction: 1.53 Shortest transaction: 0.48 </pre><p>Avec 24 Mo, les choses rentrent dans l'ordre. Le cache est correctement utilisé, mais il n'y a pas d'amélioration des performances.</p> <p><article class="media media--type-image media--view-mode-default" data-align="center"><div class="field field--name-field-media-image field--type-image field--label-visually_hidden"> <div class="field__label visually-hidden">Image</div> <div class="field__item"> <a href="https://www.vincentliefooghe.net/sites/default/files/drupal-APC-24Mo.png" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;drupal-APC-24Mo.png&quot;}" role="button" title="drupal-APC-24Mo.png" data-colorbox-gallery="gallery-all-EKd_tqs2qn8" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;drupal-APC-24Mo.png&quot;}"><img src="/sites/default/files/styles/large/public/drupal-APC-24Mo.png?itok=QO_CN2t_" width="480" height="255" alt="drupal-APC-24Mo.png" loading="lazy" typeof="foaf:Image" class="image-style-large" /></a> </div> </div> </article></p> <h2>Résultats avec 32 Mo</h2> <pre>Transactions: 2595 hits Availability: 100.00 % Elapsed time: 119.78 secs Data transferred: 13.48 MB Response time: 1.15 secs Transaction rate: 21.66 trans/sec Throughput: 0.11 MB/sec Concurrency: 24.87 Successful transactions: 2583 Failed transactions: 0 Longest transaction: 5.92 Shortest transaction: 0.89 </pre><h2>Conclusion</h2> <p>Cette série de tests a montré que le paramétrage du cache APC doit être régulièrement monitoré et validé, sous peine d'avoir un effet inverse à celui attendu et de dégrader les performances.</p> <p>On peut également constater qu'il ne sert à rien de surallouer la mémoire, car une fois la taille optimale allouée, il n'y a aucun gain.</p> <p>Cela prouve également que le choix de l'hébergeur est important, et que la richesse du CMS Drupal a également des impacts sur les performances de la plate-forme. Il convient donc de faire le bon choix. Un hébergement mutualisé ne pourra généralement pas offrir la souplesse d'un hébergeur spécialisé, capable de mettre en oeuvre les bons composants et les bons paramétrages.</p> <h2>Addendrum : impact du cache Drupal</h2> <p>Les tests ont été réalisés avec le cache désactivé. De ce fait, de nombreuses requêtes MySQL sont générées, et tendent à ralentir le débit.<br />Si on active le cache Drupal pour les utilisateurs anonymes, les résultats sont spectaculaires.</p> <p>Un premier essai sans cache APC, mais avec le cache Drupal :</p> <pre>Transactions: 3610 hits Availability: 100.00 % Elapsed time: 119.95 secs Data transferred: 18.70 MB Response time: 0.83 secs Transaction rate: 30.10 trans/sec Throughput: 0.16 MB/sec Concurrency: 24.91 Successful transactions: 3598 Failed transactions: 0 Longest transaction: 5.18 Shortest transaction: 0.59 </pre><p>On constate une nette amélioration par rapport à un paramétrage sans cache (30 transactions / seconde vs 6.5). Au final, on est assez proche d'une configuration APC sans cache Drupal.</p> <p>Deuxième essai avec le cache Drupal et le cache APC :</p> <pre>Transactions: 23611 hits Availability: 100.00 % Elapsed time: 119.03 secs Data transferred: 122.00 MB Response time: 0.13 secs Transaction rate: 198.36 trans/sec Throughput: 1.02 MB/sec Concurrency: 24.93 Successful transactions: 23483 Failed transactions: 0 Longest transaction: 2.49 Shortest transaction: 0.06 </pre><p>Lorsqu'on active les caches APC et Drupal, les performances sont multipliées par 30 !</p> <p>N'oubliez donc pas, pour avoir de bonnes performances, d'activer tous les niveaux de cache possibles : au niveau Drupal, mais également au niveau PHP. Le choix d'un hébergeur qui supporte ces différents niveaux est un gage de performances. Mon hébergeur, <a href="http://www.hebinweb.com">HebInWeb.com</a>, met en oeuvre APC sur les instances Drupal.</p> <p> </p> </div> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/users/vincentl" typeof="schema:Person" property="schema:name" datatype="">vincentl</span></span> <span class="field field--name-created field--type-created field--label-hidden">lun 04/08/2014 - 15:33</span> <div class="field field--name-field-categorie field--type-entity-reference field--label-above"> <div class="field__label">Catégorie</div> <div class="field__item"><a href="/cat%C3%A9gorie/cms" hreflang="fr">CMS</a></div> </div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field__label">Tag</div> <div class="field__items"> <div class="field__item"><a href="/taxonomy/term/1" hreflang="fr">Drupal</a></div> <div class="field__item"><a href="/tags/apc" hreflang="fr">apc</a></div> <div class="field__item"><a href="/tags/cache" hreflang="fr">cache</a></div> <div class="field__item"><a href="/tags/performances" hreflang="fr">performances</a></div> <div class="field__item"><a href="/tags/planetdrupal" hreflang="fr">planetdrupal</a></div> </div> </div> <section class="field field--name-comment-node-book field--type-comment field--label-hidden comment-wrapper"> </section> Mon, 04 Aug 2014 13:33:24 +0000 vincentl 105 at https://www.vincentliefooghe.net https://www.vincentliefooghe.net/content/influence-du-param%C3%A9trage-apc-sur-les-performances-drupal#comments Performances Drupal https://www.vincentliefooghe.net/content/performances-drupal <span class="field field--name-title field--type-string field--label-hidden">Performances Drupal</span> <div class="clearfix text-formatted field field--name-body field--type-text-with-summary field--label-hidden field__item"><p>Drupal est généralement basé sur une plate-forme LAMP (Linux / Apache / MySQL / PHP), même si on peut au final changer la majorité des couches, sauf le PHP.</p> <p>Plusieurs options sont donc possibles pour améliorer les performances, qui peuvent parfois être calamiteuses sur un serveur mal dimensionné :</p> <ul><li>O.S. (méme si c'est souvent en dernier recours qu'on va faire le <em>tuning</em> à ce niveau)</li> <li>Serveur http : Apache n'est pas le plus rapide, mais il est le plus courant</li> <li>Base de données : l'optimisation de la base MySQL est l'un des gros facteurs de gains</li> <li>PHP : le mode de fonctionnement et l'ajout d'un OpCode permettent de gagner encore.</li> </ul><p> </p> </div> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><span lang="" about="/users/vincentl" typeof="schema:Person" property="schema:name" datatype="">vincentl</span></span> <span class="field field--name-created field--type-created field--label-hidden">mar 12/02/2013 - 21:54</span> <div class="field field--name-field-categorie field--type-entity-reference field--label-above"> <div class="field__label">Catégorie</div> <div class="field__item"><a href="/cat%C3%A9gorie/cms" hreflang="fr">CMS</a></div> </div> <div class="field field--name-field-tags field--type-entity-reference field--label-above"> <div class="field__label">Tag</div> <div class="field__items"> <div class="field__item"><a href="/taxonomy/term/1" hreflang="fr">Drupal</a></div> <div class="field__item"><a href="/tags/performances" hreflang="fr">performances</a></div> </div> </div> <section class="field field--name-comment-node-book field--type-comment field--label-hidden comment-wrapper"> </section> Tue, 12 Feb 2013 20:54:18 +0000 vincentl 57 at https://www.vincentliefooghe.net https://www.vincentliefooghe.net/content/performances-drupal#comments